diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts
index bf13b6d33..a16f8bdd0 100644
--- a/src/Corporation/Actions.ts
+++ b/src/Corporation/Actions.ts
@@ -16,6 +16,7 @@ import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers";
import { checkEnum } from "../utils/helpers/enum";
import { CityName } from "../Locations/data/CityNames";
+import { getRandomInt } from "../utils/helpers/getRandomInt";
export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void {
if (corporation.divisions.find(({ type }) => industry == type))
@@ -90,6 +91,33 @@ export function IssueDividends(corporation: Corporation, rate: number): void {
corporation.dividendRate = rate;
}
+export function IssueNewShares(corporation: Corporation, amount: number): [number, number, number] {
+ const max = corporation.calculateMaxNewShares();
+
+ // Round to nearest ten-millionth
+ amount = Math.round(amount / 10e6) * 10e6;
+
+ if (isNaN(amount) || amount < 10e6 || amount > max) {
+ throw new Error(`Invalid value. Must be an number between 10m and ${max} (20% of total shares)`);
+ }
+
+ const newSharePrice = Math.round(corporation.sharePrice * 0.9);
+
+ const profit = amount * newSharePrice;
+ corporation.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
+
+ const privateOwnedRatio = 1 - (corporation.numShares + corporation.issuedShares) / corporation.totalShares;
+ const maxPrivateShares = Math.round((amount / 2) * privateOwnedRatio);
+ const privateShares = Math.round(getRandomInt(0, maxPrivateShares) / 10e6) * 10e6;
+
+ corporation.issuedShares += amount - privateShares;
+ corporation.totalShares += amount;
+ corporation.funds = corporation.funds + profit;
+ corporation.immediatelyUpdateSharePrice();
+
+ return [profit, amount, privateShares];
+}
+
export function SellMaterial(mat: Material, amt: string, price: string): void {
if (price === "") price = "0";
if (amt === "") amt = "0";
diff --git a/src/Corporation/Corporation.tsx b/src/Corporation/Corporation.tsx
index c7e2f2381..6f0d71595 100644
--- a/src/Corporation/Corporation.tsx
+++ b/src/Corporation/Corporation.tsx
@@ -225,6 +225,12 @@ export class Corporation {
this.sharePrice = this.getTargetSharePrice();
}
+ calculateMaxNewShares(): number {
+ const maxNewSharesUnrounded = Math.round(this.totalShares * 0.2);
+ const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 10e6);
+ return maxNewShares;
+ }
+
// Calculates how much money will be made and what the resulting stock price
// will be when the player sells his/her shares
// @return - [Player profit, final stock price, end shareSalesUntilPriceUpdate property]
diff --git a/src/Corporation/ui/modals/IssueNewSharesModal.tsx b/src/Corporation/ui/modals/IssueNewSharesModal.tsx
index 944d58203..306c9f9aa 100644
--- a/src/Corporation/ui/modals/IssueNewSharesModal.tsx
+++ b/src/Corporation/ui/modals/IssueNewSharesModal.tsx
@@ -2,13 +2,12 @@ import React, { useState } from "react";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Modal } from "../../../ui/React/Modal";
-import { getRandomInt } from "../../../utils/helpers/getRandomInt";
-import { CorporationConstants } from "../../data/Constants";
import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography";
import { NumberInput } from "../../../ui/React/NumberInput";
import Button from "@mui/material/Button";
import { KEY } from "../../../utils/helpers/keyCodes";
+import { IssueNewShares } from "../../Actions";
interface IEffectTextProps {
shares: number | null;
@@ -18,8 +17,7 @@ function EffectText(props: IEffectTextProps): React.ReactElement {
const corp = useCorporation();
if (props.shares === null) return <>>;
const newSharePrice = Math.round(corp.sharePrice * 0.9);
- const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2);
- const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
+ const maxNewShares = corp.calculateMaxNewShares();
let newShares = props.shares;
if (isNaN(newShares)) {
return Invalid input;
@@ -55,8 +53,7 @@ interface IProps {
export function IssueNewSharesModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const [shares, setShares] = useState(NaN);
- const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2);
- const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
+ const maxNewShares = corp.calculateMaxNewShares();
const newShares = Math.round((shares || 0) / 10e6) * 10e6;
const disabled = isNaN(shares) || isNaN(newShares) || newShares < 10e6 || newShares > maxNewShares;
@@ -64,27 +61,8 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
function issueNewShares(): void {
if (isNaN(shares)) return;
if (disabled) return;
+ const [profit, newShares, privateShares] = IssueNewShares(corp, shares);
- const newSharePrice = Math.round(corp.sharePrice * 0.9);
- let newShares = shares;
-
- // Round to nearest ten-millionth
- newShares = Math.round(newShares / 10e6) * 10e6;
-
- const profit = newShares * newSharePrice;
- corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
-
- // Determine how many are bought by private investors
- // If private investors own n% of the company, private investors get up to 0.5n% at most
- // Round # of private shares to the nearest million
- const privateOwnedRatio = 1 - (corp.numShares + corp.issuedShares) / corp.totalShares;
- const maxPrivateShares = Math.round((newShares / 2) * privateOwnedRatio);
- const privateShares = Math.round(getRandomInt(0, maxPrivateShares) / 1e6) * 1e6;
-
- corp.issuedShares += newShares - privateShares;
- corp.totalShares += newShares;
- corp.funds = corp.funds + profit;
- corp.immediatelyUpdateSharePrice();
props.onClose();
let dialogContents =
diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts
index 296c22e53..ed631a5f7 100644
--- a/src/Netscript/RamCostGenerator.ts
+++ b/src/Netscript/RamCostGenerator.ts
@@ -373,6 +373,7 @@ const corporation = {
unlockUpgrade: 0,
levelUpgrade: 0,
issueDividends: 0,
+ issueNewShares: 0,
buyBackShares: 0,
sellShares: 0,
getBonusTime: 0,
diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts
index cd51a3075..f34c142ad 100644
--- a/src/NetscriptFunctions/Corporation.ts
+++ b/src/NetscriptFunctions/Corporation.ts
@@ -24,6 +24,7 @@ import {
UnlockUpgrade,
LevelUpgrade,
IssueDividends,
+ IssueNewShares,
SellMaterial,
SellProduct,
SetSmartSupply,
@@ -820,6 +821,21 @@ export function NetscriptCorporation(): InternalAPI {
if (!corporation.public) throw helpers.makeRuntimeErrorMsg(ctx, `Your company has not gone public!`);
IssueDividends(corporation, rate);
},
+ issueNewShares: (ctx) => (_amount) => {
+ checkAccess(ctx);
+ const corporation = getCorporation();
+ const maxNewShares = corporation.calculateMaxNewShares();
+ if (_amount == undefined) _amount = maxNewShares;
+ const amount = helpers.number(ctx, "amount", _amount);
+ if (corporation.issueNewSharesCooldown > 0) throw new Error(`Can't issue new shares, action on cooldown.`);
+ if (amount < 10e6 || amount > maxNewShares)
+ throw new Error(
+ `Invalid value for amount field! Must be numeric, greater than 10m, and less than ${maxNewShares} (20% of total shares)`,
+ );
+ if (!corporation.public) throw helpers.makeRuntimeErrorMsg(ctx, `Your company has not gone public!`);
+ const [funds] = IssueNewShares(corporation, amount);
+ return funds;
+ },
getDivision: (ctx) => (_divisionName) => {
checkAccess(ctx);
const divisionName = helpers.string(ctx, "divisionName", _divisionName);
diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts
index ff09b105d..63fe874e5 100644
--- a/src/ScriptEditor/NetscriptDefinitions.d.ts
+++ b/src/ScriptEditor/NetscriptDefinitions.d.ts
@@ -7545,6 +7545,11 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
* @param rate - Fraction of profit to issue as dividends. */
issueDividends(rate: number): void;
+ /** Issue new shares
+ * @param amount - Number of new shares to issue, will be rounded to nearest 10m. Defaults to max amount.
+ * @returns Amount of funds generated for the corporation. */
+ issueNewShares(amount?: number): number;
+
/** Buyback Shares
* @param amount - Amount of shares to buy back. */
buyBackShares(amount: number): void;