NETSCRIPT: Added ns.corporation.issueNewShares function (#261)

This commit is contained in:
Mughur 2022-12-25 10:35:18 +02:00 committed by GitHub
parent 556fe8dd33
commit 5c80655d62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 26 deletions

@ -16,6 +16,7 @@ import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers"; import { isRelevantMaterial } from "./ui/Helpers";
import { checkEnum } from "../utils/helpers/enum"; import { checkEnum } from "../utils/helpers/enum";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
import { getRandomInt } from "../utils/helpers/getRandomInt";
export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void { export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void {
if (corporation.divisions.find(({ type }) => industry == type)) if (corporation.divisions.find(({ type }) => industry == type))
@ -90,6 +91,33 @@ export function IssueDividends(corporation: Corporation, rate: number): void {
corporation.dividendRate = rate; 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 { export function SellMaterial(mat: Material, amt: string, price: string): void {
if (price === "") price = "0"; if (price === "") price = "0";
if (amt === "") amt = "0"; if (amt === "") amt = "0";

@ -225,6 +225,12 @@ export class Corporation {
this.sharePrice = this.getTargetSharePrice(); 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 // Calculates how much money will be made and what the resulting stock price
// will be when the player sells his/her shares // will be when the player sells his/her shares
// @return - [Player profit, final stock price, end shareSalesUntilPriceUpdate property] // @return - [Player profit, final stock price, end shareSalesUntilPriceUpdate property]

@ -2,13 +2,12 @@ import React, { useState } from "react";
import { numeralWrapper } from "../../../ui/numeralFormat"; import { numeralWrapper } from "../../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
import { CorporationConstants } from "../../data/Constants";
import { useCorporation } from "../Context"; import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { NumberInput } from "../../../ui/React/NumberInput"; import { NumberInput } from "../../../ui/React/NumberInput";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { KEY } from "../../../utils/helpers/keyCodes"; import { KEY } from "../../../utils/helpers/keyCodes";
import { IssueNewShares } from "../../Actions";
interface IEffectTextProps { interface IEffectTextProps {
shares: number | null; shares: number | null;
@ -18,8 +17,7 @@ function EffectText(props: IEffectTextProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
if (props.shares === null) return <></>; if (props.shares === null) return <></>;
const newSharePrice = Math.round(corp.sharePrice * 0.9); const newSharePrice = Math.round(corp.sharePrice * 0.9);
const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2); const maxNewShares = corp.calculateMaxNewShares();
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
let newShares = props.shares; let newShares = props.shares;
if (isNaN(newShares)) { if (isNaN(newShares)) {
return <Typography>Invalid input</Typography>; return <Typography>Invalid input</Typography>;
@ -55,8 +53,7 @@ interface IProps {
export function IssueNewSharesModal(props: IProps): React.ReactElement { export function IssueNewSharesModal(props: IProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const [shares, setShares] = useState<number>(NaN); const [shares, setShares] = useState<number>(NaN);
const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2); const maxNewShares = corp.calculateMaxNewShares();
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
const newShares = Math.round((shares || 0) / 10e6) * 10e6; const newShares = Math.round((shares || 0) / 10e6) * 10e6;
const disabled = isNaN(shares) || isNaN(newShares) || newShares < 10e6 || newShares > maxNewShares; const disabled = isNaN(shares) || isNaN(newShares) || newShares < 10e6 || newShares > maxNewShares;
@ -64,27 +61,8 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
function issueNewShares(): void { function issueNewShares(): void {
if (isNaN(shares)) return; if (isNaN(shares)) return;
if (disabled) 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(); props.onClose();
let dialogContents = let dialogContents =

@ -373,6 +373,7 @@ const corporation = {
unlockUpgrade: 0, unlockUpgrade: 0,
levelUpgrade: 0, levelUpgrade: 0,
issueDividends: 0, issueDividends: 0,
issueNewShares: 0,
buyBackShares: 0, buyBackShares: 0,
sellShares: 0, sellShares: 0,
getBonusTime: 0, getBonusTime: 0,

@ -24,6 +24,7 @@ import {
UnlockUpgrade, UnlockUpgrade,
LevelUpgrade, LevelUpgrade,
IssueDividends, IssueDividends,
IssueNewShares,
SellMaterial, SellMaterial,
SellProduct, SellProduct,
SetSmartSupply, SetSmartSupply,
@ -820,6 +821,21 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
if (!corporation.public) throw helpers.makeRuntimeErrorMsg(ctx, `Your company has not gone public!`); if (!corporation.public) throw helpers.makeRuntimeErrorMsg(ctx, `Your company has not gone public!`);
IssueDividends(corporation, rate); 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) => { getDivision: (ctx) => (_divisionName) => {
checkAccess(ctx); checkAccess(ctx);
const divisionName = helpers.string(ctx, "divisionName", _divisionName); const divisionName = helpers.string(ctx, "divisionName", _divisionName);

@ -7545,6 +7545,11 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
* @param rate - Fraction of profit to issue as dividends. */ * @param rate - Fraction of profit to issue as dividends. */
issueDividends(rate: number): void; 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 /** Buyback Shares
* @param amount - Amount of shares to buy back. */ * @param amount - Amount of shares to buy back. */
buyBackShares(amount: number): void; buyBackShares(amount: number): void;