Player is now a Person

Use correct class inheritance, use class as type and remove IPlayer
This commit is contained in:
Snarling 2022-09-20 01:57:46 -04:00
parent 475a8812bb
commit c510e47885
24 changed files with 297 additions and 518 deletions

@ -5,7 +5,7 @@ import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../uti
import { BladeburnerConstants } from "./data/Constants"; import { BladeburnerConstants } from "./data/Constants";
import { IBladeburner } from "./IBladeburner"; import { IBladeburner } from "./IBladeburner";
import { IAction, ISuccessChanceParams } from "./IAction"; import { IAction, ISuccessChanceParams } from "./IAction";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
class StatsMultiplier { class StatsMultiplier {
[key: string]: number; [key: string]: number;
@ -153,7 +153,7 @@ export class Action implements IAction {
* Tests for success. Should be called when an action has completed * Tests for success. Should be called when an action has completed
* @param inst {Bladeburner} - Bladeburner instance * @param inst {Bladeburner} - Bladeburner instance
*/ */
attempt(inst: IBladeburner, person: IPerson): boolean { attempt(inst: IBladeburner, person: Person): boolean {
return Math.random() < this.getSuccessChance(inst, person); return Math.random() < this.getSuccessChance(inst, person);
} }
@ -162,7 +162,7 @@ export class Action implements IAction {
return 1; return 1;
} }
getActionTime(inst: IBladeburner, person: IPerson): number { getActionTime(inst: IBladeburner, person: Person): number {
const difficulty = this.getDifficulty(); const difficulty = this.getDifficulty();
let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor; let baseTime = difficulty / BladeburnerConstants.DifficultyToTimeFactor;
const skillFac = inst.skillMultipliers.actionTime; // Always < 1 const skillFac = inst.skillMultipliers.actionTime; // Always < 1
@ -212,7 +212,7 @@ export class Action implements IAction {
return 1; return 1;
} }
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number] { getEstSuccessChance(inst: IBladeburner, person: Person): [number, number] {
function clamp(x: number): number { function clamp(x: number): number {
return Math.max(0, Math.min(x, 1)); return Math.max(0, Math.min(x, 1));
} }
@ -233,7 +233,7 @@ export class Action implements IAction {
* @params - options: * @params - options:
* est (bool): Get success chance estimate instead of real success chance * est (bool): Get success chance estimate instead of real success chance
*/ */
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams = { est: false }): number { getSuccessChance(inst: IBladeburner, person: Person, params: ISuccessChanceParams = { est: false }): number {
if (inst == null) { if (inst == null) {
throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance"); throw new Error("Invalid Bladeburner instance passed into Action.getSuccessChance");
} }

@ -16,7 +16,7 @@ import { City } from "./City";
import { IAction } from "./IAction"; import { IAction } from "./IAction";
import { Player } from "../Player"; import { Player } from "../Player";
import { createTaskTracker, ITaskTracker } from "../PersonObjects/ITaskTracker"; import { createTaskTracker, ITaskTracker } from "../PersonObjects/ITaskTracker";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { ConsoleHelpText } from "./data/Help"; import { ConsoleHelpText } from "./data/Help";
import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { exceptionAlert } from "../utils/helpers/exceptionAlert";
@ -995,7 +995,7 @@ export class Bladeburner implements IBladeburner {
* @param action(Action obj) - Derived action class * @param action(Action obj) - Derived action class
* @param success(bool) - Whether action was successful * @param success(bool) - Whether action was successful
*/ */
getActionStats(action: IAction, person: IPerson, success: boolean): ITaskTracker { getActionStats(action: IAction, person: Person, success: boolean): ITaskTracker {
const difficulty = action.getDifficulty(); const difficulty = action.getDifficulty();
/** /**
@ -1025,7 +1025,7 @@ export class Bladeburner implements IBladeburner {
}; };
} }
getDiplomacyEffectiveness(person: IPerson): number { getDiplomacyEffectiveness(person: Person): number {
// Returns a decimal by which the city's chaos level should be multiplied (e.g. 0.98) // Returns a decimal by which the city's chaos level should be multiplied (e.g. 0.98)
const CharismaLinearFactor = 1e3; const CharismaLinearFactor = 1e3;
const CharismaExponentialFactor = 0.045; const CharismaExponentialFactor = 0.045;
@ -1035,11 +1035,11 @@ export class Bladeburner implements IBladeburner {
return (100 - charismaEff) / 100; return (100 - charismaEff) / 100;
} }
getRecruitmentSuccessChance(person: IPerson): number { getRecruitmentSuccessChance(person: Person): number {
return Math.pow(person.skills.charisma, 0.45) / (this.teamSize - this.sleeveSize + 1); return Math.pow(person.skills.charisma, 0.45) / (this.teamSize - this.sleeveSize + 1);
} }
getRecruitmentTime(person: IPerson): number { getRecruitmentTime(person: Person): number {
const effCharisma = person.skills.charisma * this.skillMultipliers.effCha; const effCharisma = person.skills.charisma * this.skillMultipliers.effCha;
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90; const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor)); return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
@ -1257,7 +1257,7 @@ export class Bladeburner implements IBladeburner {
} }
} }
completeAction(person: IPerson, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker { completeAction(person: Person, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker {
let retValue = createTaskTracker(); let retValue = createTaskTracker();
switch (actionIdent.type) { switch (actionIdent.type) {
case ActionTypes["Contract"]: case ActionTypes["Contract"]:
@ -1610,7 +1610,7 @@ export class Bladeburner implements IBladeburner {
} }
} }
changeRank(person: IPerson, change: number): void { changeRank(person: Person, change: number): void {
if (isNaN(change)) { if (isNaN(change)) {
throw new Error("NaN passed into Bladeburner.changeRank()"); throw new Error("NaN passed into Bladeburner.changeRank()");
} }
@ -2146,7 +2146,7 @@ export class Bladeburner implements IBladeburner {
} }
} }
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string { getActionTimeNetscriptFn(person: Person, type: string, name: string): number | string {
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
return "bladeburner.getActionTime"; return "bladeburner.getActionTime";
@ -2177,7 +2177,7 @@ export class Bladeburner implements IBladeburner {
} }
} }
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string { getActionEstimatedSuccessChanceNetscriptFn(person: Person, type: string, name: string): [number, number] | string {
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
return "bladeburner.getActionEstimatedSuccessChance"; return "bladeburner.getActionEstimatedSuccessChance";

@ -1,5 +1,5 @@
import { IReviverValue } from "../utils/JSONReviver"; import { IReviverValue } from "../utils/JSONReviver";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
import { IBladeburner } from "./IBladeburner"; import { IBladeburner } from "./IBladeburner";
interface IStatsMultiplier { interface IStatsMultiplier {
@ -57,15 +57,15 @@ export interface IAction {
teamCount: number; teamCount: number;
getDifficulty(): number; getDifficulty(): number;
attempt(inst: IBladeburner, person: IPerson): boolean; attempt(inst: IBladeburner, person: Person): boolean;
getActionTimePenalty(): number; getActionTimePenalty(): number;
getActionTime(inst: IBladeburner, person: IPerson): number; getActionTime(inst: IBladeburner, person: Person): number;
getTeamSuccessBonus(inst: IBladeburner): number; getTeamSuccessBonus(inst: IBladeburner): number;
getActionTypeSkillSuccessBonus(inst: IBladeburner): number; getActionTypeSkillSuccessBonus(inst: IBladeburner): number;
getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number; getChaosCompetencePenalty(inst: IBladeburner, params: ISuccessChanceParams): number;
getChaosDifficultyBonus(inst: IBladeburner): number; getChaosDifficultyBonus(inst: IBladeburner): number;
getEstSuccessChance(inst: IBladeburner, person: IPerson): [number, number]; getEstSuccessChance(inst: IBladeburner, person: Person): [number, number];
getSuccessChance(inst: IBladeburner, person: IPerson, params: ISuccessChanceParams): number; getSuccessChance(inst: IBladeburner, person: Person, params: ISuccessChanceParams): number;
getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number; getSuccessesNeededForNextLevel(baseSuccessesPerLevel: number): number;
setMaxLevel(baseSuccessesPerLevel: number): void; setMaxLevel(baseSuccessesPerLevel: number): void;
toJSON(): IReviverValue; toJSON(): IReviverValue;

@ -2,7 +2,7 @@ import { IActionIdentifier } from "./IActionIdentifier";
import { City } from "./City"; import { City } from "./City";
import { Skill } from "./Skill"; import { Skill } from "./Skill";
import { IAction } from "./IAction"; import { IAction } from "./IAction";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
import { ITaskTracker } from "../PersonObjects/ITaskTracker"; import { ITaskTracker } from "../PersonObjects/ITaskTracker";
import { WorkerScript } from "../Netscript/WorkerScript"; import { WorkerScript } from "../Netscript/WorkerScript";
import { Contract } from "./Contract"; import { Contract } from "./Contract";
@ -82,8 +82,8 @@ export interface IBladeburner {
getGeneralActionNamesNetscriptFn(): string[]; getGeneralActionNamesNetscriptFn(): string[];
getSkillNamesNetscriptFn(): string[]; getSkillNamesNetscriptFn(): string[];
startActionNetscriptFn(type: string, name: string, workerScript: WorkerScript): boolean; startActionNetscriptFn(type: string, name: string, workerScript: WorkerScript): boolean;
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string; getActionTimeNetscriptFn(person: Person, type: string, name: string): number | string;
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string; getActionEstimatedSuccessChanceNetscriptFn(person: Person, type: string, name: string): [number, number] | string;
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number; getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number; getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number;
getSkillUpgradeCostNetscriptFn(skillName: string, count: number, workerScript: WorkerScript): number; getSkillUpgradeCostNetscriptFn(skillName: string, count: number, workerScript: WorkerScript): number;
@ -102,23 +102,23 @@ export interface IBladeburner {
triggerMigration(sourceCityName: string): void; triggerMigration(sourceCityName: string): void;
triggerPotentialMigration(sourceCityName: string, chance: number): void; triggerPotentialMigration(sourceCityName: string, chance: number): void;
randomEvent(): void; randomEvent(): void;
getDiplomacyEffectiveness(person: IPerson): number; getDiplomacyEffectiveness(person: Person): number;
getRecruitmentSuccessChance(person: IPerson): number; getRecruitmentSuccessChance(person: Person): number;
getRecruitmentTime(person: IPerson): number; getRecruitmentTime(person: Person): number;
resetSkillMultipliers(): void; resetSkillMultipliers(): void;
updateSkillMultipliers(): void; updateSkillMultipliers(): void;
completeOperation(success: boolean): void; completeOperation(success: boolean): void;
getActionObject(actionId: IActionIdentifier): IAction | null; getActionObject(actionId: IActionIdentifier): IAction | null;
completeContract(success: boolean, actionIdent: IActionIdentifier): void; completeContract(success: boolean, actionIdent: IActionIdentifier): void;
completeAction(person: IPerson, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker; completeAction(person: Person, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker;
infiltrateSynthoidCommunities(): void; infiltrateSynthoidCommunities(): void;
changeRank(person: IPerson, change: number): void; changeRank(person: Person, change: number): void;
processAction(seconds: number): void; processAction(seconds: number): void;
calculateStaminaGainPerSecond(): number; calculateStaminaGainPerSecond(): number;
calculateMaxStamina(): void; calculateMaxStamina(): void;
create(): void; create(): void;
process(): void; process(): void;
getActionStats(action: IAction, person: IPerson, success: boolean): ITaskTracker; getActionStats(action: IAction, person: Person, success: boolean): ITaskTracker;
sleeveSupport(joining: boolean): void; sleeveSupport(joining: boolean): void;
toJSON(): IReviverValue; toJSON(): IReviverValue;
} }

@ -225,7 +225,7 @@ export class StaneksGift implements IStaneksGift {
if (!sleeve.hasAugmentation(AugmentationNames.ZOE)) continue; if (!sleeve.hasAugmentation(AugmentationNames.ZOE)) continue;
sleeve.resetMultipliers(); sleeve.resetMultipliers();
sleeve.mults = mergeMultipliers(sleeve.mults, sleeveMults); sleeve.mults = mergeMultipliers(sleeve.mults, sleeveMults);
sleeve.updateStatLevels(); sleeve.updateSkillLevels();
} }
} }

@ -1,6 +1,6 @@
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { Player } from "../Player"; import { Player } from "../Player";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
import { WorkerScript } from "../Netscript/WorkerScript"; import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/WorkType";
import { CrimeWork } from "../Work/CrimeWork"; import { CrimeWork } from "../Work/CrimeWork";
@ -115,7 +115,7 @@ export class Crime {
return this.time; return this.time;
} }
successRate(p: IPerson): number { successRate(p: Person): number {
let chance: number = let chance: number =
this.hacking_success_weight * p.skills.hacking + this.hacking_success_weight * p.skills.hacking +
this.strength_success_weight * p.skills.strength + this.strength_success_weight * p.skills.strength +

@ -1,40 +0,0 @@
import { calculateIntelligenceBonus } from "../../PersonObjects/formulas/intelligence";
import { CONSTANTS } from "../../Constants";
export interface ICrime {
hacking_success_weight: number;
strength_success_weight: number;
defense_success_weight: number;
dexterity_success_weight: number;
agility_success_weight: number;
charisma_success_weight: number;
difficulty: number;
}
export interface IPerson {
hacking: number;
strength: number;
defense: number;
dexterity: number;
agility: number;
charisma: number;
intelligence: number;
crime_success_mult: number;
}
export function calculateCrimeSuccessChance(crime: ICrime, person: IPerson): number {
let chance: number =
crime.hacking_success_weight * person.hacking +
crime.strength_success_weight * person.strength +
crime.defense_success_weight * person.defense +
crime.dexterity_success_weight * person.dexterity +
crime.agility_success_weight * person.agility +
crime.charisma_success_weight * person.charisma +
CONSTANTS.IntelligenceCrimeWeight * person.intelligence;
chance /= CONSTANTS.MaxSkillLevel;
chance /= crime.difficulty;
chance *= person.crime_success_mult;
chance *= calculateIntelligenceBonus(person.intelligence);
return Math.min(chance, 1);
}

@ -1,6 +1,6 @@
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { IPerson } from "../../PersonObjects/IPerson"; import { Person } from "../../PersonObjects/Person";
export function repFromDonation(amt: number, person: IPerson): number { export function repFromDonation(amt: number, person: Person): number {
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep; return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep;
} }

@ -1,12 +1,12 @@
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { IPerson } from "./PersonObjects/IPerson"; import { Person } from "./PersonObjects/Person";
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence"; import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
import { Server } from "./Server/Server"; import { Server } from "./Server/Server";
/** /**
* Returns the chance the person has to successfully hack a server * Returns the chance the person has to successfully hack a server
*/ */
export function calculateHackingChance(server: Server, person: IPerson): number { export function calculateHackingChance(server: Server, person: Person): number {
const hackFactor = 1.75; const hackFactor = 1.75;
const difficultyMult = (100 - server.hackDifficulty) / 100; const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = hackFactor * person.skills.hacking; const skillMult = hackFactor * person.skills.hacking;
@ -30,7 +30,7 @@ export function calculateHackingChance(server: Server, person: IPerson): number
* Returns the amount of hacking experience the person will gain upon * Returns the amount of hacking experience the person will gain upon
* successfully hacking a server * successfully hacking a server
*/ */
export function calculateHackingExpGain(server: Server, person: IPerson): number { export function calculateHackingExpGain(server: Server, person: Person): number {
const baseExpGain = 3; const baseExpGain = 3;
const diffFactor = 0.3; const diffFactor = 0.3;
if (server.baseDifficulty == null) { if (server.baseDifficulty == null) {
@ -46,7 +46,7 @@ export function calculateHackingExpGain(server: Server, person: IPerson): number
* Returns the percentage of money that will be stolen from a server if * Returns the percentage of money that will be stolen from a server if
* it is successfully hacked (returns the decimal form, not the actual percent value) * it is successfully hacked (returns the decimal form, not the actual percent value)
*/ */
export function calculatePercentMoneyHacked(server: Server, person: IPerson): number { export function calculatePercentMoneyHacked(server: Server, person: Person): number {
// Adjust if needed for balancing. This is the divisor for the final calculation // Adjust if needed for balancing. This is the divisor for the final calculation
const balanceFactor = 240; const balanceFactor = 240;
@ -67,7 +67,7 @@ export function calculatePercentMoneyHacked(server: Server, person: IPerson): nu
/** /**
* Returns time it takes to complete a hack on a server, in seconds * Returns time it takes to complete a hack on a server, in seconds
*/ */
export function calculateHackingTime(server: Server, person: IPerson): number { export function calculateHackingTime(server: Server, person: Person): number {
const difficultyMult = server.requiredHackingSkill * server.hackDifficulty; const difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
const baseDiff = 500; const baseDiff = 500;
@ -88,7 +88,7 @@ export function calculateHackingTime(server: Server, person: IPerson): number {
/** /**
* Returns time it takes to complete a grow operation on a server, in seconds * Returns time it takes to complete a grow operation on a server, in seconds
*/ */
export function calculateGrowTime(server: Server, person: IPerson): number { export function calculateGrowTime(server: Server, person: Person): number {
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2 const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
return growTimeMultiplier * calculateHackingTime(server, person); return growTimeMultiplier * calculateHackingTime(server, person);
@ -97,7 +97,7 @@ export function calculateGrowTime(server: Server, person: IPerson): number {
/** /**
* Returns time it takes to complete a weaken operation on a server, in seconds * Returns time it takes to complete a weaken operation on a server, in seconds
*/ */
export function calculateWeakenTime(server: Server, person: IPerson): number { export function calculateWeakenTime(server: Server, person: Person): number {
const weakenTimeMultiplier = 4; // Relative to hacking time const weakenTimeMultiplier = 4; // Relative to hacking time
return weakenTimeMultiplier * calculateHackingTime(server, person); return weakenTimeMultiplier * calculateHackingTime(server, person);

@ -21,7 +21,7 @@ import { CONSTANTS } from "../Constants";
import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing"; import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing";
import { IPort, NetscriptPort } from "../NetscriptPort"; import { IPort, NetscriptPort } from "../NetscriptPort";
import { NetscriptPorts } from "../NetscriptWorker"; import { NetscriptPorts } from "../NetscriptWorker";
import { IPerson } from "../PersonObjects/IPerson"; import { Person } from "../PersonObjects/Person";
import { FormulaGang } from "../Gang/formulas/formulas"; import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember"; import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask"; import { GangMemberTask } from "../Gang/GangMemberTask";
@ -498,7 +498,7 @@ function getValidPort(ctx: NetscriptContext, port: number): IPort {
return iport; return iport;
} }
function player(ctx: NetscriptContext, p: unknown): IPerson { function player(ctx: NetscriptContext, p: unknown): Person {
const fakePlayer = { const fakePlayer = {
hp: undefined, hp: undefined,
mults: undefined, mults: undefined,
@ -518,7 +518,7 @@ function player(ctx: NetscriptContext, p: unknown): IPerson {
entropy: undefined, entropy: undefined,
}; };
if (!roughlyIs(fakePlayer, p)) throw makeRuntimeErrorMsg(ctx, `player should be a Player.`, "TYPE"); if (!roughlyIs(fakePlayer, p)) throw makeRuntimeErrorMsg(ctx, `player should be a Player.`, "TYPE");
return p as IPerson; return p as Person;
} }
function server(ctx: NetscriptContext, s: unknown): Server { function server(ctx: NetscriptContext, s: unknown): Server {

@ -1,33 +0,0 @@
// Interface that represents either the player (PlayerObject) or
// a Sleeve. Used for functions that need to take in both.
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { HP } from "./HP";
import { ITaskTracker } from "./ITaskTracker";
import { Multipliers } from "./Multipliers";
import { Skills } from "./Skills";
export interface IPerson {
hp: HP;
skills: Skills;
exp: Skills;
mults: Multipliers;
augmentations: IPlayerOwnedAugmentation[];
getIntelligenceBonus(weight: number): number;
gainHackingExp(exp: number): void;
gainStrengthExp(exp: number): void;
gainDefenseExp(exp: number): void;
gainDexterityExp(exp: number): void;
gainAgilityExp(exp: number): void;
gainCharismaExp(exp: number): void;
gainIntelligenceExp(exp: number): void;
gainStats(retValue: ITaskTracker): void;
calculateSkill(exp: number, mult?: number): number;
takeDamage(amt: number): boolean;
regenerateHp: (amt: number) => void;
queryStatFromString: (str: string) => number;
whoAmI: () => string;
}

@ -1,18 +1,15 @@
import * as generalMethods from "./Player/PlayerObjectGeneralMethods"; import * as personMethods from "./PersonMethods";
import { Augmentation } from "../Augmentation/Augmentation";
import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import { CONSTANTS } from "../Constants";
import { calculateSkill } from "./formulas/skill"; import { calculateSkill } from "./formulas/skill";
import { calculateIntelligenceBonus } from "./formulas/intelligence"; import { calculateIntelligenceBonus } from "./formulas/intelligence";
import { IPerson } from "./IPerson"; import { defaultMultipliers } from "./Multipliers";
import { defaultMultipliers, mergeAugmentation } from "./Multipliers";
import { Skills } from "./Skills"; import { Skills } from "./Skills";
import { HP } from "./HP"; import { HP } from "./HP";
import { IReviverValue } from "../utils/JSONReviver";
// Base class representing a person-like object // Base class representing a person-like object
export abstract class Person implements IPerson { export abstract class Person {
hp: HP = { current: 10, max: 10 }; hp: HP = { current: 10, max: 10 };
skills: Skills = { skills: Skills = {
hacking: 1, hacking: 1,
@ -45,126 +42,31 @@ export abstract class Person implements IPerson {
*/ */
city: CityName = CityName.Sector12; city: CityName = CityName.Sector12;
gainHackingExp = generalMethods.gainHackingExp; gainHackingExp = personMethods.gainHackingExp;
gainStrengthExp = generalMethods.gainStrengthExp; gainStrengthExp = personMethods.gainStrengthExp;
gainDefenseExp = generalMethods.gainDefenseExp; gainDefenseExp = personMethods.gainDefenseExp;
gainDexterityExp = generalMethods.gainDexterityExp; gainDexterityExp = personMethods.gainDexterityExp;
gainAgilityExp = generalMethods.gainAgilityExp; gainAgilityExp = personMethods.gainAgilityExp;
gainCharismaExp = generalMethods.gainCharismaExp; gainCharismaExp = personMethods.gainCharismaExp;
gainIntelligenceExp = generalMethods.gainIntelligenceExp; gainIntelligenceExp = personMethods.gainIntelligenceExp;
gainStats = generalMethods.gainStats; gainStats = personMethods.gainStats;
calculateSkill = generalMethods.calculateSkill; regenerateHp = personMethods.regenerateHp;
regenerateHp = generalMethods.regenerateHp; queryStatFromString = personMethods.queryStatFromString;
queryStatFromString = generalMethods.queryStatFromString; updateSkillLevels = personMethods.updateSkillLevels;
calculateSkill = calculateSkill; //Class version is equal to imported version
/**
* Updates this object's multipliers for the given augmentation
*/
applyAugmentation(aug: Augmentation): void {
this.mults = mergeAugmentation(this.mults, aug.mults);
}
/**
* Given an experience amount and stat multiplier, calculates the
* stat level. Stat-agnostic (same formula for every stat)
*/
calculateStat(exp: number, mult = 1): number {
return calculateSkill(exp, mult);
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Field Work for a faction
*/
getFactionFieldWorkRepGain(): number {
const t =
(0.9 *
(this.skills.hacking / CONSTANTS.MaxSkillLevel +
this.skills.strength / CONSTANTS.MaxSkillLevel +
this.skills.defense / CONSTANTS.MaxSkillLevel +
this.skills.dexterity / CONSTANTS.MaxSkillLevel +
this.skills.agility / CONSTANTS.MaxSkillLevel +
this.skills.charisma / CONSTANTS.MaxSkillLevel)) /
5.5;
return t * this.mults.faction_rep;
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Hacking Work for a faction
*/
getFactionHackingWorkRepGain(): number {
return (this.skills.hacking / CONSTANTS.MaxSkillLevel) * this.mults.faction_rep;
}
/**
* Calculate and return the amount of faction reputation earned per cycle
* when doing Security Work for a faction
*/
getFactionSecurityWorkRepGain(): number {
const t =
(0.9 *
(this.skills.hacking / CONSTANTS.MaxSkillLevel +
this.skills.strength / CONSTANTS.MaxSkillLevel +
this.skills.defense / CONSTANTS.MaxSkillLevel +
this.skills.dexterity / CONSTANTS.MaxSkillLevel +
this.skills.agility / CONSTANTS.MaxSkillLevel)) /
4.5;
return t * this.mults.faction_rep;
}
/** /**
* Reset all multipliers to 1 * Reset all multipliers to 1
*/ */
resetMultipliers(): void { resetMultipliers() {
this.mults = defaultMultipliers(); this.mults = defaultMultipliers();
} }
/**
* Update all stat levels
*/
updateStatLevels(): void {
this.skills.hacking = Math.max(
1,
Math.floor(this.calculateStat(this.exp.hacking, this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier)),
);
this.skills.strength = Math.max(
1,
Math.floor(
this.calculateStat(this.exp.strength, this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier),
),
);
this.skills.defense = Math.max(
1,
Math.floor(this.calculateStat(this.exp.defense, this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier)),
);
this.skills.dexterity = Math.max(
1,
Math.floor(
this.calculateStat(this.exp.dexterity, this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier),
),
);
this.skills.agility = Math.max(
1,
Math.floor(this.calculateStat(this.exp.agility, this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier)),
);
this.skills.charisma = Math.max(
1,
Math.floor(
this.calculateStat(this.exp.charisma, this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier),
),
);
const ratio: number = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
}
getIntelligenceBonus(weight: number): number { getIntelligenceBonus(weight: number): number {
return calculateIntelligenceBonus(this.skills.intelligence, weight); return calculateIntelligenceBonus(this.skills.intelligence, weight);
} }
abstract takeDamage(amt: number): boolean; abstract takeDamage(amt: number): boolean;
abstract whoAmI(): string; abstract whoAmI(): string;
abstract toJSON(): IReviverValue;
} }

@ -0,0 +1,199 @@
import { Person } from "./Person";
import { calculateSkill } from "./formulas/skill";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Player } from "../Player";
import { ITaskTracker } from "./ITaskTracker";
export function gainHackingExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainHackingExp()");
return;
}
this.exp.hacking += exp;
if (this.exp.hacking < 0) {
this.exp.hacking = 0;
}
this.skills.hacking = calculateSkill(
this.exp.hacking,
this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier,
);
}
export function gainStrengthExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainStrengthExp()");
return;
}
this.exp.strength += exp;
if (this.exp.strength < 0) {
this.exp.strength = 0;
}
this.skills.strength = calculateSkill(
this.exp.strength,
this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier,
);
}
export function gainDefenseExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into player.gainDefenseExp()");
return;
}
this.exp.defense += exp;
if (this.exp.defense < 0) {
this.exp.defense = 0;
}
this.skills.defense = calculateSkill(
this.exp.defense,
this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier,
);
const ratio = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
}
export function gainDexterityExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainDexterityExp()");
return;
}
this.exp.dexterity += exp;
if (this.exp.dexterity < 0) {
this.exp.dexterity = 0;
}
this.skills.dexterity = calculateSkill(
this.exp.dexterity,
this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier,
);
}
export function gainAgilityExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainAgilityExp()");
return;
}
this.exp.agility += exp;
if (this.exp.agility < 0) {
this.exp.agility = 0;
}
this.skills.agility = calculateSkill(
this.exp.agility,
this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier,
);
}
export function gainCharismaExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainCharismaExp()");
return;
}
this.exp.charisma += exp;
if (this.exp.charisma < 0) {
this.exp.charisma = 0;
}
this.skills.charisma = calculateSkill(
this.exp.charisma,
this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier,
);
}
export function gainIntelligenceExp(this: Person, exp: number): void {
if (isNaN(exp)) {
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
return;
}
if (Player.sourceFileLvl(5) > 0 || this.skills.intelligence > 0 || Player.bitNodeN === 5) {
this.exp.intelligence += exp;
this.skills.intelligence = Math.floor(this.calculateSkill(this.exp.intelligence, 1));
}
}
export function gainStats(this: Person, retValue: ITaskTracker): void {
this.gainHackingExp(retValue.hack * this.mults.hacking_exp);
this.gainStrengthExp(retValue.str * this.mults.strength_exp);
this.gainDefenseExp(retValue.def * this.mults.defense_exp);
this.gainDexterityExp(retValue.dex * this.mults.dexterity_exp);
this.gainAgilityExp(retValue.agi * this.mults.agility_exp);
this.gainCharismaExp(retValue.cha * this.mults.charisma_exp);
this.gainIntelligenceExp(retValue.int);
}
//Given a string expression like "str" or "strength", returns the given stat
export function queryStatFromString(this: Person, str: string): number {
const tempStr = str.toLowerCase();
if (tempStr.includes("hack")) {
return this.skills.hacking;
}
if (tempStr.includes("str")) {
return this.skills.strength;
}
if (tempStr.includes("def")) {
return this.skills.defense;
}
if (tempStr.includes("dex")) {
return this.skills.dexterity;
}
if (tempStr.includes("agi")) {
return this.skills.agility;
}
if (tempStr.includes("cha")) {
return this.skills.charisma;
}
if (tempStr.includes("int")) {
return this.skills.intelligence;
}
return 0;
}
export function regenerateHp(this: Person, amt: number): void {
if (typeof amt !== "number") {
console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`);
return;
}
this.hp.current += amt;
if (this.hp.current > this.hp.max) {
this.hp.current = this.hp.max;
}
}
export function updateSkillLevels(this: Person): void {
this.skills.hacking = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.hacking, this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier)),
);
this.skills.strength = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.strength, this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier),
),
);
this.skills.defense = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.defense, this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier)),
);
this.skills.dexterity = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.dexterity, this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier),
),
);
this.skills.agility = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.agility, this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier)),
);
this.skills.charisma = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.charisma, this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier),
),
);
const ratio: number = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
}

@ -11,7 +11,6 @@ import { Sleeve } from "../Sleeve/Sleeve";
import { IPlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile"; import { IPlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
import { IPerson } from "../IPerson";
import { LocationName } from "../../Locations/data/LocationNames"; import { LocationName } from "../../Locations/data/LocationNames";
import { IPlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation"; import { IPlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
import { ICorporation } from "../../Corporation/ICorporation"; import { ICorporation } from "../../Corporation/ICorporation";
@ -20,7 +19,6 @@ import { IBladeburner } from "../../Bladeburner/IBladeburner";
import { HacknetNode } from "../../Hacknet/HacknetNode"; import { HacknetNode } from "../../Hacknet/HacknetNode";
import { HashManager } from "../../Hacknet/HashManager"; import { HashManager } from "../../Hacknet/HashManager";
import { CityName } from "../../Locations/data/CityNames";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver"; import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver";
@ -29,15 +27,11 @@ import { cyrb53 } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { Work } from "src/Work/Work"; import { Work } from "src/Work/Work";
import { defaultMultipliers } from "../Multipliers"; import { Person } from "../Person";
import { HP } from "../HP";
import { Skills } from "../Skills";
export class PlayerObject implements IPerson { export class PlayerObject extends Person {
// Class members // Player-specific properties
augmentations: IPlayerOwnedAugmentation[] = [];
bitNodeN = 1; //current bitnode bitNodeN = 1; //current bitnode
city = CityName.Sector12;
corporation: ICorporation | null = null; corporation: ICorporation | null = null;
gang: IGang | null = null; gang: IGang | null = null;
bladeburner: IBladeburner | null = null; bladeburner: IBladeburner | null = null;
@ -73,34 +67,12 @@ export class PlayerObject implements IPerson {
lastSave = 0; lastSave = 0;
totalPlaytime = 0; totalPlaytime = 0;
hp: HP = { current: 10, max: 10 };
skills: Skills = {
hacking: 1,
strength: 1,
defense: 1,
dexterity: 1,
agility: 1,
charisma: 1,
intelligence: 0,
};
exp: Skills = {
hacking: 0,
strength: 0,
defense: 0,
dexterity: 0,
agility: 0,
charisma: 0,
intelligence: 0,
};
mults = defaultMultipliers();
currentWork: Work | null = null; currentWork: Work | null = null;
focus = false; focus = false;
entropy = 0; entropy = 0;
// Methods // Player-specific methods
init = generalMethods.init; init = generalMethods.init;
startWork = workMethods.startWork; startWork = workMethods.startWork;
processWork = workMethods.processWork; processWork = workMethods.processWork;
@ -124,14 +96,6 @@ export class PlayerObject implements IPerson {
canAccessGang = gangMethods.canAccessGang; canAccessGang = gangMethods.canAccessGang;
canAccessGrafting = generalMethods.canAccessGrafting; canAccessGrafting = generalMethods.canAccessGrafting;
canAfford = generalMethods.canAfford; canAfford = generalMethods.canAfford;
gainHackingExp = generalMethods.gainHackingExp;
gainStrengthExp = generalMethods.gainStrengthExp;
gainDefenseExp = generalMethods.gainDefenseExp;
gainDexterityExp = generalMethods.gainDexterityExp;
gainAgilityExp = generalMethods.gainAgilityExp;
gainCharismaExp = generalMethods.gainCharismaExp;
gainIntelligenceExp = generalMethods.gainIntelligenceExp;
gainStats = generalMethods.gainStats;
gainMoney = generalMethods.gainMoney; gainMoney = generalMethods.gainMoney;
getCurrentServer = serverMethods.getCurrentServer; getCurrentServer = serverMethods.getCurrentServer;
getGangFaction = gangMethods.getGangFaction; getGangFaction = gangMethods.getGangFaction;
@ -153,7 +117,6 @@ export class PlayerObject implements IPerson {
loseMoney = generalMethods.loseMoney; loseMoney = generalMethods.loseMoney;
reapplyAllAugmentations = generalMethods.reapplyAllAugmentations; reapplyAllAugmentations = generalMethods.reapplyAllAugmentations;
reapplyAllSourceFiles = generalMethods.reapplyAllSourceFiles; reapplyAllSourceFiles = generalMethods.reapplyAllSourceFiles;
regenerateHp = generalMethods.regenerateHp;
recordMoneySource = generalMethods.recordMoneySource; recordMoneySource = generalMethods.recordMoneySource;
setMoney = generalMethods.setMoney; setMoney = generalMethods.setMoney;
startBladeburner = bladeburnerMethods.startBladeburner; startBladeburner = bladeburnerMethods.startBladeburner;
@ -164,21 +127,16 @@ export class PlayerObject implements IPerson {
travel = generalMethods.travel; travel = generalMethods.travel;
giveExploit = generalMethods.giveExploit; giveExploit = generalMethods.giveExploit;
giveAchievement = generalMethods.giveAchievement; giveAchievement = generalMethods.giveAchievement;
queryStatFromString = generalMethods.queryStatFromString;
getIntelligenceBonus = generalMethods.getIntelligenceBonus;
getCasinoWinnings = generalMethods.getCasinoWinnings; getCasinoWinnings = generalMethods.getCasinoWinnings;
quitJob = generalMethods.quitJob; quitJob = generalMethods.quitJob;
hasJob = generalMethods.hasJob; hasJob = generalMethods.hasJob;
createHacknetServer = serverMethods.createHacknetServer; createHacknetServer = serverMethods.createHacknetServer;
queueAugmentation = generalMethods.queueAugmentation; queueAugmentation = generalMethods.queueAugmentation;
receiveInvite = generalMethods.receiveInvite; receiveInvite = generalMethods.receiveInvite;
updateSkillLevels = generalMethods.updateSkillLevels;
gainCodingContractReward = generalMethods.gainCodingContractReward; gainCodingContractReward = generalMethods.gainCodingContractReward;
stopFocusing = generalMethods.stopFocusing; stopFocusing = generalMethods.stopFocusing;
resetMultipliers = generalMethods.resetMultipliers;
prestigeAugmentation = generalMethods.prestigeAugmentation; prestigeAugmentation = generalMethods.prestigeAugmentation;
prestigeSourceFile = generalMethods.prestigeSourceFile; prestigeSourceFile = generalMethods.prestigeSourceFile;
calculateSkill = generalMethods.calculateSkill;
calculateSkillProgress = generalMethods.calculateSkillProgress; calculateSkillProgress = generalMethods.calculateSkillProgress;
hospitalize = generalMethods.hospitalize; hospitalize = generalMethods.hospitalize;
checkForFactionInvitations = generalMethods.checkForFactionInvitations; checkForFactionInvitations = generalMethods.checkForFactionInvitations;
@ -189,6 +147,7 @@ export class PlayerObject implements IPerson {
focusPenalty = generalMethods.focusPenalty; focusPenalty = generalMethods.focusPenalty;
constructor() { constructor() {
super();
// Let's get a hash of some semi-random stuff so we have something unique. // Let's get a hash of some semi-random stuff so we have something unique.
this.identifier = cyrb53( this.identifier = cyrb53(
"I-" + "I-" +
@ -219,4 +178,4 @@ export class PlayerObject implements IPerson {
} }
} }
Reviver.constructors.PlayerObject = PlayerObject; Reviver.constructors.PlayerObject = PlayerObject;

@ -24,11 +24,9 @@ import { LocationName } from "../../Locations/data/LocationNames";
import { Sleeve } from "../Sleeve/Sleeve"; import { Sleeve } from "../Sleeve/Sleeve";
import { isSleeveCompanyWork } from "../Sleeve/Work/SleeveCompanyWork"; import { isSleeveCompanyWork } from "../Sleeve/Work/SleeveCompanyWork";
import { import {
calculateSkill as calculateSkillF,
calculateSkillProgress as calculateSkillProgressF, calculateSkillProgress as calculateSkillProgressF,
ISkillProgress, ISkillProgress,
} from "../formulas/skill"; } from "../formulas/skill";
import { calculateIntelligenceBonus } from "../formulas/intelligence";
import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers"; import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
import { Server } from "../../Server/Server"; import { Server } from "../../Server/Server";
import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers"; import { safetlyCreateUniqueServer } from "../../Server/ServerHelpers";
@ -47,12 +45,8 @@ import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
import { achievements } from "../../Achievements/Achievements"; import { achievements } from "../../Achievements/Achievements";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { ITaskTracker } from "../ITaskTracker";
import { IPerson } from "../IPerson";
import { Player } from "../../Player";
import { isCompanyWork } from "../../Work/CompanyWork"; import { isCompanyWork } from "../../Work/CompanyWork";
import { defaultMultipliers } from "../Multipliers";
import { serverMetadata } from "../../Server/data/servers"; import { serverMetadata } from "../../Server/data/servers";
export function init(this: PlayerObject): void { export function init(this: PlayerObject): void {
@ -186,63 +180,11 @@ export function receiveInvite(this: PlayerObject, factionName: string): void {
this.factionInvitations.push(factionName); this.factionInvitations.push(factionName);
} }
//Calculates skill level based on experience. The same formula will be used for every skill
export function calculateSkill(this: IPerson, exp: number, mult = 1): number {
return calculateSkillF(exp, mult);
}
//Calculates skill level progress based on experience. The same formula will be used for every skill //Calculates skill level progress based on experience. The same formula will be used for every skill
export function calculateSkillProgress(this: PlayerObject, exp: number, mult = 1): ISkillProgress { export function calculateSkillProgress(this: PlayerObject, exp: number, mult = 1): ISkillProgress {
return calculateSkillProgressF(exp, mult); return calculateSkillProgressF(exp, mult);
} }
export function updateSkillLevels(this: PlayerObject): void {
this.skills.hacking = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.hacking, this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier)),
);
this.skills.strength = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.strength, this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier),
),
);
this.skills.defense = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.defense, this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier)),
);
this.skills.dexterity = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.dexterity, this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier),
),
);
this.skills.agility = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.agility, this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier)),
);
this.skills.charisma = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.charisma, this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier),
),
);
if (this.skills.intelligence > 0) {
this.skills.intelligence = Math.floor(this.calculateSkill(this.exp.intelligence));
} else {
this.skills.intelligence = 0;
}
const ratio = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
}
export function resetMultipliers(this: PlayerObject): void {
this.mults = defaultMultipliers();
}
export function hasProgram(this: PlayerObject, programName: string): boolean { export function hasProgram(this: PlayerObject, programName: string): boolean {
const home = this.getHomeComputer(); const home = this.getHomeComputer();
if (home == null) { if (home == null) {
@ -306,153 +248,6 @@ export function recordMoneySource(this: PlayerObject, amt: number, source: strin
this.moneySourceB.record(amt, source); this.moneySourceB.record(amt, source);
} }
export function gainHackingExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainHackingExp()");
return;
}
this.exp.hacking += exp;
if (this.exp.hacking < 0) {
this.exp.hacking = 0;
}
this.skills.hacking = calculateSkillF(
this.exp.hacking,
this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier,
);
}
export function gainStrengthExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainStrengthExp()");
return;
}
this.exp.strength += exp;
if (this.exp.strength < 0) {
this.exp.strength = 0;
}
this.skills.strength = calculateSkillF(
this.exp.strength,
this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier,
);
}
export function gainDefenseExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into player.gainDefenseExp()");
return;
}
this.exp.defense += exp;
if (this.exp.defense < 0) {
this.exp.defense = 0;
}
this.skills.defense = calculateSkillF(
this.exp.defense,
this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier,
);
const ratio = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
}
export function gainDexterityExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainDexterityExp()");
return;
}
this.exp.dexterity += exp;
if (this.exp.dexterity < 0) {
this.exp.dexterity = 0;
}
this.skills.dexterity = calculateSkillF(
this.exp.dexterity,
this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier,
);
}
export function gainAgilityExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainAgilityExp()");
return;
}
this.exp.agility += exp;
if (this.exp.agility < 0) {
this.exp.agility = 0;
}
this.skills.agility = calculateSkillF(
this.exp.agility,
this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier,
);
}
export function gainCharismaExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERR: NaN passed into Player.gainCharismaExp()");
return;
}
this.exp.charisma += exp;
if (this.exp.charisma < 0) {
this.exp.charisma = 0;
}
this.skills.charisma = calculateSkillF(
this.exp.charisma,
this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier,
);
}
export function gainIntelligenceExp(this: IPerson, exp: number): void {
if (isNaN(exp)) {
console.error("ERROR: NaN passed into Player.gainIntelligenceExp()");
return;
}
if (Player.sourceFileLvl(5) > 0 || this.skills.intelligence > 0 || Player.bitNodeN === 5) {
this.exp.intelligence += exp;
this.skills.intelligence = Math.floor(this.calculateSkill(this.exp.intelligence, 1));
}
}
export function gainStats(this: IPerson, retValue: ITaskTracker): void {
this.gainHackingExp(retValue.hack * this.mults.hacking_exp);
this.gainStrengthExp(retValue.str * this.mults.strength_exp);
this.gainDefenseExp(retValue.def * this.mults.defense_exp);
this.gainDexterityExp(retValue.dex * this.mults.dexterity_exp);
this.gainAgilityExp(retValue.agi * this.mults.agility_exp);
this.gainCharismaExp(retValue.cha * this.mults.charisma_exp);
this.gainIntelligenceExp(retValue.int);
}
//Given a string expression like "str" or "strength", returns the given stat
export function queryStatFromString(this: PlayerObject, str: string): number {
const tempStr = str.toLowerCase();
if (tempStr.includes("hack")) {
return this.skills.hacking;
}
if (tempStr.includes("str")) {
return this.skills.strength;
}
if (tempStr.includes("def")) {
return this.skills.defense;
}
if (tempStr.includes("dex")) {
return this.skills.dexterity;
}
if (tempStr.includes("agi")) {
return this.skills.agility;
}
if (tempStr.includes("cha")) {
return this.skills.charisma;
}
if (tempStr.includes("int")) {
return this.skills.intelligence;
}
return 0;
}
export function startFocusing(this: PlayerObject): void { export function startFocusing(this: PlayerObject): void {
this.focus = true; this.focus = true;
} }
@ -477,17 +272,6 @@ export function takeDamage(this: PlayerObject, amt: number): boolean {
} }
} }
export function regenerateHp(this: IPerson, amt: number): void {
if (typeof amt !== "number") {
console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`);
return;
}
this.hp.current += amt;
if (this.hp.current > this.hp.max) {
this.hp.current = this.hp.max;
}
}
export function hospitalize(this: PlayerObject): number { export function hospitalize(this: PlayerObject): number {
const cost = getHospitalizationCost(); const cost = getHospitalizationCost();
SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, ToastVariant.WARNING, 2000); SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, ToastVariant.WARNING, 2000);
@ -1441,10 +1225,6 @@ export function giveAchievement(this: PlayerObject, achievementId: string): void
} }
} }
export function getIntelligenceBonus(this: PlayerObject, weight: number): number {
return calculateIntelligenceBonus(this.skills.intelligence, weight);
}
export function getCasinoWinnings(this: PlayerObject): number { export function getCasinoWinnings(this: PlayerObject): number {
return this.moneySourceA.casino; return this.moneySourceA.casino;
} }

@ -80,6 +80,7 @@ export class Sleeve extends Person {
this.shockRecovery(); this.shockRecovery();
} }
applyAugmentation = sleeveMethods.applyAugmentation;
findPurchasableAugs = sleeveMethods.findPurchasableAugs; findPurchasableAugs = sleeveMethods.findPurchasableAugs;
shockBonus(): number { shockBonus(): number {
@ -147,7 +148,7 @@ export class Sleeve extends Person {
this.exp.charisma = 0; this.exp.charisma = 0;
this.applyAugmentation(aug); this.applyAugmentation(aug);
this.augmentations.push({ name: aug.name, level: 1 }); this.augmentations.push({ name: aug.name, level: 1 });
this.updateStatLevels(); this.updateSkillLevels();
} }
/** /**
@ -161,7 +162,7 @@ export class Sleeve extends Person {
this.exp.dexterity = 0; this.exp.dexterity = 0;
this.exp.agility = 0; this.exp.agility = 0;
this.exp.charisma = 0; this.exp.charisma = 0;
this.updateStatLevels(); this.updateSkillLevels();
this.hp.current = this.hp.max; this.hp.current = this.hp.max;
// Reset task-related stuff // Reset task-related stuff

@ -6,10 +6,17 @@ import { Player } from "../../Player";
import { Augmentation } from "../../Augmentation/Augmentation"; import { Augmentation } from "../../Augmentation/Augmentation";
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations"; import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { Multipliers } from "../Multipliers"; import { mergeMultipliers, Multipliers } from "../Multipliers";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers"; import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers";
/**
* Updates this object's multipliers for the given augmentation
*/
export function applyAugmentation(this: Sleeve, aug: Augmentation): void {
this.mults = mergeMultipliers(this.mults, aug.mults);
}
export function findPurchasableAugs(this: Sleeve): Augmentation[] { export function findPurchasableAugs(this: Sleeve): Augmentation[] {
// You can only purchase Augmentations that are actually available from // You can only purchase Augmentations that are actually available from
// your factions. I.e. you must be in a faction that has the Augmentation // your factions. I.e. you must be in a faction that has the Augmentation

@ -1,7 +1,7 @@
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { CalculateShareMult } from "../../NetworkShare/Share"; import { CalculateShareMult } from "../../NetworkShare/Share";
import { IPerson } from "../IPerson"; import { Person } from "../Person";
import { calculateIntelligenceBonus } from "./intelligence"; import { calculateIntelligenceBonus } from "./intelligence";
function mult(favor: number): number { function mult(favor: number): number {
@ -12,7 +12,7 @@ function mult(favor: number): number {
return favorMult * BitNodeMultipliers.FactionWorkRepGain; return favorMult * BitNodeMultipliers.FactionWorkRepGain;
} }
export function getHackingWorkRepGain(p: IPerson, favor: number): number { export function getHackingWorkRepGain(p: Person, favor: number): number {
return ( return (
((p.skills.hacking + p.skills.intelligence / 3) / CONSTANTS.MaxSkillLevel) * ((p.skills.hacking + p.skills.intelligence / 3) / CONSTANTS.MaxSkillLevel) *
p.mults.faction_rep * p.mults.faction_rep *
@ -22,7 +22,7 @@ export function getHackingWorkRepGain(p: IPerson, favor: number): number {
); );
} }
export function getFactionSecurityWorkRepGain(p: IPerson, favor: number): number { export function getFactionSecurityWorkRepGain(p: Person, favor: number): number {
const t = const t =
(0.9 * (0.9 *
(p.skills.strength + (p.skills.strength +
@ -35,7 +35,7 @@ export function getFactionSecurityWorkRepGain(p: IPerson, favor: number): number
return t * p.mults.faction_rep * mult(favor) * calculateIntelligenceBonus(p.skills.intelligence, 1); return t * p.mults.faction_rep * mult(favor) * calculateIntelligenceBonus(p.skills.intelligence, 1);
} }
export function getFactionFieldWorkRepGain(p: IPerson, favor: number): number { export function getFactionFieldWorkRepGain(p: Person, favor: number): number {
const t = const t =
(0.9 * (0.9 *
(p.skills.strength + (p.skills.strength +

@ -1,3 +1,7 @@
/**
* Given an experience amount and stat multiplier, calculates the
* stat level. Stat-agnostic (same formula for every stat)
*/
export function calculateSkill(exp: number, mult = 1): number { export function calculateSkill(exp: number, mult = 1): number {
return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1); return Math.max(Math.floor(mult * (32 * Math.log(exp + 534.5) - 200)), 1);
} }

@ -1,9 +1,9 @@
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { Server } from "../Server"; import { Server } from "../Server";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { IPerson } from "../../PersonObjects/IPerson"; import { Person } from "../../PersonObjects/Person";
export function calculateServerGrowth(server: Server, threads: number, p: IPerson, cores = 1): number { export function calculateServerGrowth(server: Server, threads: number, p: Person, cores = 1): number {
const numServerGrowthCycles = Math.max(Math.floor(threads), 0); const numServerGrowthCycles = Math.max(Math.floor(threads), 0);
//Get adjusted growth rate, which accounts for server security //Get adjusted growth rate, which accounts for server security

@ -1,4 +1,4 @@
import { IPerson } from "src/PersonObjects/IPerson"; import { Person } from "src/PersonObjects/Person";
import { Player } from "../Player"; import { Player } from "../Player";
export interface WorkStats { export interface WorkStats {
@ -68,7 +68,7 @@ export const scaleWorkStats = (w: WorkStats, n: number, scaleMoney = true): Work
}; };
}; };
export const applyWorkStats = (target: IPerson, workStats: WorkStats, cycles: number, source: string): WorkStats => { export const applyWorkStats = (target: Person, workStats: WorkStats, cycles: number, source: string): WorkStats => {
const expStats = applyWorkStatsExp(target, workStats, cycles); const expStats = applyWorkStatsExp(target, workStats, cycles);
const gains = { const gains = {
money: workStats.money * cycles, money: workStats.money * cycles,
@ -86,7 +86,7 @@ export const applyWorkStats = (target: IPerson, workStats: WorkStats, cycles: nu
return gains; return gains;
}; };
export const applyWorkStatsExp = (target: IPerson, workStats: WorkStats, cycles: number): WorkStats => { export const applyWorkStatsExp = (target: Person, workStats: WorkStats, cycles: number): WorkStats => {
const gains = { const gains = {
money: 0, money: 0,
reputation: 0, reputation: 0,

@ -8,7 +8,7 @@ import { WorkStats } from "../WorkStats";
import { Server } from "../../Server/Server"; import { Server } from "../../Server/Server";
import { GetServer } from "../../Server/AllServers"; import { GetServer } from "../../Server/AllServers";
import { serverMetadata } from "../../Server/data/servers"; import { serverMetadata } from "../../Server/data/servers";
import { IPerson } from "../../PersonObjects/IPerson"; import { Person } from "../../PersonObjects/Person";
import { LocationName } from "../../Locations/data/LocationNames"; import { LocationName } from "../../Locations/data/LocationNames";
const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second
@ -20,7 +20,7 @@ export function calculateCost(classs: Class, location: Location): number {
return classs.earnings.money * location.costMult * discount; return classs.earnings.money * location.costMult * discount;
} }
export function calculateClassEarnings(person: IPerson, type: ClassType, locationName: LocationName): WorkStats { export function calculateClassEarnings(person: Person, type: ClassType, locationName: LocationName): WorkStats {
//Find cost and exp gain per game cycle //Find cost and exp gain per game cycle
const hashManager = Player.hashManager; const hashManager = Player.hashManager;
const classs = Classes[type]; const classs = Classes[type];

@ -4,9 +4,9 @@ import { Player } from "../../Player";
import { WorkStats } from "../WorkStats"; import { WorkStats } from "../WorkStats";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { IPerson } from "src/PersonObjects/IPerson"; import { Person } from "../../PersonObjects/Person";
export const calculateCompanyWorkStats = (worker: IPerson, company: Company): WorkStats => { export const calculateCompanyWorkStats = (worker: Person, company: Company): WorkStats => {
const companyPositionName = Player.jobs[company.name]; const companyPositionName = Player.jobs[company.name];
const companyPosition = CompanyPositions[companyPositionName]; const companyPosition = CompanyPositions[companyPositionName];

@ -1,4 +1,4 @@
import { IPerson } from "../../PersonObjects/IPerson"; import { Person } from "../../PersonObjects/Person";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { FactionWorkType } from "../data/FactionWorkType"; import { FactionWorkType } from "../data/FactionWorkType";
@ -30,7 +30,7 @@ export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
}), }),
}; };
export const calculateFactionRep = (person: IPerson, tpe: FactionWorkType, favor: number): number => { export const calculateFactionRep = (person: Person, tpe: FactionWorkType, favor: number): number => {
const repFormulas = { const repFormulas = {
[FactionWorkType.HACKING]: getHackingWorkRepGain, [FactionWorkType.HACKING]: getHackingWorkRepGain,
[FactionWorkType.FIELD]: getFactionFieldWorkRepGain, [FactionWorkType.FIELD]: getFactionFieldWorkRepGain,
@ -39,7 +39,7 @@ export const calculateFactionRep = (person: IPerson, tpe: FactionWorkType, favor
return repFormulas[tpe](person, favor); return repFormulas[tpe](person, favor);
}; };
export function calculateFactionExp(person: IPerson, tpe: FactionWorkType): WorkStats { export function calculateFactionExp(person: Person, tpe: FactionWorkType): WorkStats {
const baseStats = FactionWorkStats[tpe]; const baseStats = FactionWorkStats[tpe];
return { return {
money: 0, money: 0,