diff --git a/markdown/bitburner.hackingformulas.growamount.md b/markdown/bitburner.hackingformulas.growamount.md new file mode 100644 index 000000000..71b1f165f --- /dev/null +++ b/markdown/bitburner.hackingformulas.growamount.md @@ -0,0 +1,33 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [HackingFormulas](./bitburner.hackingformulas.md) > [growAmount](./bitburner.hackingformulas.growamount.md) + +## HackingFormulas.growAmount() method + +Calculate the amount of money a grow action will leave a server with. Starting money is server.moneyAvailable. Note that when simulating the effect of [grow](./bitburner.ns.grow.md), what matters is the state of the server and player when the grow \*finishes\*, not when it is started. + +The growth amount depends both linearly \*and\* exponentially on threads; see [grow](./bitburner.ns.grow.md) for more details. + +The inverse of this function is [formulas.hacking.growThreads](./bitburner.hackingformulas.growthreads.md), although it rounds up to integer threads. + +**Signature:** + +```typescript +growAmount(server: Server, player: Person, threads: number, cores?: number): number; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| server | [Server](./bitburner.server.md) | Server info, typically from [getServer](./bitburner.ns.getserver.md) | +| player | [Person](./bitburner.person.md) | Player info, typically from [getPlayer](./bitburner.ns.getplayer.md) | +| threads | number | Number of threads to grow with. Can be fractional. | +| cores | number | _(Optional)_ Number of cores on the computer that will execute grow. | + +**Returns:** + +number + +The amount of money after the calculated grow. + diff --git a/markdown/bitburner.hackingformulas.growpercent.md b/markdown/bitburner.hackingformulas.growpercent.md index bf61c4105..c56ade88b 100644 --- a/markdown/bitburner.hackingformulas.growpercent.md +++ b/markdown/bitburner.hackingformulas.growpercent.md @@ -4,7 +4,13 @@ ## HackingFormulas.growPercent() method -Calculate the percent a server would grow to. Not exact due to limitations of mathematics. (Ex: 3.0 would grow the server to 300% of its current value.) +Calculate the growth multiplier constant for a given server and threads. + +The actual amount of money grown depends both linearly \*and\* exponentially on threads; this is only giving the exponential part that is used for the multiplier. See [grow](./bitburner.ns.grow.md) for more details. + +As a result of the above, this multiplier does \*not\* depend on the amount of money on the server. Changing server.moneyAvailable and server.moneyMax will have no effect. + +For the most common use-cases, you probably want either [formulas.hacking.growThreads](./bitburner.hackingformulas.growthreads.md) or [formulas.hacking.growAmount](./bitburner.hackingformulas.growamount.md) instead. **Signature:** @@ -17,7 +23,7 @@ growPercent(server: Server, threads: number, player: Person, cores?: number): nu | Parameter | Type | Description | | --- | --- | --- | | server | [Server](./bitburner.server.md) | Server info, typically from [getServer](./bitburner.ns.getserver.md) | -| threads | number | Amount of thread. | +| threads | number | Amount of threads. Can be fractional. | | player | [Person](./bitburner.person.md) | Player info, typically from [getPlayer](./bitburner.ns.getplayer.md) | | cores | number | _(Optional)_ Number of cores on the computer that will execute grow. | diff --git a/markdown/bitburner.hackingformulas.growthreads.md b/markdown/bitburner.hackingformulas.growthreads.md index be57c00eb..6e21fba40 100644 --- a/markdown/bitburner.hackingformulas.growthreads.md +++ b/markdown/bitburner.hackingformulas.growthreads.md @@ -4,7 +4,11 @@ ## HackingFormulas.growThreads() method -Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable. +Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable. Note that when simulating the effect of [grow](./bitburner.ns.grow.md), what matters is the state of the server and player when the grow \*finishes\*, not when it is started. + +The growth amount depends both linearly \*and\* exponentially on threads; see [grow](./bitburner.ns.grow.md) for more details. + +The inverse of this function is [formulas.hacking.growAmount](./bitburner.hackingformulas.growamount.md), although it can work with fractional threads. **Signature:** diff --git a/markdown/bitburner.hackingformulas.md b/markdown/bitburner.hackingformulas.md index 45d27dfd8..d1caf2f8f 100644 --- a/markdown/bitburner.hackingformulas.md +++ b/markdown/bitburner.hackingformulas.md @@ -16,8 +16,9 @@ interface HackingFormulas | Method | Description | | --- | --- | -| [growPercent(server, threads, player, cores)](./bitburner.hackingformulas.growpercent.md) | Calculate the percent a server would grow to. Not exact due to limitations of mathematics. (Ex: 3.0 would grow the server to 300% of its current value.) | -| [growThreads(server, player, targetMoney, cores)](./bitburner.hackingformulas.growthreads.md) | Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable. | +| [growAmount(server, player, threads, cores)](./bitburner.hackingformulas.growamount.md) |

