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.
This commit is contained in:
Snarling 2022-11-09 07:26:26 -05:00 committed by GitHub
parent 6f08aee8f6
commit 8e0e0eaa88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 251 additions and 337 deletions

@ -1,10 +1,10 @@
import { Player } from "@player";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { addOffset } from "../utils/helpers/addOffset";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { BladeburnerConstants } from "./data/Constants";
import { Bladeburner } from "./Bladeburner";
import { Person } from "../PersonObjects/Person";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
interface ISuccessChanceParams {
est: boolean;
@ -254,7 +254,7 @@ export class Action {
competence += this.weights[stat] * Math.pow(effMultiplier * playerStatLvl, this.decays[stat]);
}
}
competence *= Player.getIntelligenceBonus(0.75);
competence *= calculateIntelligenceBonus(person.skills.intelligence, 0.75);
competence *= inst.calculateStaminaPenalty();
competence *= this.getTeamSuccessBonus(inst);
@ -277,7 +277,7 @@ export class Action {
}
// Augmentation multiplier
competence *= Player.mults.bladeburner_success_chance;
competence *= person.mults.bladeburner_success_chance;
if (isNaN(competence)) {
throw new Error("Competence calculated as NaN in Action.getSuccessChance()");

@ -1,4 +1,4 @@
import { Person } from "../PersonObjects/Person";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { CONSTANTS } from "../Constants";
import * as names from "./data/companypositionnames";
@ -118,7 +118,7 @@ export class CompanyPosition {
this.charismaExpGain = p.charismaExpGain != null ? p.charismaExpGain : 0;
}
calculateJobPerformance(worker: Person): number {
calculateJobPerformance(worker: IPerson): 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;

@ -15,7 +15,7 @@ interface IProps {
export function CreateCorporationModal(props: IProps): React.ReactElement {
const canSelfFund = Player.canAfford(150e9);
if (!Player.canAccessCorporation() || Player.hasCorporation()) {
if (!Player.canAccessCorporation() || Player.corporation) {
props.onClose();
return <></>;
}
@ -26,13 +26,8 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
}
function selfFund(): void {
if (!canSelfFund) {
return;
}
if (name == "") {
return;
}
if (!canSelfFund) return;
if (name == "") return;
Player.startCorporation(name);
Player.loseMoney(150e9, "corporation");

@ -1,9 +1,10 @@
import { CONSTANTS } from "../Constants";
import { Player } from "@player";
import { Person } from "../PersonObjects/Person";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType";
import { CrimeWork } from "../Work/CrimeWork";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
interface IConstructorParams {
hacking_success_weight?: number;
@ -120,7 +121,7 @@ export class Crime {
return this.time;
}
successRate(p: Person): number {
successRate(p: IPerson): number {
let chance: number =
this.hacking_success_weight * p.skills.hacking +
this.strength_success_weight * p.skills.strength +
@ -132,7 +133,7 @@ export class Crime {
chance /= CONSTANTS.MaxSkillLevel;
chance /= this.difficulty;
chance *= p.mults.crime_success;
chance *= p.getIntelligenceBonus(1);
chance *= calculateIntelligenceBonus(p.skills.intelligence, 1);
return Math.min(chance, 1);
}

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

@ -1,10 +1,10 @@
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { Person } from "./PersonObjects/Person";
import { Person as IPerson } from "./ScriptEditor/NetscriptDefinitions";
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
import { Server } from "./Server/Server";
/** Returns the chance the person has to successfully hack a server */
export function calculateHackingChance(server: Server, person: Person): number {
export function calculateHackingChance(server: Server, person: IPerson): number {
const hackFactor = 1.75;
const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = hackFactor * person.skills.hacking;
@ -28,7 +28,7 @@ export function calculateHackingChance(server: Server, person: Person): number {
* Returns the amount of hacking experience the person will gain upon
* successfully hacking a server
*/
export function calculateHackingExpGain(server: Server, person: Person): number {
export function calculateHackingExpGain(server: Server, person: IPerson): number {
const baseExpGain = 3;
const diffFactor = 0.3;
if (server.baseDifficulty == null) {
@ -44,7 +44,7 @@ export function calculateHackingExpGain(server: Server, person: Person): number
* 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)
*/
export function calculatePercentMoneyHacked(server: Server, person: Person): number {
export function calculatePercentMoneyHacked(server: Server, person: IPerson): number {
// Adjust if needed for balancing. This is the divisor for the final calculation
const balanceFactor = 240;
@ -63,7 +63,7 @@ export function calculatePercentMoneyHacked(server: Server, person: Person): num
}
/** Returns time it takes to complete a hack on a server, in seconds */
export function calculateHackingTime(server: Server, person: Person): number {
export function calculateHackingTime(server: Server, person: IPerson): number {
const difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
const baseDiff = 500;
@ -82,14 +82,14 @@ export function calculateHackingTime(server: Server, person: Person): number {
}
/** Returns time it takes to complete a grow operation on a server, in seconds */
export function calculateGrowTime(server: Server, person: Person): number {
export function calculateGrowTime(server: Server, person: IPerson): number {
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
return growTimeMultiplier * calculateHackingTime(server, person);
}
/** Returns time it takes to complete a weaken operation on a server, in seconds */
export function calculateWeakenTime(server: Server, person: Person): number {
export function calculateWeakenTime(server: Server, person: IPerson): number {
const weakenTimeMultiplier = 4; // Relative to hacking time
return weakenTimeMultiplier * calculateHackingTime(server, person);

@ -43,11 +43,10 @@ type IProps = {
export function SpecialLocation(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const inBladeburner = Player.inBladeburner();
/** Click handler for Bladeburner button at Sector-12 NSA */
function handleBladeburner(): void {
if (Player.inBladeburner()) {
if (Player.bladeburner) {
// Enter Bladeburner division
Router.toBladeburner();
} else if (
@ -80,7 +79,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
if (!Player.canAccessBladeburner() || BitNodeMultipliers.BladeburnerRank === 0) {
return <></>;
}
const text = inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
const text = Player.bladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
return (
<>
<br />
@ -143,7 +142,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
}
return (
<>
<Button disabled={!Player.canAccessCorporation() || Player.hasCorporation()} onClick={() => setOpen(true)}>
<Button disabled={!Player.canAccessCorporation() || !!Player.corporation} onClick={() => setOpen(true)}>
Create a Corporation
</Button>
<CreateCorporationModal open={open} onClose={() => setOpen(false)} />

@ -21,7 +21,6 @@ import { CONSTANTS } from "../Constants";
import { influenceStockThroughServerHack } from "../StockMarket/PlayerInfluencing";
import { IPort, NetscriptPort } from "../NetscriptPort";
import { NetscriptPorts } from "../NetscriptWorker";
import { Person } from "../PersonObjects/Person";
import { FormulaGang } from "../Gang/formulas/formulas";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
@ -29,7 +28,7 @@ import { RunningScript } from "../Script/RunningScript";
import { toNative } from "../NetscriptFunctions/toNative";
import { ScriptIdentifier } from "./ScriptIdentifier";
import { findRunningScript, findRunningScriptByPid } from "../Script/ScriptHelpers";
import { RunningScript as IRunningScript } from "../ScriptEditor/NetscriptDefinitions";
import { RunningScript as IRunningScript, Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { arrayToString } from "../utils/helpers/arrayToString";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { BaseServer } from "../Server/BaseServer";
@ -53,7 +52,7 @@ export const helpers = {
scriptIdentifier,
hack,
getValidPort,
player,
person,
server,
gang,
gangMember,
@ -546,27 +545,15 @@ function getValidPort(ctx: NetscriptContext, port: number): IPort {
return iport;
}
function player(ctx: NetscriptContext, p: unknown): Person {
const fakePlayer = {
function person(ctx: NetscriptContext, p: unknown): IPerson {
const fakePerson = {
hp: undefined,
exp: undefined,
mults: undefined,
numPeopleKilled: undefined,
money: undefined,
city: undefined,
location: undefined,
bitNodeN: undefined,
totalPlaytime: undefined,
playtimeSinceLastAug: undefined,
playtimeSinceLastBitnode: undefined,
jobs: undefined,
factions: undefined,
tor: undefined,
inBladeburner: undefined,
hasCorporation: undefined,
entropy: undefined,
};
if (!roughlyIs(fakePlayer, p)) throw makeRuntimeErrorMsg(ctx, `player should be a Player.`, "TYPE");
return p as Person;
if (!roughlyIs(fakePerson, p)) throw makeRuntimeErrorMsg(ctx, `person should be a Person.`, "TYPE");
return p as IPerson;
}
function server(ctx: NetscriptContext, s: unknown): Server {

@ -231,6 +231,7 @@ const gang = {
// Bladeburner API
const bladeburner = {
inBladeburner: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 4,
getContractNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getOperationNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
getBlackOpNames: RamCostConstants.ScriptBladeburnerApiBaseRamCost / 10,
@ -295,9 +296,8 @@ const sleeve = {
setToCompanyWork: RamCostConstants.ScriptSleeveBaseRamCost,
setToFactionWork: RamCostConstants.ScriptSleeveBaseRamCost,
setToGymWorkout: RamCostConstants.ScriptSleeveBaseRamCost,
getSleeveStats: RamCostConstants.ScriptSleeveBaseRamCost,
getTask: RamCostConstants.ScriptSleeveBaseRamCost,
getInformation: RamCostConstants.ScriptSleeveBaseRamCost,
getSleeve: RamCostConstants.ScriptSleeveBaseRamCost,
getSleeveAugmentations: RamCostConstants.ScriptSleeveBaseRamCost,
getSleevePurchasableAugs: RamCostConstants.ScriptSleeveBaseRamCost,
purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost,
@ -343,6 +343,7 @@ const grafting = {
} as const;
const corporation = {
hasCorporation: 0,
getMaterialNames: 0,
getIndustryTypes: 0,
getEmployeePositions: 0,
@ -453,6 +454,7 @@ export const RamCosts: RamCostTree<Omit<NSFull, "args" | "enums">> = {
enableLog: 0,
isLogEnabled: 0,
getScriptLogs: 0,
hasTorRouter: 0.05,
nuke: RamCostConstants.ScriptPortProgramRamCost,
brutessh: RamCostConstants.ScriptPortProgramRamCost,
ftpcrack: RamCostConstants.ScriptPortProgramRamCost,
@ -543,15 +545,13 @@ export const RamCosts: RamCostTree<Omit<NSFull, "args" | "enums">> = {
bypass: 0,
alterReality: 0,
rainbow: 0,
heart: {
// Easter egg function
break: 0,
},
heart: { break: 0 },
iKnowWhatImDoing: 0,
formulas: {
mockServer: 0,
mockPlayer: 0,
mockPerson: 0,
reputation: {
calculateFavorToRep: 0,
calculateRepToFavor: 0,
@ -597,6 +597,7 @@ export const RamCosts: RamCostTree<Omit<NSFull, "args" | "enums">> = {
ascensionMultiplier: 0,
},
work: {
crimeSuccessChance: 0,
crimeGains: 0,
classGains: 0,
factionGains: 0,

@ -78,6 +78,7 @@ import { ScriptDeath } from "./Netscript/ScriptDeath";
import { getBitNodeMultipliers } from "./BitNode/BitNode";
import { assert, arrayAssert, stringAssert, objectAssert } from "./utils/helpers/typeAssertion";
import { CrimeType } from "./utils/WorkType";
import { cloneDeep } from "lodash";
export const enums = {
toast: ToastVariant,
@ -122,6 +123,7 @@ const base: InternalAPI<NS> = {
helpers.log(ctx, () => `returned ${server.serversOnNetwork.length} connections for ${server.hostname}`);
return out;
},
hasTorRouter: () => () => Player.hasTorRouter(),
hack:
(ctx) =>
(_hostname, opts = {}) => {
@ -1806,10 +1808,10 @@ const base: InternalAPI<NS> = {
},
getPlayer: () => () => {
const data = {
hp: JSON.parse(JSON.stringify(Player.hp)),
skills: JSON.parse(JSON.stringify(Player.skills)),
exp: JSON.parse(JSON.stringify(Player.exp)),
mults: JSON.parse(JSON.stringify(Player.mults)),
hp: cloneDeep(Player.hp),
skills: cloneDeep(Player.skills),
exp: cloneDeep(Player.exp),
mults: cloneDeep(Player.mults),
numPeopleKilled: Player.numPeopleKilled,
money: Player.money,
city: Player.city,
@ -1818,14 +1820,10 @@ const base: InternalAPI<NS> = {
totalPlaytime: Player.totalPlaytime,
playtimeSinceLastAug: Player.playtimeSinceLastAug,
playtimeSinceLastBitnode: Player.playtimeSinceLastBitnode,
jobs: {},
jobs: cloneDeep(Player.jobs),
factions: Player.factions.slice(),
tor: Player.hasTorRouter(),
inBladeburner: Player.inBladeburner(),
hasCorporation: Player.hasCorporation(),
entropy: Player.entropy,
};
Object.assign(data.jobs, Player.jobs);
return data;
},
getMoneySources: () => () => ({

@ -47,6 +47,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
};
return {
inBladeburner: () => () => !!Player.bladeburner,
getContractNames: (ctx) => () => {
const bladeburner = getBladeburner(ctx);
return bladeburner.getContractNamesNetscriptFn();

@ -1,4 +1,4 @@
import { Player as player } from "../Player";
import { Player, Player as player } from "../Player";
import { OfficeSpace } from "../Corporation/OfficeSpace";
import { Product } from "../Corporation/Product";
@ -63,7 +63,7 @@ import { CityName } from "../Locations/data/CityNames";
export function NetscriptCorporation(): InternalAPI<NSCorporation> {
function createCorporation(corporationName: string, selfFund = true): boolean {
if (!player.canAccessCorporation() || player.hasCorporation()) return false;
if (!player.canAccessCorporation() || player.corporation) return false;
if (!corporationName) return false;
if (player.bitNodeN !== 3 && !selfFund) throw new Error("cannot use seed funds outside of BitNode 3");
if (BitNodeMultipliers.CorporationSoftcap < 0.15)
@ -705,6 +705,7 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
return {
...warehouseAPI,
...officeAPI,
hasCorporation: () => () => !!Player.corporation,
// Todo: Just remove these functions and provide enums?
getMaterialNames: (ctx) => () => {
checkAccess(ctx);

@ -26,7 +26,7 @@ import {
calculateWeakenTime,
} from "../Hacking";
import { Programs } from "../Programs/Programs";
import { Formulas as IFormulas } from "../ScriptEditor/NetscriptDefinitions";
import { Formulas as IFormulas, Player as IPlayer, Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import {
calculateRespectGain,
calculateWantedLevelGain,
@ -87,26 +87,10 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
requiredHackingSkill: 0,
serverGrowth: 0,
}),
mockPlayer: () => () => ({
mockPlayer: () => (): IPlayer => ({
hp: { current: 0, max: 0 },
skills: {
hacking: 0,
strength: 0,
defense: 0,
dexterity: 0,
agility: 0,
charisma: 0,
intelligence: 0,
},
exp: {
hacking: 0,
strength: 0,
defense: 0,
dexterity: 0,
agility: 0,
charisma: 0,
intelligence: 0,
},
skills: { hacking: 0, strength: 0, defense: 0, dexterity: 0, agility: 0, charisma: 0, intelligence: 0 },
exp: { hacking: 0, strength: 0, defense: 0, dexterity: 0, agility: 0, charisma: 0, intelligence: 0 },
mults: defaultMultipliers(),
numPeopleKilled: 0,
money: 0,
@ -118,11 +102,15 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
playtimeSinceLastBitnode: 0,
jobs: {},
factions: [],
tor: false,
hasCorporation: false,
inBladeburner: false,
entropy: 0,
}),
mockPerson: () => (): IPerson => ({
hp: { current: 0, max: 0 },
skills: { hacking: 0, strength: 0, defense: 0, dexterity: 0, agility: 0, charisma: 0, intelligence: 0 },
exp: { hacking: 0, strength: 0, defense: 0, dexterity: 0, agility: 0, charisma: 0, intelligence: 0 },
mults: defaultMultipliers(),
city: "",
}),
reputation: {
calculateFavorToRep: (ctx) => (_favor) => {
const favor = helpers.number(ctx, "favor", _favor);
@ -136,9 +124,9 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
},
repFromDonation: (ctx) => (_amount, _player) => {
const amount = helpers.number(ctx, "amount", _amount);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return repFromDonation(amount, player);
return repFromDonation(amount, person);
},
},
skills: {
@ -162,49 +150,49 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
hacking: {
hackChance: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculateHackingChance(server, player);
return calculateHackingChance(server, person);
},
hackExp: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculateHackingExpGain(server, player);
return calculateHackingExpGain(server, person);
},
hackPercent: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculatePercentMoneyHacked(server, player);
return calculatePercentMoneyHacked(server, person);
},
growPercent:
(ctx) =>
(_server, _threads, _player, _cores = 1) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
const threads = helpers.number(ctx, "threads", _threads);
const cores = helpers.number(ctx, "cores", _cores);
checkFormulasAccess(ctx);
return calculateServerGrowth(server, threads, player, cores);
return calculateServerGrowth(server, threads, person, cores);
},
hackTime: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculateHackingTime(server, player) * 1000;
return calculateHackingTime(server, person) * 1000;
},
growTime: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculateGrowTime(server, player) * 1000;
return calculateGrowTime(server, person) * 1000;
},
weakenTime: (ctx) => (_server, _player) => {
const server = helpers.server(ctx, _server);
const player = helpers.player(ctx, _player);
const person = helpers.person(ctx, _player);
checkFormulasAccess(ctx);
return calculateWeakenTime(server, player) * 1000;
return calculateWeakenTime(server, person) * 1000;
},
},
hacknetNodes: {
@ -365,20 +353,26 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
},
},
work: {
crimeSuccessChance: (ctx) => (_person, _crimeType) => {
const person = helpers.person(ctx, _person);
const crimeType = helpers.string(ctx, "crimeType", _crimeType);
if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`);
return Crimes[crimeType].successRate(person);
},
crimeGains: (ctx) => (_person, _crimeType) => {
const person = helpers.player(ctx, _person);
const person = helpers.person(ctx, _person);
const crimeType = helpers.string(ctx, "crimeType", _crimeType);
if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`);
return calculateCrimeWorkStats(person, Crimes[crimeType]);
},
classGains: (ctx) => (_person, _classType, _locationName) => {
const person = helpers.player(ctx, _person);
const person = helpers.person(ctx, _person);
const classType = helpers.string(ctx, "classType", _classType);
const locationName = helpers.string(ctx, "locationName", _locationName);
return calculateClassEarnings(person, classType as ClassType, locationName as LocationName);
},
factionGains: (ctx) => (_player, _workType, _favor) => {
const player = helpers.player(ctx, _player);
const player = helpers.person(ctx, _player);
const workType = helpers.string(ctx, "_workType", _workType) as FactionWorkType;
const favor = helpers.number(ctx, "favor", _favor);
const exp = calculateFactionExp(player, workType);
@ -386,9 +380,8 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
exp.reputation = rep;
return exp;
},
companyGains: (ctx) => (_player, _companyName, _positionName, _favor) => {
const player = helpers.player(ctx, _player);
const player = helpers.person(ctx, _player);
CompanyPositions;
const positionName = helpers.string(ctx, "_positionName", _positionName);
const position = Object.values(CompanyPositions).find((c) => c.name === positionName);

@ -1234,7 +1234,6 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
return true;
};
const bladeburnerRequirements = () => {
if (!Player.inBladeburner()) return false;
if (!Player.bladeburner) return false;
return Player.bladeburner.blackops[BlackOperationNames.OperationDaedalus];
};

@ -4,7 +4,7 @@ import { CityName } from "../Locations/data/CityNames";
import { findCrime } from "../Crime/CrimeHelpers";
import { Augmentation } from "../Augmentation/Augmentation";
import { Sleeve as ISleeve, SleeveSkills } from "../ScriptEditor/NetscriptDefinitions";
import { sleeve } from "../ScriptEditor/NetscriptDefinitions";
import { checkEnum } from "../utils/helpers/checkEnum";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
@ -15,7 +15,7 @@ import { Crimes } from "../Crime/Crimes";
import { CrimeType } from "../utils/WorkType";
import { cloneDeep } from "lodash";
export function NetscriptSleeve(): InternalAPI<ISleeve> {
export function NetscriptSleeve(): InternalAPI<sleeve> {
const checkSleeveAPIAccess = function (ctx: NetscriptContext) {
if (Player.bitNodeN !== 10 && !Player.sourceFileLvl(10)) {
throw helpers.makeRuntimeErrorMsg(
@ -33,21 +33,6 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
}
};
const getSleeveStats = function (sleeveNumber: number): SleeveSkills {
const sl = Player.sleeves[sleeveNumber];
return {
shock: 100 - sl.shock,
sync: sl.sync,
memory: sl.memory,
hacking: sl.skills.hacking,
strength: sl.skills.strength,
defense: sl.skills.defense,
dexterity: sl.skills.dexterity,
agility: sl.skills.agility,
charisma: sl.skills.charisma,
};
};
return {
getNumSleeves: (ctx) => () => {
checkSleeveAPIAccess(ctx);
@ -154,12 +139,6 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
return Player.sleeves[sleeveNumber].workoutAtGym(gymName, stat);
},
getSleeveStats: (ctx) => (_sleeveNumber) => {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return getSleeveStats(sleeveNumber);
},
getTask: (ctx) => (_sleeveNumber) => {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
@ -169,40 +148,25 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
if (sl.currentWork === null) return null;
return sl.currentWork.APICopy();
},
getInformation: (ctx) => (_sleeveNumber) => {
getSleeve: (ctx) => (_sleeveNumber) => {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
const sl = Player.sleeves[sleeveNumber];
return {
tor: false,
city: sl.city,
hp: sl.hp,
jobs: Object.keys(Player.jobs), // technically sleeves have the same jobs as the player.
jobTitle: Object.values(Player.jobs),
mult: {
agility: sl.mults.agility,
agilityExp: sl.mults.agility_exp,
charisma: sl.mults.charisma,
charismaExp: sl.mults.charisma_exp,
companyRep: sl.mults.company_rep,
crimeMoney: sl.mults.crime_money,
crimeSuccess: sl.mults.crime_success,
defense: sl.mults.defense,
defenseExp: sl.mults.defense_exp,
dexterity: sl.mults.dexterity,
dexterityExp: sl.mults.dexterity_exp,
factionRep: sl.mults.faction_rep,
hacking: sl.mults.hacking,
hackingExp: sl.mults.hacking_exp,
strength: sl.mults.strength,
strengthExp: sl.mults.strength_exp,
workMoney: sl.mults.work_money,
},
const data = {
hp: cloneDeep(sl.hp),
skills: cloneDeep(sl.skills),
exp: cloneDeep(sl.exp),
mults: cloneDeep(sl.mults),
city: sl.city,
shock: sl.shock,
sync: sl.sync,
memory: sl.memory,
};
return data;
},
getSleeveAugmentations: (ctx) => (_sleeveNumber) => {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
@ -238,7 +202,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
if (getSleeveStats(sleeveNumber).shock > 0) {
if (Player.sleeves[sleeveNumber].shock > 0) {
throw helpers.makeRuntimeErrorMsg(ctx, `Sleeve shock too high: Sleeve ${sleeveNumber}`);
}

@ -1,6 +1,7 @@
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { GraftableAugmentation } from "./GraftableAugmentation";
import { Player } from "@player";
import { calculateIntelligenceBonus } from "../formulas/intelligence";
export const getGraftingAvailableAugs = (): string[] => {
const augs: string[] = [];
@ -14,7 +15,7 @@ export const getGraftingAvailableAugs = (): string[] => {
};
export const graftingIntBonus = (): number => {
return 1 + (Player.getIntelligenceBonus(3) - 1) / 3;
return 1 + (calculateIntelligenceBonus(Player.skills.intelligence, 3) - 1) / 3;
};
export const calculateGraftingTimeWithBonus = (aug: GraftableAugmentation): number => {

@ -2,14 +2,14 @@ import * as personMethods from "./PersonMethods";
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { CityName } from "../Locations/data/CityNames";
import { calculateSkill } from "./formulas/skill";
import { calculateIntelligenceBonus } from "./formulas/intelligence";
import { defaultMultipliers } from "./Multipliers";
import { Skills } from "./Skills";
import { HP } from "./HP";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { IReviverValue } from "../utils/JSONReviver";
// Base class representing a person-like object
export abstract class Person {
export abstract class Person implements IPerson {
hp: HP = { current: 10, max: 10 };
skills: Skills = {
hacking: 1,
@ -58,10 +58,6 @@ export abstract class Person {
this.mults = defaultMultipliers();
}
getIntelligenceBonus(weight: number): number {
return calculateIntelligenceBonus(this.skills.intelligence, weight);
}
abstract takeDamage(amt: number): boolean;
abstract whoAmI(): string;
abstract toJSON(): IReviverValue;

@ -26,8 +26,9 @@ import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { CONSTANTS } from "../../Constants";
import { Work } from "src/Work/Work";
import { Person } from "../Person";
import { Player as IPlayer } from "../../ScriptEditor/NetscriptDefinitions";
export class PlayerObject extends Person {
export class PlayerObject extends Person implements IPlayer {
// Player-specific properties
bitNodeN = 1; //current bitnode
corporation: Corporation | null = null;
@ -102,11 +103,9 @@ export class PlayerObject extends Person {
getUpgradeHomeRamCost = serverMethods.getUpgradeHomeRamCost;
getUpgradeHomeCoresCost = serverMethods.getUpgradeHomeCoresCost;
gotoLocation = generalMethods.gotoLocation;
hasCorporation = corporationMethods.hasCorporation;
hasGangWith = gangMethods.hasGangWith;
hasTorRouter = serverMethods.hasTorRouter;
hasProgram = generalMethods.hasProgram;
inBladeburner = bladeburnerMethods.inBladeburner;
inGang = gangMethods.inGang;
isAwareOfGang = gangMethods.isAwareOfGang;
isQualified = generalMethods.isQualified;

@ -5,10 +5,6 @@ export function canAccessBladeburner(this: PlayerObject): boolean {
return this.bitNodeN === 6 || this.bitNodeN === 7 || this.sourceFileLvl(6) > 0 || this.sourceFileLvl(7) > 0;
}
export function inBladeburner(this: PlayerObject): boolean {
return Boolean(this.bladeburner);
}
export function startBladeburner(this: PlayerObject): void {
this.bladeburner = new Bladeburner();
}

@ -9,10 +9,6 @@ export function canAccessCorporation(this: PlayerObject): boolean {
return this.bitNodeN === 3 || this.sourceFileLvl(3) > 0;
}
export function hasCorporation(this: PlayerObject): boolean {
return Boolean(this.corporation);
}
export function startCorporation(this: PlayerObject, corpName: string, additionalShares = 0): void {
this.corporation = new Corporation({
name: corpName,

@ -138,9 +138,10 @@ export function prestigeSourceFile(this: PlayerObject): void {
}
}
// Gang
this.gang = null;
resetGangs();
this.corporation = null;
this.bladeburner = null;
// Reset Stock market
this.hasWseAccount = false;

@ -40,8 +40,9 @@ import { SleeveSupportWork } from "./Work/SleeveSupportWork";
import { SleeveBladeburnerWork } from "./Work/SleeveBladeburnerWork";
import { SleeveCrimeWork } from "./Work/SleeveCrimeWork";
import * as sleeveMethods from "./SleeveMethods";
import { Sleeve as ISleeve } from "../../ScriptEditor/NetscriptDefinitions";
export class Sleeve extends Person {
export class Sleeve extends Person implements ISleeve {
currentWork: Work | null = null;
/** Clone retains 'memory' synchronization (and maybe exp?) upon prestige/installing Augs */

@ -2,6 +2,7 @@ import { Player } from "@player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { Work, WorkType } from "./Work";
import { calculateIntelligenceBonus } from "../../formulas/intelligence";
export const isSleeveSynchroWork = (w: Work | null): w is SleeveSynchroWork =>
w !== null && w.type === WorkType.SYNCHRO;
@ -12,7 +13,10 @@ export class SleeveSynchroWork extends Work {
}
process(sleeve: Sleeve, cycles: number): number {
sleeve.sync = Math.min(100, sleeve.sync + Player.getIntelligenceBonus(0.5) * 0.0002 * cycles);
sleeve.sync = Math.min(
100,
sleeve.sync + calculateIntelligenceBonus(Player.skills.intelligence, 0.5) * 0.0002 * cycles,
);
if (sleeve.sync >= 100) sleeve.stopWork();
return 0;
}

@ -2,6 +2,8 @@ import React from "react";
import { Typography, Table, TableBody, TableCell, TableRow } from "@mui/material";
import { CONSTANTS } from "../../../Constants";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { Settings } from "../../../Settings/Settings";
import { StatsRow } from "../../../ui/React/StatsRow";
@ -15,7 +17,8 @@ import { isSleeveClassWork } from "../Work/SleeveClassWork";
import { isSleeveFactionWork } from "../Work/SleeveFactionWork";
import { isSleeveCompanyWork } from "../Work/SleeveCompanyWork";
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
import { BitNodeMultipliers } from "../../../BitNode/BitNodeMultipliers";
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
interface IProps {
sleeve: Sleeve;
@ -99,37 +102,37 @@ export function EarningsElement(props: IProps): React.ReactElement {
if (isSleeveCrimeWork(props.sleeve.currentWork)) {
const gains = props.sleeve.currentWork.getExp(props.sleeve);
data = [
[`Money:`, <Money money={5 * gains.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * gains.hackExp)}`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * gains.strExp)}`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * gains.defExp)}`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * gains.dexExp)}`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * gains.agiExp)}`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * gains.chaExp)}`],
[`Money:`, <Money money={gains.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(gains.hackExp)}`],
[`Strength Exp:`, `${numeralWrapper.formatExp(gains.strExp)}`],
[`Defense Exp:`, `${numeralWrapper.formatExp(gains.defExp)}`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(gains.dexExp)}`],
[`Agility Exp:`, `${numeralWrapper.formatExp(gains.agiExp)}`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(gains.chaExp)}`],
];
}
if (isSleeveClassWork(props.sleeve.currentWork)) {
const rates = props.sleeve.currentWork.calculateRates(props.sleeve);
data = [
[`Money:`, <MoneyRate money={5 * rates.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
[`Money:`, <MoneyRate money={CYCLES_PER_SEC * rates.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.chaExp)} / sec`],
];
}
if (isSleeveFactionWork(props.sleeve.currentWork)) {
const rates = props.sleeve.currentWork.getExpRates(props.sleeve);
const repGain = props.sleeve.currentWork.getReputationRate(props.sleeve);
data = [
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
[`Hacking Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.chaExp)} / sec`],
[`Reputation:`, <ReputationRate reputation={repGain} />],
];
}
@ -137,14 +140,14 @@ export function EarningsElement(props: IProps): React.ReactElement {
if (isSleeveCompanyWork(props.sleeve.currentWork)) {
const rates = props.sleeve.currentWork.getGainRates(props.sleeve);
data = [
[`Money:`, <MoneyRate money={5 * rates.money * BitNodeMultipliers.CompanyWorkMoney} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * rates.chaExp)} / sec`],
[`Reputation:`, <ReputationRate reputation={5 * rates.reputation} />],
[`Money:`, <MoneyRate money={CYCLES_PER_SEC * rates.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.hackExp)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.strExp)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.defExp)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.dexExp)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.agiExp)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(CYCLES_PER_SEC * rates.chaExp)} / sec`],
[`Reputation:`, <ReputationRate reputation={CYCLES_PER_SEC * rates.reputation} />],
];
}

@ -246,7 +246,7 @@ const canDo: {
"Take University Course": (sleeve: Sleeve) =>
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Workout at Gym": (sleeve: Sleeve) => [CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Perform Bladeburner Actions": () => Player.inBladeburner(),
"Perform Bladeburner Actions": () => !!Player.bladeburner,
"Shock Recovery": (sleeve: Sleeve) => sleeve.shock < 100,
Synchronize: (sleeve: Sleeve) => sleeve.sync < 100,
};

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

@ -281,10 +281,7 @@ export function prestigeSourceFile(flume: boolean): void {
deleteStockMarket();
}
Player.gang = null;
Player.corporation = null;
resetIndustryResearchTrees();
Player.bladeburner = null;
// Source-File 9 (level 3) effect
if (Player.sourceFileLvl(9) >= 3) {

@ -42,20 +42,28 @@ interface Person {
skills: Skills;
exp: Skills;
mults: Multipliers;
numPeopleKilled: number;
money: number;
city: string;
location: string;
}
/** @public */
interface Player extends Person {
money: number;
numPeopleKilled: number;
entropy: number;
jobs: Record<string, string>;
factions: string[];
bitNodeN: number;
totalPlaytime: number;
playtimeSinceLastAug: number;
playtimeSinceLastBitnode: number;
jobs: Record<string, string>;
factions: string[];
tor: boolean;
hasCorporation: boolean;
inBladeburner: boolean;
entropy: number;
location: string;
}
/** @public */
interface Sleeve extends Person {
shock: number;
sync: number;
memory: number;
}
/** @public */
@ -90,65 +98,65 @@ interface MoneySources {
/** @public */
export interface Multipliers {
/** Multiplier to hacking skill */
hacking?: number;
hacking: number;
/** Multiplier to strength skill */
strength?: number;
strength: number;
/** Multiplier to defense skill */
defense?: number;
defense: number;
/** Multiplier to dexterity skill */
dexterity?: number;
dexterity: number;
/** Multiplier to agility skill */
agility?: number;
agility: number;
/** Multiplier to charisma skill */
charisma?: number;
charisma: number;
/** Multiplier to hacking experience gain rate */
hacking_exp?: number;
hacking_exp: number;
/** Multiplier to strength experience gain rate */
strength_exp?: number;
strength_exp: number;
/** Multiplier to defense experience gain rate */
defense_exp?: number;
defense_exp: number;
/** Multiplier to dexterity experience gain rate */
dexterity_exp?: number;
dexterity_exp: number;
/** Multiplier to agility experience gain rate */
agility_exp?: number;
agility_exp: number;
/** Multiplier to charisma experience gain rate */
charisma_exp?: number;
charisma_exp: number;
/** Multiplier to chance of successfully performing a hack */
hacking_chance?: number;
hacking_chance: number;
/** Multiplier to hacking speed */
hacking_speed?: number;
hacking_speed: number;
/** Multiplier to amount of money the player gains from hacking */
hacking_money?: number;
hacking_money: number;
/** Multiplier to amount of money injected into servers using grow */
hacking_grow?: number;
hacking_grow: number;
/** Multiplier to amount of reputation gained when working */
company_rep?: number;
company_rep: number;
/** Multiplier to amount of reputation gained when working */
faction_rep?: number;
faction_rep: number;
/** Multiplier to amount of money gained from crimes */
crime_money?: number;
crime_money: number;
/** Multiplier to crime success rate */
crime_success?: number;
crime_success: number;
/** Multiplier to amount of money gained from working */
work_money?: number;
work_money: number;
/** Multiplier to amount of money produced by Hacknet Nodes */
hacknet_node_money?: number;
hacknet_node_money: number;
/** Multiplier to cost of purchasing a Hacknet Node */
hacknet_node_purchase_cost?: number;
hacknet_node_purchase_cost: number;
/** Multiplier to cost of ram for a Hacknet Node */
hacknet_node_ram_cost?: number;
hacknet_node_ram_cost: number;
/** Multiplier to cost of core for a Hacknet Node */
hacknet_node_core_cost?: number;
hacknet_node_core_cost: number;
/** Multiplier to cost of leveling up a Hacknet Node */
hacknet_node_level_cost?: number;
hacknet_node_level_cost: number;
/** Multiplier to Bladeburner max stamina */
bladeburner_max_stamina?: number;
bladeburner_max_stamina: number;
/** Multiplier to Bladeburner stamina gain rate */
bladeburner_stamina_gain?: number;
bladeburner_stamina_gain: number;
/** Multiplier to effectiveness in Bladeburner Field Analysis */
bladeburner_analysis?: number;
bladeburner_analysis: number;
/** Multiplier to success chance in Bladeburner contracts/operations */
bladeburner_success_chance?: number;
bladeburner_success_chance: number;
}
/** @public */
@ -259,7 +267,7 @@ export interface CodingAttemptOptions {
}
/**
* Return value of {@link Sleeve.getSleevePurchasableAugs | getSleevePurchasableAugs}
* Return value of {@link sleeve.getSleevePurchasableAugs | getSleevePurchasableAugs}
* @public
*/
export interface AugmentPair {
@ -869,52 +877,6 @@ export interface GangMemberAscension {
cha: number;
}
/**
* Object representing a sleeve stats.
* @public
*/
export interface SleeveSkills {
/** Current shock of the sleeve [0-100] */
shock: number;
/** Current sync of the sleeve [0-100] */
sync: number;
/** Current memory of the sleeve [1-100] */
memory: number;
/** Current hacking skill of the sleeve */
hacking: number;
/** Current strength of the sleeve */
strength: number;
/** Current defense of the sleeve */
defense: number;
/** Current dexterity of the sleeve */
dexterity: number;
/** Current agility of the sleeve */
agility: number;
/** Current charisma of the sleeve */
charisma: number;
}
/**
* Object representing sleeve information.
* @public
*/
export interface SleeveInformation {
/** Location of the sleeve */
city: string;
/** hp of the sleeve */
hp: HP;
/** Jobs available to the sleeve */
jobs: string[];
/** Job titles available to the sleeve */
jobTitle: string[];
/** Does this sleeve have access to the tor router */
tor: boolean;
/** Sleeve multipliers */
mult: Multipliers;
/** Sleeve skills */
skills: Skills;
}
/**
* Object representing a sleeve current task.
* @public
@ -3137,6 +3099,13 @@ export interface Bladeburner {
* @returns Amount of accumulated bonus time (milliseconds) for the Bladeburner mechanic.
*/
getBonusTime(): number;
/** Returns whether player is a member of bladeburner division. Does not require API access.
* @remarks
* RAM cost: 1 GB
*
* @returns whether player is a member of bladeburner division. */
inBladeburner(): boolean;
}
/**
@ -3511,7 +3480,7 @@ export interface Gang {
* If you are not in BitNode-10, then you must have Source-File 10 in order to use this API.
* @public
*/
export interface Sleeve {
export interface sleeve {
/**
* Get the number of sleeves you own.
* @remarks
@ -3523,29 +3492,17 @@ export interface Sleeve {
*/
getNumSleeves(): number;
/**
* Get the stats of a sleeve.
* @remarks
* RAM cost: 4 GB
*
* Return a structure containing the stats of the sleeve.
*
* @param sleeveNumber - Index of the sleeve to get stats of.
* @returns Object containing the stats of the sleeve.
*/
getSleeveStats(sleeveNumber: number): SleeveSkills;
/**
* Get information about a sleeve.
* @remarks
* RAM cost: 4 GB
*
* Return a struct containing tons of information about this sleeve
* Return a person object for this sleeve
*
* @param sleeveNumber - Index of the sleeve to retrieve information.
* @returns Object containing tons of information about this sleeve.
* @returns Object containing information about this sleeve.
*/
getInformation(sleeveNumber: number): SleeveInformation;
getSleeve(sleeveNumber: number): Sleeve;
/**
* Get task of a sleeve.
@ -3853,6 +3810,7 @@ export interface WorkStats {
* @public
*/
interface WorkFormulas {
crimeSuccessChance(person: Person, crimeType: CrimeType | CrimeNames): number;
crimeGains(person: Person, crimeType: CrimeType | CrimeNames): WorkStats;
classGains(person: Person, classType: string, locationName: string): WorkStats;
factionGains(person: Person, workType: string, favor: number): WorkStats;
@ -4129,7 +4087,8 @@ interface GangFormulas {
*/
export interface Formulas {
mockServer(): Server;
mockPlayer(): Person;
mockPlayer(): Player;
mockPerson(): Person;
/** Reputation formulas */
reputation: ReputationFormulas;
/** Skills formulas */
@ -4465,7 +4424,7 @@ export interface NS {
* Namespace for sleeve functions.
* @remarks RAM cost: 0 GB
*/
readonly sleeve: Sleeve;
readonly sleeve: sleeve;
/**
* Namespace for stock functions.
@ -5180,6 +5139,25 @@ export interface NS {
*/
scan(host?: string): string[];
/** Returns whether the player has access to the darkweb.
* @remarks
* RAM cost: 0.05GB
*
* @example
* ```js
* // NS1:
* if (hasTorRouter()) tprint("TOR router detected.");
* ```
*
* @example
* ```js
* // NS2:
* if (ns.hasTorRouter()) tprint("TOR router detected.");
* ```
*
* @returns Whether player has access to the dark web. */
hasTorRouter(): boolean;
/**
* Runs NUKE.exe on a server.
* @remarks
@ -6705,7 +6683,7 @@ export interface NS {
*
* @returns Player info
*/
getPlayer(): Person;
getPlayer(): Player;
/**
* Get information about the sources of income for this run.
@ -7201,12 +7179,14 @@ export interface WarehouseAPI {
* @public
*/
export interface Corporation extends WarehouseAPI, OfficeAPI {
/**
* Create a Corporation
/** Returns whether the player has a corporation. Does not require API access.
* @returns whether the player has a corporation */
hasCorporation(): boolean;
/** Create a Corporation
* @param divisionName - Name of the division
* @param selfFund - If you should self fund, defaults to true, false will only work on Bitnode 3
* @returns true if created and false if not
*/
* @returns true if created and false if not */
createCorporation(corporationName: string, selfFund: boolean): boolean;
/**
* Check if you have a one time unlockable upgrade

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

@ -6,6 +6,7 @@ import { Player } from "@player";
import { Programs } from "../Programs/Programs";
import { Work, WorkType } from "./Work";
import { Program } from "../Programs/Program";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
export const isCreateProgramWork = (w: Work | null): w is CreateProgramWork =>
w !== null && w.type === WorkType.CREATE_PROGRAM;
@ -61,7 +62,7 @@ export class CreateProgramWork extends Work {
}
//Higher hacking skill will allow you to create programs faster
const reqLvl = this.getProgram().create?.level ?? 0;
let skillMult = (Player.skills.hacking / reqLvl) * Player.getIntelligenceBonus(3); //This should always be greater than 1;
let skillMult = (Player.skills.hacking / reqLvl) * calculateIntelligenceBonus(Player.skills.intelligence, 3); //This should always be greater than 1;
skillMult = 1 + (skillMult - 1) / 5; //The divider constant can be adjusted as necessary
skillMult *= focusBonus;
//Skill multiplier directly applied to "time worked"

@ -1,7 +1,7 @@
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Crime } from "../Crime/Crime";
import { newWorkStats, scaleWorkStats, WorkStats, multWorkStats } from "./WorkStats";
import { Person } from "../PersonObjects/Person";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { CONSTANTS } from "../Constants";
import { FactionWorkType } from "./data/FactionWorkType";
import {
@ -40,7 +40,7 @@ export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
}),
};
export function calculateCrimeWorkStats(person: Person, crime: Crime): WorkStats {
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.
@ -63,7 +63,7 @@ export function calculateCrimeWorkStats(person: Person, crime: Crime): WorkStats
return gains;
}
export const calculateFactionRep = (person: Person, type: FactionWorkType, favor: number): number => {
export const calculateFactionRep = (person: IPerson, type: FactionWorkType, favor: number): number => {
const repFormulas = {
[FactionWorkType.HACKING]: getHackingWorkRepGain,
[FactionWorkType.FIELD]: getFactionFieldWorkRepGain,
@ -72,7 +72,7 @@ export const calculateFactionRep = (person: Person, type: FactionWorkType, favor
return repFormulas[type](person, favor);
};
export function calculateFactionExp(person: Person, type: FactionWorkType): WorkStats {
export function calculateFactionExp(person: IPerson, type: FactionWorkType): WorkStats {
return scaleWorkStats(
multWorkStats(FactionWorkStats[type], person.mults),
BitNodeMultipliers.FactionWorkExpGain / gameCPS,
@ -87,7 +87,7 @@ export function calculateCost(classs: Class, location: Location): number {
return classs.earnings.money * location.costMult * discount;
}
export function calculateClassEarnings(person: Person, type: ClassType, locationName: LocationName): WorkStats {
export function calculateClassEarnings(person: IPerson, type: ClassType, locationName: LocationName): WorkStats {
const hashManager = Player.hashManager;
const classs = Classes[type];
const location = Locations[locationName];
@ -107,7 +107,7 @@ export function calculateClassEarnings(person: Person, type: ClassType, location
}
export const calculateCompanyWorkStats = (
worker: Person,
worker: IPerson,
company: Company,
companyPosition: CompanyPosition,
favor: number,