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