Calculate the amount of money a grow action will leave a server with. Starting money is server.moneyAvailable. Note that when simulating the effect of [grow](./bitburner.ns.grow.md), what matters is the state of the server and player when the grow \*finishes\*, not when it is started.

The growth amount depends both linearly \*and\* exponentially on threads; see [grow](./bitburner.ns.grow.md) for more details.

The inverse of this function is [formulas.hacking.growThreads](./bitburner.hackingformulas.growthreads.md), although it rounds up to integer threads.

| +| [growPercent(server, threads, player, cores)](./bitburner.hackingformulas.growpercent.md) |

Calculate the growth multiplier constant for a given server and threads.

The actual amount of money grown depends both linearly \*and\* exponentially on threads; this is only giving the exponential part that is used for the multiplier. See [grow](./bitburner.ns.grow.md) for more details.

As a result of the above, this multiplier does \*not\* depend on the amount of money on the server. Changing server.moneyAvailable and server.moneyMax will have no effect.

For the most common use-cases, you probably want either [formulas.hacking.growThreads](./bitburner.hackingformulas.growthreads.md) or [formulas.hacking.growAmount](./bitburner.hackingformulas.growamount.md) instead.

| +| [growThreads(server, player, targetMoney, cores)](./bitburner.hackingformulas.growthreads.md) |

Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable. Note that when simulating the effect of [grow](./bitburner.ns.grow.md), what matters is the state of the server and player when the grow \*finishes\*, not when it is started.

The growth amount depends both linearly \*and\* exponentially on threads; see [grow](./bitburner.ns.grow.md) for more details.

The inverse of this function is [formulas.hacking.growAmount](./bitburner.hackingformulas.growamount.md), although it can work with fractional threads.

