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;
+}