mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-23 06:32:26 +01:00
work on corp mui
This commit is contained in:
parent
86678b6290
commit
a6d7f93111
@ -26,7 +26,7 @@ export function AllPages(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange} aria-label="basic tabs example">
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||
<Tab label="General" />
|
||||
<Tab label="Contracts" />
|
||||
<Tab label="Operations" />
|
||||
|
112
src/Corporation/ui/BribeFactionModal.tsx
Normal file
112
src/Corporation/ui/BribeFactionModal.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import React, { useState } from "react";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Box from "@mui/material/Box";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [money, setMoney] = useState<number | null>(0);
|
||||
const [stock, setStock] = useState<number | null>(0);
|
||||
const [selectedFaction, setSelectedFaction] = useState(
|
||||
player.factions.length > 0 ? player.factions.filter((faction) => Factions[faction].getInfo().offersWork())[0] : "",
|
||||
);
|
||||
|
||||
function onMoneyChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setMoney(parseFloat(event.target.value));
|
||||
}
|
||||
|
||||
function onStockChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setStock(parseFloat(event.target.value));
|
||||
}
|
||||
|
||||
function changeFaction(event: SelectChangeEvent<string>): void {
|
||||
setSelectedFaction(event.target.value);
|
||||
}
|
||||
|
||||
function repGain(money: number, stock: number): number {
|
||||
return (money + stock * corp.sharePrice) / CorporationConstants.BribeToRepRatio;
|
||||
}
|
||||
|
||||
function getRepText(money: number, stock: number): string {
|
||||
if (money === 0 && stock === 0) return "";
|
||||
if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) {
|
||||
return "ERROR: Invalid value(s) entered";
|
||||
} else if (corp.funds.lt(money)) {
|
||||
return "ERROR: You do not have this much money to bribe with";
|
||||
} else if (stock > corp.numShares) {
|
||||
return "ERROR: You do not have this many shares to bribe with";
|
||||
} else {
|
||||
return (
|
||||
"You will gain " +
|
||||
numeralWrapper.formatReputation(repGain(money, stock)) +
|
||||
" reputation with " +
|
||||
selectedFaction +
|
||||
" with this bribe"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function bribe(money: number, stock: number): void {
|
||||
const fac = Factions[selectedFaction];
|
||||
if (fac == null) {
|
||||
dialogBoxCreate("ERROR: You must select a faction to bribe");
|
||||
}
|
||||
if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) {
|
||||
} else if (corp.funds.lt(money)) {
|
||||
} else if (stock > corp.numShares) {
|
||||
} else {
|
||||
const rep = repGain(money, stock);
|
||||
dialogBoxCreate(
|
||||
"You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.",
|
||||
);
|
||||
fac.playerReputation += rep;
|
||||
corp.funds = corp.funds.minus(money);
|
||||
corp.numShares -= stock;
|
||||
props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation.
|
||||
</Typography>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Typography>Faction:</Typography>
|
||||
<Select variant="standard" value={selectedFaction} onChange={changeFaction}>
|
||||
{player.factions.map((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return;
|
||||
return (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</Box>
|
||||
<Typography>{getRepText(money ? money : 0, stock ? stock : 0)}</Typography>
|
||||
<TextField variant="standard" onChange={onMoneyChange} placeholder="Corporation funds" />
|
||||
<TextField sx={{ mx: 1 }} variant="standard" onChange={onStockChange} placeholder="Stock Shares" />
|
||||
<Button sx={{ mx: 1 }} onClick={() => bribe(money ? money : 0, stock ? stock : 0)}>
|
||||
Bribe
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
|
||||
interface IProps {
|
||||
popupId: string;
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function BribeFactionPopup(props: IProps): React.ReactElement {
|
||||
const [money, setMoney] = useState<number | null>(0);
|
||||
const [stock, setStock] = useState<number | null>(0);
|
||||
const [selectedFaction, setSelectedFaction] = useState(
|
||||
props.player.factions.length > 0 ? props.player.factions.filter(faction => Factions[faction].getInfo().offersWork())[0] : ""
|
||||
);
|
||||
|
||||
function onMoneyChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setMoney(parseFloat(event.target.value));
|
||||
}
|
||||
|
||||
function onStockChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setStock(parseFloat(event.target.value));
|
||||
}
|
||||
|
||||
function changeFaction(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
setSelectedFaction(event.target.value);
|
||||
}
|
||||
|
||||
function repGain(money: number, stock: number): number {
|
||||
return (money + stock * props.corp.sharePrice) / CorporationConstants.BribeToRepRatio;
|
||||
}
|
||||
|
||||
function getRepText(money: number, stock: number): string {
|
||||
if (money === 0 && stock === 0) return "";
|
||||
if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) {
|
||||
return "ERROR: Invalid value(s) entered";
|
||||
} else if (props.corp.funds.lt(money)) {
|
||||
return "ERROR: You do not have this much money to bribe with";
|
||||
} else if (stock > props.corp.numShares) {
|
||||
return "ERROR: You do not have this many shares to bribe with";
|
||||
} else {
|
||||
return (
|
||||
"You will gain " +
|
||||
numeralWrapper.formatReputation(repGain(money, stock)) +
|
||||
" reputation with " +
|
||||
selectedFaction +
|
||||
" with this bribe"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function bribe(money: number, stock: number): void {
|
||||
const fac = Factions[selectedFaction];
|
||||
if (fac == null) {
|
||||
dialogBoxCreate("ERROR: You must select a faction to bribe");
|
||||
}
|
||||
if (isNaN(money) || isNaN(stock) || money < 0 || stock < 0) {
|
||||
} else if (props.corp.funds.lt(money)) {
|
||||
} else if (stock > props.corp.numShares) {
|
||||
} else {
|
||||
const rep = repGain(money, stock);
|
||||
dialogBoxCreate(
|
||||
"You gained " + numeralWrapper.formatReputation(rep) + " reputation with " + fac.name + " by bribing them.",
|
||||
);
|
||||
fac.playerReputation += rep;
|
||||
props.corp.funds = props.corp.funds.minus(money);
|
||||
props.corp.numShares -= stock;
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation.</p>
|
||||
<select className="dropdown" style={{ margin: "3px" }} defaultValue={selectedFaction} onChange={changeFaction}>
|
||||
{props.player.factions.map((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return;
|
||||
return (
|
||||
<option key={name} value={name}>
|
||||
{name}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<p>{getRepText(money ? money : 0, stock ? stock : 0)}</p>
|
||||
<input
|
||||
className="text-input"
|
||||
onChange={onMoneyChange}
|
||||
placeholder="Corporation funds"
|
||||
style={{ margin: "5px" }}
|
||||
/>
|
||||
<input className="text-input" onChange={onStockChange} placeholder="Stock Shares" style={{ margin: "5px" }} />
|
||||
<button
|
||||
className="a-link-button"
|
||||
onClick={() => bribe(money ? money : 0, stock ? stock : 0)}
|
||||
style={{ display: "inline-block" }}
|
||||
>
|
||||
Bribe
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,20 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
popupId: string;
|
||||
corp: ICorporation;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player buyback shares
|
||||
// This is created when the player clicks the "Buyback Shares" button in the overview panel
|
||||
export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number | null>(null);
|
||||
|
||||
function changeShares(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
@ -22,38 +23,38 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
else setShares(Math.round(parseFloat(event.target.value)));
|
||||
}
|
||||
|
||||
const currentStockPrice = props.corp.sharePrice;
|
||||
const currentStockPrice = corp.sharePrice;
|
||||
const buybackPrice = currentStockPrice * 1.1;
|
||||
|
||||
function buy(): void {
|
||||
if (shares === null) return;
|
||||
const tempStockPrice = props.corp.sharePrice;
|
||||
const tempStockPrice = corp.sharePrice;
|
||||
const buybackPrice = tempStockPrice * 1.1;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
||||
} else if (shares > props.corp.issuedShares) {
|
||||
} else if (shares > corp.issuedShares) {
|
||||
dialogBoxCreate("ERROR: There are not this many oustanding shares to buy back");
|
||||
} else if (shares * buybackPrice > props.player.money) {
|
||||
} else if (shares * buybackPrice > player.money) {
|
||||
dialogBoxCreate(
|
||||
"ERROR: You do not have enough money to purchase this many shares (you need " +
|
||||
numeralWrapper.format(shares * buybackPrice, "$0.000a") +
|
||||
")",
|
||||
);
|
||||
} else {
|
||||
props.corp.numShares += shares;
|
||||
if (isNaN(props.corp.issuedShares)) {
|
||||
console.warn("Corporation issuedShares is NaN: " + props.corp.issuedShares);
|
||||
corp.numShares += shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.warn("Corporation issuedShares is NaN: " + corp.issuedShares);
|
||||
console.warn("Converting to number now");
|
||||
const res = props.corp.issuedShares;
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
props.corp.issuedShares = 0;
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
props.corp.issuedShares = res;
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
}
|
||||
props.corp.issuedShares -= shares;
|
||||
props.player.loseMoney(shares * buybackPrice);
|
||||
removePopup(props.popupId);
|
||||
corp.issuedShares -= shares;
|
||||
player.loseMoney(shares * buybackPrice);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
}
|
||||
@ -62,11 +63,11 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
if (shares === null) return <></>;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
return <>ERROR: Invalid value entered for number of shares to buyback</>;
|
||||
} else if (shares > props.corp.issuedShares) {
|
||||
} else if (shares > corp.issuedShares) {
|
||||
return (
|
||||
<>
|
||||
There are not this many shares available to buy back. There are only{" "}
|
||||
{numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding shares.
|
||||
{numeralWrapper.formatBigNumber(corp.issuedShares)} outstanding shares.
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
@ -83,7 +84,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<p>
|
||||
Enter the number of outstanding shares you would like to buy back. These shares must be bought at a 10% premium.
|
||||
However, repurchasing shares from the market tends to lead to an increase in stock price.
|
||||
@ -93,7 +94,7 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
The current buyback price of your company's stock is {numeralWrapper.formatMoney(buybackPrice)}. Your company
|
||||
currently has {numeralWrapper.formatBigNumber(props.corp.issuedShares)} outstanding stock shares.
|
||||
currently has {numeralWrapper.formatBigNumber(corp.issuedShares)} outstanding stock shares.
|
||||
</p>
|
||||
<CostIndicator />
|
||||
<br />
|
||||
@ -109,6 +110,6 @@ export function BuybackSharesPopup(props: IProps): React.ReactElement {
|
||||
<button onClick={buy} className="a-link-button" style={{ display: "inline-block" }}>
|
||||
Buy shares
|
||||
</button>
|
||||
</>
|
||||
</Modal>
|
||||
);
|
||||
}
|
10
src/Corporation/ui/Context.ts
Normal file
10
src/Corporation/ui/Context.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import React, { useContext } from "react";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
|
||||
export const Context: {
|
||||
Corporation: React.Context<ICorporation>;
|
||||
} = {
|
||||
Corporation: React.createContext<ICorporation>({} as ICorporation),
|
||||
};
|
||||
|
||||
export const useCorporation = () => useContext(Context.Corporation);
|
@ -2,41 +2,16 @@
|
||||
// These are the tabs at the top of the UI that let you switch to different
|
||||
// divisions, see an overview of your corporation, or create a new industry
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { HeaderTab } from "./HeaderTab";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { NewIndustryPopup } from "./NewIndustryPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { MainPanel } from "./MainPanel";
|
||||
import { Industries } from "../IndustryData";
|
||||
import { ExpandIndustryTab } from "./ExpandIndustryTab";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Context } from "./Context";
|
||||
import { Overview } from "./Overview";
|
||||
|
||||
interface IExpandButtonProps {
|
||||
corp: ICorporation;
|
||||
setDivisionName: (name: string) => void;
|
||||
}
|
||||
|
||||
function ExpandButton(props: IExpandButtonProps): React.ReactElement {
|
||||
const allIndustries = Object.keys(Industries).sort();
|
||||
const possibleIndustries = allIndustries
|
||||
.filter(
|
||||
(industryType: string) =>
|
||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
)
|
||||
.sort();
|
||||
if (possibleIndustries.length === 0) return <></>;
|
||||
|
||||
function openNewIndustryPopup(): void {
|
||||
const popupId = "cmpy-mgmt-expand-industry-popup";
|
||||
createPopup(popupId, NewIndustryPopup, {
|
||||
corp: props.corp,
|
||||
setDivisionName: props.setDivisionName,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
return <HeaderTab current={false} onClick={openNewIndustryPopup} text={"Expand into new Industry"} />;
|
||||
}
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import Tab from "@mui/material/Tab";
|
||||
|
||||
export function CorporationRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
@ -46,33 +21,37 @@ export function CorporationRoot(): React.ReactElement {
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
const [divisionName, setDivisionName] = useState("Overview");
|
||||
|
||||
const [divisionName, setDivisionName] = useState<string | number>("Overview");
|
||||
function handleChange(event: React.SyntheticEvent, tab: string | number): void {
|
||||
setDivisionName(tab);
|
||||
}
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 1000);
|
||||
const id = setInterval(rerender, 200);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const canExpand =
|
||||
Object.keys(Industries).filter(
|
||||
(industryType: string) =>
|
||||
corporation.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
).length > 0;
|
||||
|
||||
return (
|
||||
<div className="cmpy-mgmt-container">
|
||||
<div>
|
||||
<HeaderTab
|
||||
current={divisionName === "Overview"}
|
||||
key={"overview"}
|
||||
onClick={() => setDivisionName("Overview")}
|
||||
text={corporation.name}
|
||||
/>
|
||||
{corporation.divisions.map((division: IIndustry) => (
|
||||
<HeaderTab
|
||||
current={division.name === divisionName}
|
||||
key={division.name}
|
||||
onClick={() => setDivisionName(division.name)}
|
||||
text={division.name}
|
||||
/>
|
||||
))}
|
||||
<ExpandButton corp={corporation} setDivisionName={setDivisionName} />
|
||||
<Context.Corporation.Provider value={corporation}>
|
||||
<div className="cmpy-mgmt-container">
|
||||
<Tabs variant="fullWidth" value={divisionName} onChange={handleChange}>
|
||||
<Tab label={corporation.name} value={"Overview"} />
|
||||
{corporation.divisions.map((div) => (
|
||||
<Tab key={div.name} label={div.name} value={div.name} />
|
||||
))}
|
||||
{canExpand && <Tab label={"Expand"} value={-1} />}
|
||||
</Tabs>
|
||||
{divisionName === "Overview" && <Overview rerender={rerender} />}
|
||||
{divisionName === -1 && <ExpandIndustryTab setDivisionName={setDivisionName} />}
|
||||
{typeof divisionName === "string" && divisionName !== "Overview" && (
|
||||
<MainPanel rerender={rerender} divisionName={divisionName + ""} />
|
||||
)}
|
||||
</div>
|
||||
<MainPanel rerender={rerender} corp={corporation} divisionName={divisionName} player={player} />
|
||||
</div>
|
||||
</Context.Corporation.Provider>
|
||||
);
|
||||
}
|
||||
|
75
src/Corporation/ui/CreateCorporationModal.tsx
Normal file
75
src/Corporation/ui/CreateCorporationModal.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function CreateCorporationModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const canSelfFund = player.canAfford(150e9);
|
||||
if (!player.canAccessCorporation() || player.hasCorporation()) {
|
||||
props.onClose();
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const [name, setName] = useState("");
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setName(event.target.value);
|
||||
}
|
||||
|
||||
function selfFund(): void {
|
||||
if (!canSelfFund) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
player.startCorporation(name);
|
||||
player.loseMoney(150e9);
|
||||
|
||||
props.onClose();
|
||||
router.toCorporation();
|
||||
}
|
||||
|
||||
function seed(): void {
|
||||
if (name == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
player.startCorporation(name, 500e6);
|
||||
|
||||
props.onClose();
|
||||
router.toCorporation();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Would you like to start a corporation? This will require $150b for registration and initial funding. This $150b
|
||||
can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million
|
||||
shares
|
||||
<br />
|
||||
<br />
|
||||
If you would like to start one, please enter a name for your corporation below:
|
||||
</Typography>
|
||||
<TextField autoFocus={true} variant="standard" placeholder="Corporation Name" onChange={onChange} value={name} />
|
||||
<Button onClick={seed} disabled={name == ""}>
|
||||
Use seed money
|
||||
</Button>
|
||||
<Button onClick={selfFund} disabled={name == "" || !canSelfFund}>
|
||||
Self-Fund (<Money money={150e9} player={player} />)
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
popupId: string;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function CreateCorporationPopup(props: IProps): React.ReactElement {
|
||||
if (!props.player.canAccessCorporation() || props.player.hasCorporation()) {
|
||||
removePopup(props.popupId);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const [name, setName] = useState("");
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setName(event.target.value);
|
||||
}
|
||||
|
||||
function selfFund(): void {
|
||||
if (!props.player.canAfford(150e9)) {
|
||||
dialogBoxCreate("You don't have enough money to create a corporation! You need $150b.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "") {
|
||||
dialogBoxCreate("Invalid company name!");
|
||||
return;
|
||||
}
|
||||
|
||||
props.player.startCorporation(name);
|
||||
props.player.loseMoney(150e9);
|
||||
|
||||
dialogBoxCreate(
|
||||
"Congratulations! You just self-funded your own corporation. You can visit " +
|
||||
"and manage your company in the City.",
|
||||
);
|
||||
removePopup(props.popupId);
|
||||
props.router.toCorporation();
|
||||
}
|
||||
|
||||
function seed(): void {
|
||||
if (name == "") {
|
||||
dialogBoxCreate("Invalid company name!");
|
||||
return;
|
||||
}
|
||||
|
||||
props.player.startCorporation(name, 500e6);
|
||||
|
||||
dialogBoxCreate(
|
||||
"Congratulations! You just started your own corporation with government seed money. " +
|
||||
"You can visit and manage your company in the City.",
|
||||
);
|
||||
removePopup(props.popupId);
|
||||
props.router.toCorporation();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Would you like to start a corporation? This will require $150b for registration and initial funding. This $150b
|
||||
can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million
|
||||
shares
|
||||
<br />
|
||||
<br />
|
||||
If you would like to start one, please enter a name for your corporation below:
|
||||
</p>
|
||||
<input autoFocus={true} className="text-input" placeholder="Corporation Name" onChange={onChange} value={name} />
|
||||
<button className="std-button" onClick={seed} disabled={name == ""}>
|
||||
Use seed money
|
||||
</button>
|
||||
<button className="std-button" onClick={selfFund} disabled={name == "" || !props.player.canAfford(150e9)}>
|
||||
Self-Fund (<Money money={150e9} player={props.player} />)
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,24 +1,28 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { Industries, IndustryDescriptions } from "../IndustryData";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { useCorporation } from "./Context";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { NewIndustry } from "../Actions";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Box from "@mui/material/Box";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
setDivisionName: (name: string) => void;
|
||||
}
|
||||
// Create a popup that lets the player create a new industry.
|
||||
// This is created when the player clicks the "Expand into new Industry" header tab
|
||||
export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
|
||||
export function ExpandIndustryTab(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const allIndustries = Object.keys(Industries).sort();
|
||||
const possibleIndustries = allIndustries
|
||||
.filter(
|
||||
(industryType: string) =>
|
||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
)
|
||||
.sort();
|
||||
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
||||
@ -26,7 +30,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
|
||||
function newIndustry(): void {
|
||||
try {
|
||||
NewIndustry(props.corp, industry, name);
|
||||
NewIndustry(corp, industry, name);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
return;
|
||||
@ -34,11 +38,10 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
|
||||
// Set routing to the new division so that the UI automatically switches to it
|
||||
props.setDivisionName(name);
|
||||
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
function onNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
// [a-zA-Z0-9-_]
|
||||
setName(event.target.value);
|
||||
}
|
||||
|
||||
@ -46,7 +49,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
if (event.keyCode === 13) newIndustry();
|
||||
}
|
||||
|
||||
function onIndustryChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
function onIndustryChange(event: SelectChangeEvent<string>): void {
|
||||
setIndustry(event.target.value);
|
||||
}
|
||||
|
||||
@ -55,33 +58,33 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>Create a new division to expand into a new industry:</p>
|
||||
<select className="dropdown" defaultValue={industry} onChange={onIndustryChange}>
|
||||
<Typography>Create a new division to expand into a new industry:</Typography>
|
||||
<Select variant="standard" value={industry} onChange={onIndustryChange}>
|
||||
{possibleIndustries.map((industry: string) => (
|
||||
<option key={industry} value={industry}>
|
||||
<MenuItem key={industry} value={industry}>
|
||||
{industry}
|
||||
</option>
|
||||
</MenuItem>
|
||||
))}
|
||||
</select>
|
||||
<p>{desc(props.corp)}</p>
|
||||
</Select>
|
||||
<Typography>{desc(corp)}</Typography>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>Division name:</p>
|
||||
<input
|
||||
autoFocus={true}
|
||||
value={name}
|
||||
onChange={onNameChange}
|
||||
onKeyDown={onKeyDown}
|
||||
type="text"
|
||||
className="text-input"
|
||||
style={{ display: "block" }}
|
||||
maxLength={30}
|
||||
pattern="[a-zA-Z0-9-_]"
|
||||
/>
|
||||
<span onClick={newIndustry} className="popup-box-button">
|
||||
Create Division
|
||||
</span>
|
||||
<Typography>Division name:</Typography>
|
||||
|
||||
<Box display="flex" alignItems="center">
|
||||
<TextField
|
||||
variant="standard"
|
||||
autoFocus={true}
|
||||
value={name}
|
||||
onChange={onNameChange}
|
||||
onKeyDown={onKeyDown}
|
||||
type="text"
|
||||
/>
|
||||
<Button sx={{ mx: 1 }} onClick={newIndustry}>
|
||||
Create Division
|
||||
</Button>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,23 +1,25 @@
|
||||
import React from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
player: IPlayer;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
export function FindInvestorsPopup(props: IProps): React.ReactElement {
|
||||
const val = props.corp.determineValuation();
|
||||
export function FindInvestorsModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const val = corp.determineValuation();
|
||||
let percShares = 0;
|
||||
let roundMultiplier = 4;
|
||||
switch (props.corp.fundingRound) {
|
||||
switch (corp.fundingRound) {
|
||||
case 0: //Seed
|
||||
percShares = 0.1;
|
||||
roundMultiplier = 4;
|
||||
@ -41,15 +43,15 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement {
|
||||
const investShares = Math.floor(CorporationConstants.INITIALSHARES * percShares);
|
||||
|
||||
function findInvestors(): void {
|
||||
props.corp.fundingRound++;
|
||||
props.corp.addFunds(funding);
|
||||
props.corp.numShares -= investShares;
|
||||
corp.fundingRound++;
|
||||
corp.addFunds(funding);
|
||||
corp.numShares -= investShares;
|
||||
props.rerender();
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
An investment firm has offered you {numeralWrapper.formatMoney(funding)} in funding in exchange for a{" "}
|
||||
{numeralWrapper.format(percShares * 100, "0.000a")}% stake in the company (
|
||||
{numeralWrapper.format(investShares, "0.000a")} shares).
|
||||
@ -59,10 +61,8 @@ export function FindInvestorsPopup(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
Hint: Investment firms will offer more money if your corporation is turning a profit
|
||||
</p>
|
||||
<button onClick={findInvestors} className="std-button">
|
||||
Accept
|
||||
</button>
|
||||
</>
|
||||
</Typography>
|
||||
<Button onClick={findInvestors}>Accept</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
81
src/Corporation/ui/GoPublicModal.tsx
Normal file
81
src/Corporation/ui/GoPublicModal.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
export function GoPublicModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState("");
|
||||
const initialSharePrice = corp.determineValuation() / corp.totalShares;
|
||||
|
||||
function goPublic(): void {
|
||||
const numShares = parseFloat(shares);
|
||||
const initialSharePrice = corp.determineValuation() / corp.totalShares;
|
||||
if (isNaN(numShares)) {
|
||||
dialogBoxCreate("Invalid value for number of issued shares");
|
||||
return;
|
||||
}
|
||||
if (numShares > corp.numShares) {
|
||||
dialogBoxCreate("Error: You don't have that many shares to issue!");
|
||||
return;
|
||||
}
|
||||
corp.public = true;
|
||||
corp.sharePrice = initialSharePrice;
|
||||
corp.issuedShares = numShares;
|
||||
corp.numShares -= numShares;
|
||||
corp.addFunds(numShares * initialSharePrice);
|
||||
props.rerender();
|
||||
dialogBoxCreate(
|
||||
`You took your ${corp.name} public and earned ` +
|
||||
`${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`,
|
||||
);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) goPublic();
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setShares(event.target.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will
|
||||
no longer own them. Your Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)} per share (the
|
||||
IPO money will be deposited directly into your Corporation's funds).
|
||||
<br />
|
||||
<br />
|
||||
You have a total of {numeralWrapper.format(corp.numShares, "0.000a")} of shares that you can issue.
|
||||
</Typography>
|
||||
<Box display="flex" alignItems="center">
|
||||
<TextField
|
||||
variant="standard"
|
||||
value={shares}
|
||||
onChange={onChange}
|
||||
autoFocus
|
||||
type="number"
|
||||
placeholder="Shares to issue"
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<Button sx={{ mx: 1 }} onClick={goPublic}>
|
||||
Go Public
|
||||
</Button>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
export function GoPublicPopup(props: IProps): React.ReactElement {
|
||||
const [shares, setShares] = useState("");
|
||||
const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares;
|
||||
|
||||
function goPublic(): void {
|
||||
const numShares = parseFloat(shares);
|
||||
const initialSharePrice = props.corp.determineValuation() / props.corp.totalShares;
|
||||
if (isNaN(numShares)) {
|
||||
dialogBoxCreate("Invalid value for number of issued shares");
|
||||
return;
|
||||
}
|
||||
if (numShares > props.corp.numShares) {
|
||||
dialogBoxCreate("Error: You don't have that many shares to issue!");
|
||||
return;
|
||||
}
|
||||
props.corp.public = true;
|
||||
props.corp.sharePrice = initialSharePrice;
|
||||
props.corp.issuedShares = numShares;
|
||||
props.corp.numShares -= numShares;
|
||||
props.corp.addFunds(numShares * initialSharePrice);
|
||||
props.rerender();
|
||||
dialogBoxCreate(
|
||||
`You took your ${props.corp.name} public and earned ` +
|
||||
`${numeralWrapper.formatMoney(numShares * initialSharePrice)} in your IPO`,
|
||||
);
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (event.keyCode === 13) goPublic();
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setShares(event.target.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Enter the number of shares you would like to issue for your IPO. These shares will be publicly sold and you will
|
||||
no longer own them. Your Corporation will receive {numeralWrapper.formatMoney(initialSharePrice)} per share (the
|
||||
IPO money will be deposited directly into your Corporation's funds).
|
||||
<br />
|
||||
<br />
|
||||
You have a total of {numeralWrapper.format(props.corp.numShares, "0.000a")} of shares that you can issue.
|
||||
</p>
|
||||
<input
|
||||
className="text-input"
|
||||
value={shares}
|
||||
onChange={onChange}
|
||||
autoFocus={true}
|
||||
type="number"
|
||||
placeholder="Shares to issue"
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button className="std-button" onClick={goPublic}>
|
||||
Go Public
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,29 +1,34 @@
|
||||
import React, { useState } from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IssueDividends } from "../Actions";
|
||||
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
interface IProps {
|
||||
popupId: string;
|
||||
corp: ICorporation;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player issue & manage dividends
|
||||
// This is created when the player clicks the "Issue Dividends" button in the overview panel
|
||||
export function IssueDividendsPopup(props: IProps): React.ReactElement {
|
||||
const [percent, setPercent] = useState<number | null>(null);
|
||||
export function IssueDividendsModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [percent, setPercent] = useState(0);
|
||||
|
||||
const canIssue = !isNaN(percent) && percent >= 0 && percent <= CorporationConstants.DividendMaxPercentage * 100;
|
||||
function issueDividends(): void {
|
||||
if (!canIssue) return;
|
||||
if (percent === null) return;
|
||||
try {
|
||||
IssueDividends(props.corp, percent / 100);
|
||||
IssueDividends(corp, percent / 100);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
@ -31,13 +36,17 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
if (event.target.value === "") setPercent(null);
|
||||
else setPercent(parseFloat(event.target.value));
|
||||
if (event.target.value === "") setPercent(0);
|
||||
else {
|
||||
let p = parseFloat(event.target.value);
|
||||
if (p > 50) p = 50;
|
||||
setPercent(p);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Dividends are a distribution of a portion of the corporation's profits to the shareholders. This includes
|
||||
yourself, as well.
|
||||
<br />
|
||||
@ -58,19 +67,19 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement {
|
||||
That means your corporation will gain $60m / sec in funds and the remaining $40m / sec will be paid as
|
||||
dividends. Since your corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share
|
||||
per second before taxes.
|
||||
</p>
|
||||
<input
|
||||
autoFocus={true}
|
||||
</Typography>
|
||||
<TextField
|
||||
variant="standard"
|
||||
autoFocus
|
||||
value={percent}
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
className="text-input"
|
||||
placeholder="Dividend %"
|
||||
type="number"
|
||||
style={{ margin: "5px" }}
|
||||
/>
|
||||
<button onClick={issueDividends} className="std-button" style={{ display: "inline-block" }}>
|
||||
<Button disabled={!canIssue} sx={{ mx: 1 }} onClick={issueDividends}>
|
||||
Allocate Dividend Percentage
|
||||
</button>
|
||||
</>
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,24 +1,27 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IEffectTextProps {
|
||||
corp: ICorporation;
|
||||
shares: number | null;
|
||||
}
|
||||
|
||||
function EffectText(props: IEffectTextProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
if (props.shares === null) return <></>;
|
||||
const newSharePrice = Math.round(props.corp.sharePrice * 0.9);
|
||||
const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2);
|
||||
const newSharePrice = Math.round(corp.sharePrice * 0.9);
|
||||
const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2);
|
||||
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
||||
let newShares = props.shares;
|
||||
if (isNaN(newShares)) {
|
||||
return <p>Invalid input</p>;
|
||||
return <Typography>Invalid input</Typography>;
|
||||
}
|
||||
|
||||
// Round to nearest ten-millionth
|
||||
@ -26,36 +29,37 @@ function EffectText(props: IEffectTextProps): React.ReactElement {
|
||||
newShares = Math.round(newShares) * 10e6;
|
||||
|
||||
if (newShares < 10e6) {
|
||||
return <p>Must issue at least 10 million new shares</p>;
|
||||
return <Typography>Must issue at least 10 million new shares</Typography>;
|
||||
}
|
||||
|
||||
if (newShares > maxNewShares) {
|
||||
return <p>You cannot issue that many shares</p>;
|
||||
return <Typography>You cannot issue that many shares</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<p>
|
||||
<Typography>
|
||||
Issue ${numeralWrapper.format(newShares, "0.000a")} new shares for{" "}
|
||||
{numeralWrapper.formatMoney(newShares * newSharePrice)}?
|
||||
</p>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player issue new shares
|
||||
// This is created when the player clicks the "Issue New Shares" buttons in the overview panel
|
||||
export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||
export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number | null>(null);
|
||||
const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2);
|
||||
const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2);
|
||||
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
||||
|
||||
function issueNewShares(): void {
|
||||
if (shares === null) return;
|
||||
const newSharePrice = Math.round(props.corp.sharePrice * 0.9);
|
||||
const newSharePrice = Math.round(corp.sharePrice * 0.9);
|
||||
let newShares = shares;
|
||||
if (isNaN(newShares)) {
|
||||
dialogBoxCreate("Invalid input for number of new shares");
|
||||
@ -71,8 +75,8 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
const profit = newShares * newSharePrice;
|
||||
props.corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
|
||||
props.corp.totalShares += newShares;
|
||||
corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
|
||||
corp.totalShares += newShares;
|
||||
|
||||
// Determine how many are bought by private investors
|
||||
// Private investors get up to 50% at most
|
||||
@ -80,16 +84,15 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||
let privateShares = getRandomInt(0, Math.round(newShares / 2));
|
||||
privateShares = Math.round(privateShares / 1e6) * 1e6;
|
||||
|
||||
props.corp.issuedShares += newShares - privateShares;
|
||||
props.corp.funds = props.corp.funds.plus(profit);
|
||||
props.corp.immediatelyUpdateSharePrice();
|
||||
|
||||
removePopup(props.popupId);
|
||||
corp.issuedShares += newShares - privateShares;
|
||||
corp.funds = corp.funds.plus(profit);
|
||||
corp.immediatelyUpdateSharePrice();
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Issued ${numeralWrapper.format(newShares, "0.000a")} and raised ` +
|
||||
`${numeralWrapper.formatMoney(profit)}. ${numeralWrapper.format(privateShares, "0.000a")} ` +
|
||||
`of these shares were bought by private investors.<br><br>` +
|
||||
`Stock price decreased to ${numeralWrapper.formatMoney(props.corp.sharePrice)}`,
|
||||
`Stock price decreased to ${numeralWrapper.formatMoney(corp.sharePrice)}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -103,8 +106,8 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
You can issue new equity shares (i.e. stocks) in order to raise capital for your corporation.
|
||||
<br />
|
||||
<br />
|
||||
@ -122,19 +125,12 @@ export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||
When you choose to issue new equity, private shareholders have first priority for up to 50% of the new shares.
|
||||
If they choose to exercise this option, these newly issued shares become private, restricted shares, which means
|
||||
you cannot buy them back.
|
||||
</p>
|
||||
<EffectText corp={props.corp} shares={shares} />
|
||||
<input
|
||||
className="text-input"
|
||||
autoFocus={true}
|
||||
placeholder="# New Shares"
|
||||
style={{ margin: "5px" }}
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button onClick={issueNewShares} className="std-button" style={{ display: "inline-block" }}>
|
||||
</Typography>
|
||||
<EffectText shares={shares} />
|
||||
<TextField variant="standard" autoFocus placeholder="# New Shares" onChange={onChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={issueNewShares} sx={{ mx: 1 }}>
|
||||
Issue New Shares
|
||||
</button>
|
||||
</>
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -2,22 +2,22 @@
|
||||
import React from "react";
|
||||
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { CorporationUpgrade } from "../data/CorporationUpgrades";
|
||||
import { LevelUpgrade } from "../Actions";
|
||||
import { MoneyCost } from "./MoneyCost";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
|
||||
interface IProps {
|
||||
upgrade: CorporationUpgrade;
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
export function LevelableUpgrade(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const data = props.upgrade;
|
||||
const level = props.corp.upgrades[data[0]];
|
||||
const level = corp.upgrades[data[0]];
|
||||
|
||||
const baseCost = data[1];
|
||||
const priceMult = data[2];
|
||||
@ -25,14 +25,14 @@ export function LevelableUpgrade(props: IProps): React.ReactElement {
|
||||
|
||||
const text = (
|
||||
<>
|
||||
{data[4]} - <MoneyCost money={cost} corp={props.corp} />
|
||||
{data[4]} - <MoneyCost money={cost} corp={corp} />
|
||||
</>
|
||||
);
|
||||
const tooltip = data[5];
|
||||
function onClick(): void {
|
||||
if (props.corp.funds.lt(cost)) return;
|
||||
if (corp.funds.lt(cost)) return;
|
||||
try {
|
||||
LevelUpgrade(props.corp, props.upgrade);
|
||||
LevelUpgrade(corp, props.upgrade);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
@ -5,42 +5,28 @@ import React from "react";
|
||||
|
||||
import { CityTabs } from "./CityTabs";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { Overview } from "./Overview";
|
||||
import { useCorporation } from "./Context";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
divisionName: string;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
export function MainPanel(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const division =
|
||||
props.divisionName !== "Overview"
|
||||
? props.corp.divisions.find((division: IIndustry) => division.name === props.divisionName)
|
||||
? corp.divisions.find((division: IIndustry) => division.name === props.divisionName)
|
||||
: undefined; // use undefined because find returns undefined
|
||||
|
||||
if (division === undefined) {
|
||||
return (
|
||||
<div id="cmpy-mgmt-panel">
|
||||
<Overview {...props} />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div id="cmpy-mgmt-panel">
|
||||
<CityTabs
|
||||
rerender={props.rerender}
|
||||
division={division}
|
||||
corp={props.corp}
|
||||
city={CityName.Sector12}
|
||||
player={props.player}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (division === undefined) throw new Error("Cannot find division");
|
||||
return (
|
||||
<div id="cmpy-mgmt-panel">
|
||||
<CityTabs rerender={props.rerender} division={division} corp={corp} city={CityName.Sector12} player={player} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
// React Component for displaying Corporation Overview info
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { LevelableUpgrade } from "./LevelableUpgrade";
|
||||
import { UnlockUpgrade } from "./UnlockUpgrade";
|
||||
import { BribeFactionPopup } from "./BribeFactionPopup";
|
||||
import { SellSharesPopup } from "./SellSharesPopup";
|
||||
import { BuybackSharesPopup } from "./BuybackSharesPopup";
|
||||
import { IssueDividendsPopup } from "./IssueDividendsPopup";
|
||||
import { IssueNewSharesPopup } from "./IssueNewSharesPopup";
|
||||
import { FindInvestorsPopup } from "./FindInvestorsPopup";
|
||||
import { GoPublicPopup } from "./GoPublicPopup";
|
||||
import { BribeFactionModal } from "./BribeFactionModal";
|
||||
import { SellSharesModal } from "./SellSharesModal";
|
||||
import { BuybackSharesModal } from "./BuybackSharesModal";
|
||||
import { IssueDividendsModal } from "./IssueDividendsModal";
|
||||
import { IssueNewSharesModal } from "./IssueNewSharesModal";
|
||||
import { FindInvestorsModal } from "./FindInvestorsModal";
|
||||
import { GoPublicModal } from "./GoPublicModal";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
|
||||
@ -17,44 +18,52 @@ import { CorporationUpgrade, CorporationUpgrades } from "../data/CorporationUpgr
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
export function Overview({ corp, player, rerender }: IProps): React.ReactElement {
|
||||
export function Overview({ rerender }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const profit: number = corp.revenue.minus(corp.expenses).toNumber();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
<Typography>
|
||||
Total Funds: <Money money={corp.funds.toNumber()} />
|
||||
<br />
|
||||
Total Revenue: <Money money={corp.revenue.toNumber()} /> / s<br />
|
||||
Total Expenses: <Money money={corp.expenses.toNumber()} /> / s
|
||||
<br />
|
||||
Total Profits: <Money money={profit} /> / s<br />
|
||||
<DividendsStats corp={corp} profit={profit} />
|
||||
<DividendsStats profit={profit} />
|
||||
Publicly Traded: {corp.public ? "Yes" : "No"}
|
||||
<br />
|
||||
Owned Stock Shares: {numeralWrapper.format(corp.numShares, "0.000a")}
|
||||
<br />
|
||||
Stock Price: {corp.public ? <Money money={corp.sharePrice} /> : "N/A"}
|
||||
<br />
|
||||
</p>
|
||||
<p className="tooltip">
|
||||
Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")}
|
||||
<span className="tooltiptext">
|
||||
Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")}
|
||||
<br />
|
||||
Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")}
|
||||
</span>
|
||||
</p>
|
||||
</Typography>
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={
|
||||
<Typography>
|
||||
Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")}
|
||||
<br />
|
||||
Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography className="tooltip">
|
||||
Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<br />
|
||||
<br />
|
||||
<Mult name="Production Multiplier: " mult={corp.getProductionMultiplier()} />
|
||||
@ -67,100 +76,78 @@ export function Overview({ corp, player, rerender }: IProps): React.ReactElement
|
||||
<Mult name="Sales Multiplier: " mult={corp.getSalesMultiplier()} />
|
||||
<Mult name="Scientific Research Multiplier: " mult={corp.getScientificResearchMultiplier()} />
|
||||
<br />
|
||||
<BonusTime corp={corp} />
|
||||
<BonusTime />
|
||||
<div>
|
||||
<Button
|
||||
className="a-link-button"
|
||||
display="inline-block"
|
||||
onClick={() => corp.getStarterGuide(player)}
|
||||
text="Getting Started Guide"
|
||||
tooltip={
|
||||
"Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " +
|
||||
"This is a .lit file that guides you through the beginning of setting up a Corporation and " +
|
||||
"provides some tips/pointers for helping you get started with managing it."
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={
|
||||
<Typography>
|
||||
Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' This is a .lit file
|
||||
that guides you through the beginning of setting up a Corporation and provides some tips/pointers for
|
||||
helping you get started with managing it.
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
{corp.public ? (
|
||||
<PublicButtons corp={corp} player={player} rerender={rerender} />
|
||||
) : (
|
||||
<PrivateButtons corp={corp} player={player} rerender={rerender} />
|
||||
)}
|
||||
<BribeButton corp={corp} player={player} />
|
||||
>
|
||||
<Button onClick={() => corp.getStarterGuide(player)}>Getting Started Guide</Button>
|
||||
</Tooltip>
|
||||
{corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />}
|
||||
<BribeButton />
|
||||
</div>
|
||||
<br />
|
||||
<Upgrades corp={corp} player={player} rerender={rerender} />
|
||||
<Upgrades rerender={rerender} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface IPrivateButtonsProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
// Render the buttons for when your Corporation is still private
|
||||
function PrivateButtons({ corp, player, rerender }: IPrivateButtonsProps): React.ReactElement {
|
||||
function openFindInvestorsPopup(): void {
|
||||
const popupId = "cmpy-mgmt-find-investors-popup";
|
||||
createPopup(popupId, FindInvestorsPopup, {
|
||||
rerender,
|
||||
player,
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
}
|
||||
|
||||
function openGoPublicPopup(): void {
|
||||
const popupId = "cmpy-mgmt-go-public-popup";
|
||||
createPopup(popupId, GoPublicPopup, {
|
||||
rerender,
|
||||
player,
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
}
|
||||
function PrivateButtons({ rerender }: IPrivateButtonsProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [findInvestorsopen, setFindInvestorsopen] = useState(false);
|
||||
const [goPublicopen, setGoPublicopen] = useState(false);
|
||||
|
||||
const fundingAvailable = corp.fundingRound < 4;
|
||||
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
|
||||
const findInvestorsTooltip = fundingAvailable
|
||||
? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company"
|
||||
: undefined;
|
||||
? "Search for private investors who will give you startup funding in exchange for equity (stock shares) in your company"
|
||||
: "";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className={findInvestorsClassName}
|
||||
onClick={openFindInvestorsPopup}
|
||||
text="Find Investors"
|
||||
tooltip={findInvestorsTooltip}
|
||||
display="inline-block"
|
||||
/>
|
||||
<Button
|
||||
className="std-button"
|
||||
onClick={openGoPublicPopup}
|
||||
display="inline-block"
|
||||
text="Go Public"
|
||||
tooltip={
|
||||
"Become a publicly traded and owned entity. Going public " +
|
||||
"involves issuing shares for an IPO. Once you are a public " +
|
||||
"company, your shares will be traded on the stock market."
|
||||
<Tooltip disableInteractive title={<Typography>{findInvestorsTooltip}</Typography>}>
|
||||
<Button disabled={!fundingAvailable} onClick={() => setFindInvestorsopen(true)}>
|
||||
Find Investors
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={
|
||||
<Typography>
|
||||
Become a publicly traded and owned entity. Going public involves issuing shares for an IPO. Once you are a
|
||||
public company, your shares will be traded on the stock market.
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
>
|
||||
<Button onClick={() => setGoPublicopen(true)}>Go Public</Button>
|
||||
</Tooltip>
|
||||
<FindInvestorsModal open={findInvestorsopen} onClose={() => setFindInvestorsopen(false)} rerender={rerender} />
|
||||
<GoPublicModal open={goPublicopen} onClose={() => setGoPublicopen(false)} rerender={rerender} />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IUpgradeProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
// Render the UI for Corporation upgrades
|
||||
function Upgrades({ corp, player, rerender }: IUpgradeProps): React.ReactElement {
|
||||
function Upgrades({ rerender }: IUpgradeProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
// Don't show upgrades
|
||||
if (corp.divisions.length <= 0) {
|
||||
return <h1>Upgrades are unlocked once you create an industry.</h1>;
|
||||
return <Typography variant="h4">Upgrades are unlocked once you create an industry.</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -169,29 +156,32 @@ function Upgrades({ corp, player, rerender }: IUpgradeProps): React.ReactElement
|
||||
{Object.values(CorporationUnlockUpgrades)
|
||||
.filter((upgrade: CorporationUnlockUpgrade) => corp.unlockUpgrades[upgrade[0]] === 0)
|
||||
.map((upgrade: CorporationUnlockUpgrade) => (
|
||||
<UnlockUpgrade rerender={rerender} player={player} corp={corp} upgradeData={upgrade} key={upgrade[0]} />
|
||||
<UnlockUpgrade rerender={rerender} upgradeData={upgrade} key={upgrade[0]} />
|
||||
))}
|
||||
|
||||
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
|
||||
{corp.upgrades
|
||||
.map((level: number, i: number) => CorporationUpgrades[i])
|
||||
.map((upgrade: CorporationUpgrade) => (
|
||||
<LevelableUpgrade rerender={rerender} player={player} corp={corp} upgrade={upgrade} key={upgrade[0]} />
|
||||
<LevelableUpgrade rerender={rerender} upgrade={upgrade} key={upgrade[0]} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface IPublicButtonsProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Render the buttons for when your Corporation has gone public
|
||||
function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [sellSharesOpen, setSellSharesOpen] = useState(false);
|
||||
const [buybackSharesOpen, setBuybackSharesOpen] = useState(false);
|
||||
const [issueNewSharesOpen, setIssueNewSharesOpen] = useState(false);
|
||||
const [issueDividendsOpen, setIssueDividendsOpen] = useState(false);
|
||||
|
||||
const sellSharesOnCd = corp.shareSaleCooldown > 0;
|
||||
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
|
||||
const sellSharesTooltip = sellSharesOnCd
|
||||
? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown)
|
||||
: "Sell your shares in the company. The money earned from selling your " +
|
||||
@ -199,139 +189,83 @@ function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.R
|
||||
"This is one of the only ways to profit from your business venture.";
|
||||
|
||||
const issueNewSharesOnCd = corp.issueNewSharesCooldown > 0;
|
||||
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
|
||||
const issueNewSharesTooltip = issueNewSharesOnCd
|
||||
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
|
||||
: "Issue new equity shares to raise capital.";
|
||||
|
||||
function openSellSharesPopup(): void {
|
||||
const popupId = "cmpy-mgmt-sell-shares-popup";
|
||||
createPopup(popupId, SellSharesPopup, {
|
||||
corp: corp,
|
||||
player,
|
||||
popupId,
|
||||
rerender,
|
||||
});
|
||||
}
|
||||
|
||||
function openBuybackSharesPopup(): void {
|
||||
const popupId = "corp-buyback-shares-popup";
|
||||
createPopup(popupId, BuybackSharesPopup, {
|
||||
rerender,
|
||||
player,
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
}
|
||||
|
||||
function openIssueNewSharesPopup(): void {
|
||||
const popupId = "cmpy-mgmt-issue-new-shares-popup";
|
||||
createPopup(popupId, IssueNewSharesPopup, {
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
}
|
||||
|
||||
function openIssueDividendsPopup(): void {
|
||||
const popupId = "cmpy-mgmt-issue-dividends-popup";
|
||||
createPopup(popupId, IssueDividendsPopup, {
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className={sellSharesClass}
|
||||
display="inline-block"
|
||||
onClick={openSellSharesPopup}
|
||||
text="Sell Shares"
|
||||
tooltip={sellSharesTooltip}
|
||||
/>
|
||||
<Button
|
||||
className="std-button"
|
||||
display="inline-block"
|
||||
onClick={openBuybackSharesPopup}
|
||||
text="Buyback shares"
|
||||
tooltip="Buy back shares you that previously issued or sold at market price."
|
||||
/>
|
||||
<Tooltip disableInteractive title={<Typography>{sellSharesTooltip}</Typography>}>
|
||||
<Button disabled={sellSharesOnCd} onClick={() => setSellSharesOpen(true)}>
|
||||
Sell Shares
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<SellSharesModal open={sellSharesOpen} onClose={() => setSellSharesOpen(false)} rerender={rerender} />
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={<Typography>Buy back shares you that previously issued or sold at market price.</Typography>}
|
||||
>
|
||||
<Button onClick={() => setBuybackSharesOpen(true)}>Buyback shares</Button>
|
||||
</Tooltip>
|
||||
<BuybackSharesModal open={buybackSharesOpen} onClose={() => setBuybackSharesOpen(false)} rerender={rerender} />
|
||||
<br />
|
||||
<Button
|
||||
className={issueNewSharesClass}
|
||||
display="inline-block"
|
||||
onClick={openIssueNewSharesPopup}
|
||||
text="Issue New Shares"
|
||||
tooltip={issueNewSharesTooltip}
|
||||
/>
|
||||
<Button
|
||||
className="std-button"
|
||||
display="inline-block"
|
||||
onClick={openIssueDividendsPopup}
|
||||
text="Issue Dividends"
|
||||
tooltip="Manage the dividends that are paid out to shareholders (including yourself)"
|
||||
/>
|
||||
<Tooltip disableInteractive title={<Typography>{issueNewSharesTooltip}</Typography>}>
|
||||
<Button disabled={issueNewSharesOnCd} onClick={() => setIssueNewSharesOpen(true)}>
|
||||
Issue New Shares
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<IssueNewSharesModal open={issueNewSharesOpen} onClose={() => setIssueNewSharesOpen(false)} />
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={<Typography>Manage the dividends that are paid out to shareholders (including yourself)</Typography>}
|
||||
>
|
||||
<Button onClick={() => setIssueDividendsOpen(true)}>Issue Dividends</Button>
|
||||
</Tooltip>
|
||||
<IssueDividendsModal open={issueDividendsOpen} onClose={() => setIssueDividendsOpen(false)} />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Generic Function for Creating a button
|
||||
interface ICreateButtonProps {
|
||||
text: string;
|
||||
className?: string;
|
||||
display?: string;
|
||||
tooltip?: string;
|
||||
onClick?: (event: React.MouseEvent) => void;
|
||||
}
|
||||
function BribeButton(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const canBribe =
|
||||
corp.determineValuation() >= CorporationConstants.BribeThreshold &&
|
||||
player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0;
|
||||
|
||||
function Button({ className = "std-button", text, display, tooltip, onClick }: ICreateButtonProps): React.ReactElement {
|
||||
const hasTooltip = tooltip != null;
|
||||
if (hasTooltip) className += " tooltip";
|
||||
return (
|
||||
<button className={className} onClick={onClick} style={{ display: display ? display : "block" }}>
|
||||
{text}
|
||||
{hasTooltip && <span className={"tooltiptext"}>{tooltip}</span>}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
interface IBribeButtonProps {
|
||||
player: IPlayer;
|
||||
corp: ICorporation;
|
||||
}
|
||||
function BribeButton({ player, corp }: IBribeButtonProps): React.ReactElement {
|
||||
function openBribeFactionPopup(): void {
|
||||
const popupId = "corp-bribe-popup";
|
||||
createPopup(popupId, BribeFactionPopup, {
|
||||
player,
|
||||
popupId,
|
||||
corp: corp,
|
||||
});
|
||||
function openBribe(): void {
|
||||
if (!canBribe) return;
|
||||
setOpen(true);
|
||||
}
|
||||
|
||||
const canBribe = corp.determineValuation() >= CorporationConstants.BribeThreshold || true;
|
||||
const bribeFactionsClass = canBribe ? "a-link-button" : "a-link-button-inactive";
|
||||
return (
|
||||
<Button
|
||||
className={bribeFactionsClass}
|
||||
display="inline-block"
|
||||
onClick={openBribeFactionPopup}
|
||||
text="Bribe Factions"
|
||||
tooltip={
|
||||
canBribe
|
||||
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
|
||||
: "Your Corporation is not powerful enough to bribe Faction leaders"
|
||||
}
|
||||
/>
|
||||
<>
|
||||
<Tooltip
|
||||
disableInteractive
|
||||
title={
|
||||
canBribe
|
||||
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
|
||||
: "Your Corporation is not powerful enough to bribe Faction leaders"
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<Button disabled={!canBribe} onClick={openBribe}>
|
||||
Bribe Factions
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<BribeFactionModal open={open} onClose={() => setOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IDividendsStatsProps {
|
||||
corp: ICorporation;
|
||||
profit: number;
|
||||
}
|
||||
function DividendsStats({ corp, profit }: IDividendsStatsProps): React.ReactElement {
|
||||
function DividendsStats({ profit }: IDividendsStatsProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
if (corp.dividendPercentage <= 0 || profit <= 0) return <></>;
|
||||
const totalDividends = (corp.dividendPercentage / 100) * profit;
|
||||
const retainedEarnings = profit - totalDividends;
|
||||
@ -361,26 +295,24 @@ interface IMultProps {
|
||||
function Mult({ name, mult }: IMultProps): React.ReactElement {
|
||||
if (mult <= 1) return <></>;
|
||||
return (
|
||||
<p>
|
||||
<Typography>
|
||||
{name}
|
||||
{numeralWrapper.format(mult, "0.000")}
|
||||
<br />
|
||||
</p>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
interface IBonusTimeProps {
|
||||
corp: ICorporation;
|
||||
}
|
||||
// Returns a string with general information about Corporation
|
||||
function BonusTime({ corp }: IBonusTimeProps): React.ReactElement {
|
||||
function BonusTime(): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const storedTime = corp.storedCycles * CONSTANTS.MilliPerCycle;
|
||||
if (storedTime <= 15000) return <></>;
|
||||
return (
|
||||
<p>
|
||||
<Typography>
|
||||
Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}
|
||||
<br />
|
||||
<br />
|
||||
</p>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
@ -1,21 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
popupId: string;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player sell Corporation shares
|
||||
// This is created when the player clicks the "Sell Shares" button in the overview panel
|
||||
export function SellSharesPopup(props: IProps): React.ReactElement {
|
||||
export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number | null>(null);
|
||||
|
||||
function changeShares(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
@ -27,10 +32,10 @@ export function SellSharesPopup(props: IProps): React.ReactElement {
|
||||
if (props.shares === null) return <></>;
|
||||
if (isNaN(props.shares) || props.shares <= 0) {
|
||||
return <>ERROR: Invalid value entered for number of shares to sell</>;
|
||||
} else if (props.shares > props.corp.numShares) {
|
||||
} else if (props.shares > corp.numShares) {
|
||||
return <>You don't have this many shares to sell!</>;
|
||||
} else {
|
||||
const stockSaleResults = props.corp.calculateShareSale(props.shares);
|
||||
const stockSaleResults = corp.calculateShareSale(props.shares);
|
||||
const profit = stockSaleResults[0];
|
||||
return (
|
||||
<>
|
||||
@ -44,35 +49,35 @@ export function SellSharesPopup(props: IProps): React.ReactElement {
|
||||
if (shares === null) return;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
||||
} else if (shares > props.corp.numShares) {
|
||||
} else if (shares > corp.numShares) {
|
||||
dialogBoxCreate("ERROR: You don't have this many shares to sell");
|
||||
} else {
|
||||
const stockSaleResults = props.corp.calculateShareSale(shares);
|
||||
const stockSaleResults = corp.calculateShareSale(shares);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
|
||||
props.corp.numShares -= shares;
|
||||
if (isNaN(props.corp.issuedShares)) {
|
||||
console.error(`Corporation issuedShares is NaN: ${props.corp.issuedShares}`);
|
||||
const res = props.corp.issuedShares;
|
||||
corp.numShares -= shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`);
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
props.corp.issuedShares = 0;
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
props.corp.issuedShares = res;
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
}
|
||||
props.corp.issuedShares += shares;
|
||||
props.corp.sharePrice = newSharePrice;
|
||||
props.corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
props.corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
props.player.gainMoney(profit);
|
||||
props.player.recordMoneySource(profit, "corporation");
|
||||
removePopup(props.popupId);
|
||||
corp.issuedShares += shares;
|
||||
corp.sharePrice = newSharePrice;
|
||||
corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit);
|
||||
player.recordMoneySource(profit, "corporation");
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Sold ${numeralWrapper.formatMoney(shares)} shares for ` +
|
||||
`${numeralWrapper.formatMoney(profit)}. ` +
|
||||
`The corporation's stock price fell to ${numeralWrapper.formatMoney(props.corp.sharePrice)} ` +
|
||||
`The corporation's stock price fell to ${numeralWrapper.formatMoney(corp.sharePrice)} ` +
|
||||
`as a result of dilution.`,
|
||||
);
|
||||
|
||||
@ -85,8 +90,8 @@ export function SellSharesPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the number of shares you would like to sell. The money from selling your shares will go directly to you
|
||||
(NOT your Corporation).
|
||||
<br />
|
||||
@ -95,22 +100,21 @@ export function SellSharesPopup(props: IProps): React.ReactElement {
|
||||
large number of shares all at once will have an immediate effect in reducing your stock price.
|
||||
<br />
|
||||
<br />
|
||||
The current price of your company's stock is {numeralWrapper.formatMoney(props.corp.sharePrice)}
|
||||
</p>
|
||||
<ProfitIndicator shares={shares} corp={props.corp} />
|
||||
The current price of your company's stock is {numeralWrapper.formatMoney(corp.sharePrice)}
|
||||
</Typography>
|
||||
<ProfitIndicator shares={shares} corp={corp} />
|
||||
<br />
|
||||
<input
|
||||
autoFocus={true}
|
||||
className="text-input"
|
||||
<TextField
|
||||
variant="standard"
|
||||
autoFocus
|
||||
type="number"
|
||||
placeholder="Shares to sell"
|
||||
style={{ margin: "5px" }}
|
||||
onChange={changeShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button onClick={sell} className="a-link-button" style={{ display: "inline-block" }}>
|
||||
<Button onClick={sell} sx={{ mx: 1 }}>
|
||||
Sell shares
|
||||
</button>
|
||||
</>
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -3,30 +3,28 @@ import React from "react";
|
||||
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { CorporationUnlockUpgrade } from "../data/CorporationUnlockUpgrades";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { useCorporation } from "./Context";
|
||||
import { UnlockUpgrade as UU } from "../Actions";
|
||||
import { MoneyCost } from "./MoneyCost";
|
||||
|
||||
interface IProps {
|
||||
upgradeData: CorporationUnlockUpgrade;
|
||||
corp: ICorporation;
|
||||
player: IPlayer;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
export function UnlockUpgrade(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const data = props.upgradeData;
|
||||
const text = (
|
||||
<>
|
||||
{data[2]} - <MoneyCost money={data[1]} corp={props.corp} />
|
||||
{data[2]} - <MoneyCost money={data[1]} corp={corp} />
|
||||
</>
|
||||
);
|
||||
const tooltip = data[3];
|
||||
function onClick(): void {
|
||||
if (props.corp.funds.lt(data[1])) return;
|
||||
if (corp.funds.lt(data[1])) return;
|
||||
try {
|
||||
UU(props.corp, props.upgradeData);
|
||||
UU(corp, props.upgradeData);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
@ -15,8 +15,7 @@ import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { CreateCorporationPopup } from "../../Corporation/ui/CreateCorporationPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
@ -32,17 +31,6 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
const inBladeburner = player.inBladeburner();
|
||||
/**
|
||||
* Click handler for "Create Corporation" button at Sector-12 City Hall
|
||||
*/
|
||||
function createCorporationPopup(): void {
|
||||
const popupId = `create-start-corporation-popup`;
|
||||
createPopup(popupId, CreateCorporationPopup, {
|
||||
player: player,
|
||||
popupId: popupId,
|
||||
router: router,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for Bladeburner button at Sector-12 NSA
|
||||
@ -93,7 +81,8 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return <Button onClick={EatNoodles}>Eat noodles</Button>;
|
||||
}
|
||||
|
||||
function renderCreateCorporation(): React.ReactElement {
|
||||
function CreateCorporation(): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
if (!player.canAccessCorporation()) {
|
||||
return (
|
||||
<>
|
||||
@ -104,9 +93,12 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Button disabled={!player.canAccessCorporation() || player.hasCorporation()} onClick={createCorporationPopup}>
|
||||
Create a Corporation
|
||||
</Button>
|
||||
<>
|
||||
<Button disabled={!player.canAccessCorporation() || player.hasCorporation()} onClick={() => setOpen(true)}>
|
||||
Create a Corporation
|
||||
</Button>
|
||||
<CreateCorporationModal open={open} onClose={() => setOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -122,7 +114,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return renderResleeving();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return renderCreateCorporation();
|
||||
return <CreateCorporation />;
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return renderBladeburner();
|
||||
|
Loading…
Reference in New Issue
Block a user