| | [growTime(server, player)](./bitburner.hackingformulas.growtime.md) | Calculate grow time. | | [hackChance(server, player)](./bitburner.hackingformulas.hackchance.md) | Calculate hack chance. (Ex: 0.25 would indicate a 25% chance of success.) | | [hackExp(server, player)](./bitburner.hackingformulas.hackexp.md) | Calculate hack exp for one thread. | diff --git a/markdown/bitburner.ns.grow.md b/markdown/bitburner.ns.grow.md index 02ba93ddf..45c94bc0a 100644 --- a/markdown/bitburner.ns.grow.md +++ b/markdown/bitburner.ns.grow.md @@ -41,7 +41,9 @@ The multiplier scales exponentially with thread count, and its base depends on t [growthAnalyze](./bitburner.ns.growthanalyze.md) can be used to determine the number of threads needed for a specified multiplicative portion of server growth. -To determine the effect of a single grow, obtain access to the Formulas API and use [formulas.hacking.growPercent](./bitburner.hackingformulas.growpercent.md), or invert [growthAnalyze](./bitburner.ns.growthanalyze.md). +To determine the effect of a single grow, obtain access to the Formulas API and use [formulas.hacking.growPercent](./bitburner.hackingformulas.growamount.md), or invert [growthAnalyze](./bitburner.ns.growthanalyze.md). + +To determine how many threads are needed to return a server to max money, obtain access to the Formulas API and use [formulas.hacking.growThreads](./bitburner.hackingformulas.growthreads.md), or [NS.growthAnalyze()](./bitburner.ns.growthanalyze.md) \*if\* the server will be at the same security in the future. Like [hack](./bitburner.ns.hack.md), `grow` can be called on any hackable server, regardless of where the script is running. Hackable servers are any servers not owned by the player. diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index aaa913993..9b0f5cfd6 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -615,6 +615,7 @@ export const RamCosts: RamCostTree = { hackPercent: 0, growPercent: 0, growThreads: 0, + growAmount: 0, hackTime: 0, growTime: 0, weakenTime: 0, diff --git a/src/NetscriptFunctions/Formulas.ts b/src/NetscriptFunctions/Formulas.ts index 98f9d2cad..efdcb294a 100644 --- a/src/NetscriptFunctions/Formulas.ts +++ b/src/NetscriptFunctions/Formulas.ts @@ -1,5 +1,5 @@ import { Player as player } from "../Player"; -import { calculateServerGrowth } from "../Server/formulas/grow"; +import { calculateServerGrowth, calculateGrowMoney } from "../Server/formulas/grow"; import { numCycleForGrowthCorrected } from "../Server/ServerHelpers"; import { calculateMoneyGainRate, @@ -196,6 +196,16 @@ export function NetscriptFormulas(): InternalAPI { checkFormulasAccess(ctx); return numCycleForGrowthCorrected(server, targetMoney, startMoney, cores, player); }, + growAmount: + (ctx) => + (_server, _player, _threads, _cores = 1) => { + const server = helpers.server(ctx, _server); + const person = helpers.person(ctx, _player); + const threads = helpers.number(ctx, "threads", _threads); + const cores = helpers.number(ctx, "cores", _cores); + checkFormulasAccess(ctx); + return calculateGrowMoney(server, threads, person, cores); + }, hackTime: (ctx) => (_server, _player) => { const server = helpers.server(ctx, _server); const person = helpers.person(ctx, _player); diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 29fb3612a..a54d21244 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -4684,11 +4684,20 @@ interface HackingFormulas { */ hackPercent(server: Server, player: Person): number; /** - * Calculate the percent a server would grow to. - * Not exact due to limitations of mathematics. - * (Ex: 3.0 would grow the server to 300% of its current value.) + * Calculate the growth multiplier constant for a given server and threads. + * + * The actual amount of money grown depends both linearly *and* exponentially on threads; + * this is only giving the exponential part that is used for the multiplier. + * See {@link NS.grow | grow} for more details. + * + * As a result of the above, this multiplier does *not* depend on the amount of money on the server. + * Changing server.moneyAvailable and server.moneyMax will have no effect. + * + * For the most common use-cases, you probably want + * either {@link HackingFormulas.growThreads | formulas.hacking.growThreads} + * or {@link HackingFormulas.growAmount | formulas.hacking.growAmount} instead. * @param server - Server info, typically from {@link NS.getServer | getServer} - * @param threads - Amount of thread. + * @param threads - Amount of threads. Can be fractional. * @param player - Player info, typically from {@link NS.getPlayer | getPlayer} * @param cores - Number of cores on the computer that will execute grow. * @returns The calculated grow percent. @@ -4696,6 +4705,13 @@ interface HackingFormulas { growPercent(server: Server, threads: number, player: Person, cores?: number): number; /** * Calculate how many threads it will take to grow server to targetMoney. Starting money is server.moneyAvailable. + * Note that when simulating the effect of {@link NS.grow | grow}, what matters is the state of the server and player + * when the grow *finishes*, not when it is started. + * + * The growth amount depends both linearly *and* exponentially on threads; see {@link NS.grow | grow} for more details. + * + * The inverse of this function is {@link HackingFormulas.growAmount | formulas.hacking.growAmount}, + * although it can work with fractional threads. * @param server - Server info, typically from {@link NS.getServer | getServer} * @param player - Player info, typically from {@link NS.getPlayer | getPlayer} * @param targetMoney - Desired final money, capped to server's moneyMax @@ -4703,6 +4719,22 @@ interface HackingFormulas { * @returns The calculated grow threads as an integer, rounded up. */ growThreads(server: Server, player: Person, targetMoney: number, cores?: number): number; + /** + * Calculate the amount of money a grow action will leave a server with. Starting money is server.moneyAvailable. + * Note that when simulating the effect of {@link NS.grow | grow}, what matters is the state of the server and player + * when the grow *finishes*, not when it is started. + * + * The growth amount depends both linearly *and* exponentially on threads; see {@link NS.grow | grow} for more details. + * + * The inverse of this function is {@link HackingFormulas.growThreads | formulas.hacking.growThreads}, + * although it rounds up to integer threads. + * @param server - Server info, typically from {@link NS.getServer | getServer} + * @param player - Player info, typically from {@link NS.getPlayer | getPlayer} + * @param threads - Number of threads to grow with. Can be fractional. + * @param cores - Number of cores on the computer that will execute grow. + * @returns The amount of money after the calculated grow. + */ + growAmount(server: Server, player: Person, threads: number, cores?: number): number; /** * Calculate hack time. * @param server - Server info, typically from {@link NS.getServer | getServer} @@ -5365,7 +5397,11 @@ export interface NS { * multiplicative portion of server growth. * * To determine the effect of a single grow, obtain access to the Formulas API and use - * {@link HackingFormulas.growPercent | formulas.hacking.growPercent}, or invert {@link NS.growthAnalyze | growthAnalyze}. + * {@link HackingFormulas.growAmount | formulas.hacking.growPercent}, or invert {@link NS.growthAnalyze | growthAnalyze}. + * + * To determine how many threads are needed to return a server to max money, obtain access to the Formulas API and use + * {@link HackingFormulas.growThreads | formulas.hacking.growThreads}, or {@link NS.growthAnalyze} *if* the server will + * be at the same security in the future. * * Like {@link NS.hack | hack}, `grow` can be called on any hackable server, regardless of where the script is * running. Hackable servers are any servers not owned by the player. diff --git a/src/Server/ServerHelpers.ts b/src/Server/ServerHelpers.ts index 90a2711d6..7f60233ca 100644 --- a/src/Server/ServerHelpers.ts +++ b/src/Server/ServerHelpers.ts @@ -1,13 +1,12 @@ import { GetServer, createUniqueRandomIp, ipExists } from "./AllServers"; import { Server, IConstructorParams } from "./Server"; import { BaseServer } from "./BaseServer"; -import { calculateServerGrowth, calculateServerGrowthLog } from "./formulas/grow"; +import { calculateGrowMoney, calculateServerGrowthLog } from "./formulas/grow"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { ServerConstants } from "./data/Constants"; import { Player } from "@player"; import { CompletedProgramName, LiteratureName } from "@enums"; import { Person as IPerson } from "@nsdefs"; -import { isValidNumber } from "../utils/helpers/isValidNumber"; import { Server as IServer } from "@nsdefs"; import { workerScripts } from "../Netscript/WorkerScripts"; import { killWorkerScriptByPid } from "../Netscript/killWorkerScript"; @@ -177,25 +176,8 @@ export function numCycleForGrowthCorrected( //Applied server growth for a single server. Returns the percentage growth export function processSingleServerGrowth(server: Server, threads: number, cores = 1): number { - let serverGrowth = calculateServerGrowth(server, threads, Player, cores); - if (serverGrowth < 1) { - console.warn("serverGrowth calculated to be less than 1"); - serverGrowth = 1; - } - const oldMoneyAvailable = server.moneyAvailable; - server.moneyAvailable += threads; // It can be grown even if it has no money - server.moneyAvailable *= serverGrowth; - - // in case of data corruption - if (isValidNumber(server.moneyMax) && isNaN(server.moneyAvailable)) { - server.moneyAvailable = server.moneyMax; - } - - // cap at max - if (isValidNumber(server.moneyMax) && server.moneyAvailable > server.moneyMax) { - server.moneyAvailable = server.moneyMax; - } + server.moneyAvailable = calculateGrowMoney(server, threads, Player, cores); // if there was any growth at all, increase security if (oldMoneyAvailable !== server.moneyAvailable) { diff --git a/src/Server/formulas/grow.ts b/src/Server/formulas/grow.ts index 4e2416e01..eaf16b7ea 100644 --- a/src/Server/formulas/grow.ts +++ b/src/Server/formulas/grow.ts @@ -1,6 +1,7 @@ import { currentNodeMults } from "../../BitNode/BitNodeMultipliers"; import { Person as IPerson, Server as IServer } from "@nsdefs"; import { ServerConstants } from "../data/Constants"; +import { isValidNumber } from "../../utils/helpers/isValidNumber"; // Returns the log of the growth rate. When passing 1 for threads, this gives a useful constant. export function calculateServerGrowthLog(server: IServer, threads: number, p: IPerson, cores = 1): number { @@ -30,3 +31,27 @@ export function calculateServerGrowth(server: IServer, threads: number, p: IPers if (!server.serverGrowth) return 0; return Math.exp(calculateServerGrowthLog(server, threads, p, cores)); } + +// This differs from calculateServerGrowth in that it includes the additive +// factor and all the boundary checks. +export function calculateGrowMoney(server: IServer, threads: number, p: IPerson, cores = 1): number { + let serverGrowth = calculateServerGrowth(server, threads, p, cores); + if (serverGrowth < 1) { + console.warn("serverGrowth calculated to be less than 1"); + serverGrowth = 1; + } + + let moneyAvailable = server.moneyAvailable ?? Number.NaN; + moneyAvailable += threads; // It can be grown even if it has no money + moneyAvailable *= serverGrowth; + + // cap at max (or data corruption) + if ( + server.moneyMax !== undefined && + isValidNumber(server.moneyMax) && + (moneyAvailable > server.moneyMax || isNaN(moneyAvailable)) + ) { + moneyAvailable = server.moneyMax; + } + return moneyAvailable; +}