mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-26 16:07:33 +01:00
finalize corp in mui
This commit is contained in:
parent
86ddc940aa
commit
b0e4a2a775
38
dist/vendor.bundle.js
vendored
38
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -20,12 +20,26 @@ interface IProps {
|
||||
|
||||
export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const factions = player.factions.filter((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return false;
|
||||
if (player.hasGangWith(name)) return false;
|
||||
return true;
|
||||
});
|
||||
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] : "",
|
||||
);
|
||||
const [selectedFaction, setSelectedFaction] = useState(factions.length > 0 ? factions[0] : "");
|
||||
const disabled =
|
||||
money === null ||
|
||||
stock === null ||
|
||||
(money === 0 && stock === 0) ||
|
||||
isNaN(money) ||
|
||||
isNaN(stock) ||
|
||||
money < 0 ||
|
||||
stock < 0 ||
|
||||
corp.funds.lt(money) ||
|
||||
stock > corp.numShares;
|
||||
|
||||
function onMoneyChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setMoney(parseFloat(event.target.value));
|
||||
@ -64,22 +78,15 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
|
||||
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();
|
||||
}
|
||||
if (disabled) return;
|
||||
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 (
|
||||
@ -90,9 +97,10 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
<Box display="flex" alignItems="center">
|
||||
<Typography>Faction:</Typography>
|
||||
<Select value={selectedFaction} onChange={changeFaction}>
|
||||
{player.factions.map((name: string) => {
|
||||
{factions.map((name: string) => {
|
||||
const info = Factions[name].getInfo();
|
||||
if (!info.offersWork()) return;
|
||||
if (player.hasGangWith(name)) return;
|
||||
return (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
@ -104,7 +112,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
|
||||
<Typography>{getRepText(money ? money : 0, stock ? stock : 0)}</Typography>
|
||||
<TextField onChange={onMoneyChange} placeholder="Corporation funds" />
|
||||
<TextField sx={{ mx: 1 }} onChange={onStockChange} placeholder="Stock Shares" />
|
||||
<Button sx={{ mx: 1 }} onClick={() => bribe(money ? money : 0, stock ? stock : 0)}>
|
||||
<Button disabled={disabled} sx={{ mx: 1 }} onClick={() => bribe(money ? money : 0, stock ? stock : 0)}>
|
||||
Bribe
|
||||
</Button>
|
||||
</Modal>
|
||||
|
@ -4,6 +4,9 @@ import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@ -25,38 +28,30 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
const currentStockPrice = corp.sharePrice;
|
||||
const buybackPrice = currentStockPrice * 1.1;
|
||||
const disabled =
|
||||
shares === null ||
|
||||
isNaN(shares) ||
|
||||
shares <= 0 ||
|
||||
shares > corp.issuedShares ||
|
||||
shares * buybackPrice > player.money;
|
||||
|
||||
function buy(): void {
|
||||
if (shares === null) return;
|
||||
const tempStockPrice = corp.sharePrice;
|
||||
const buybackPrice = tempStockPrice * 1.1;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
||||
} else if (shares > corp.issuedShares) {
|
||||
dialogBoxCreate("ERROR: There are not this many oustanding shares to buy back");
|
||||
} else if (shares * buybackPrice > player.money) {
|
||||
dialogBoxCreate(
|
||||
"ERROR: You do not have enough money to purchase this many shares (you need " +
|
||||
numeralWrapper.format(shares * buybackPrice, "$0.000a") +
|
||||
")",
|
||||
);
|
||||
} else {
|
||||
corp.numShares += shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.warn("Corporation issuedShares is NaN: " + corp.issuedShares);
|
||||
console.warn("Converting to number now");
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
corp.numShares += shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.warn("Corporation issuedShares is NaN: " + corp.issuedShares);
|
||||
console.warn("Converting to number now");
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
corp.issuedShares -= shares;
|
||||
player.loseMoney(shares * buybackPrice);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
corp.issuedShares -= shares;
|
||||
player.loseMoney(shares * buybackPrice);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
function CostIndicator(): React.ReactElement {
|
||||
@ -85,7 +80,7 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<p>
|
||||
<Typography>
|
||||
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.
|
||||
<br />
|
||||
@ -95,21 +90,19 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
The current buyback price of your company's stock is {numeralWrapper.formatMoney(buybackPrice)}. Your company
|
||||
currently has {numeralWrapper.formatBigNumber(corp.issuedShares)} outstanding stock shares.
|
||||
</p>
|
||||
</Typography>
|
||||
<CostIndicator />
|
||||
<br />
|
||||
<input
|
||||
<TextField
|
||||
autoFocus={true}
|
||||
className="text-input"
|
||||
type="number"
|
||||
placeholder="Shares to buyback"
|
||||
style={{ margin: "5px" }}
|
||||
onChange={changeShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button onClick={buy} className="a-link-button" style={{ display: "inline-block" }}>
|
||||
<Button disabled={disabled} onClick={buy}>
|
||||
Buy shares
|
||||
</button>
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Industries, IndustryDescriptions } from "../IndustryData";
|
||||
import { IndustryStartingCosts, Industries, IndustryDescriptions } from "../IndustryData";
|
||||
import { useCorporation } from "./Context";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { NewIndustry } from "../Actions";
|
||||
@ -28,7 +28,14 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
|
||||
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
||||
const [name, setName] = useState("");
|
||||
|
||||
const cost = IndustryStartingCosts[industry];
|
||||
if (cost === undefined) {
|
||||
throw new Error(`Invalid industry: '${industry}'`);
|
||||
}
|
||||
const disabled = corp.funds.lt(cost) || name === "";
|
||||
|
||||
function newIndustry(): void {
|
||||
if (disabled) return;
|
||||
try {
|
||||
NewIndustry(corp, industry, name);
|
||||
} catch (err) {
|
||||
@ -74,7 +81,7 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
|
||||
|
||||
<Box display="flex" alignItems="center">
|
||||
<TextField autoFocus={true} value={name} onChange={onNameChange} onKeyDown={onKeyDown} type="text" />
|
||||
<Button sx={{ mx: 1 }} onClick={newIndustry}>
|
||||
<Button disabled={disabled} sx={{ mx: 1 }} onClick={newIndustry}>
|
||||
Create Division
|
||||
</Button>
|
||||
</Box>
|
||||
|
@ -19,6 +19,8 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
|
||||
const possibleCities = Object.keys(division.offices).filter((cityName: string) => division.offices[cityName] === 0);
|
||||
const [city, setCity] = useState(possibleCities[0]);
|
||||
|
||||
const disabled = corp.funds.lt(CorporationConstants.OfficeInitialCost);
|
||||
|
||||
function onCityChange(event: SelectChangeEvent<string>): void {
|
||||
setCity(event.target.value);
|
||||
}
|
||||
@ -48,7 +50,7 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button onClick={expand} disabled={corp.funds.lt(0)}>
|
||||
<Button onClick={expand} disabled={disabled}>
|
||||
Confirm
|
||||
</Button>
|
||||
</>
|
||||
|
@ -1,25 +1,32 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { Material } from "../Material";
|
||||
import { Export } from "../Export";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { ExportMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player manage exports
|
||||
export function ExportPopup(props: IProps): React.ReactElement {
|
||||
if (props.corp.divisions.length === 0) throw new Error("Export popup created with no divisions.");
|
||||
if (Object.keys(props.corp.divisions[0].warehouses).length === 0)
|
||||
export function ExportModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
if (corp.divisions.length === 0) throw new Error("Export popup created with no divisions.");
|
||||
if (Object.keys(corp.divisions[0].warehouses).length === 0)
|
||||
throw new Error("Export popup created in a division with no warehouses.");
|
||||
const [industry, setIndustry] = useState<string>(props.corp.divisions[0].name);
|
||||
const [city, setCity] = useState<string>(Object.keys(props.corp.divisions[0].warehouses)[0]);
|
||||
const [industry, setIndustry] = useState<string>(corp.divisions[0].name);
|
||||
const [city, setCity] = useState<string>(Object.keys(corp.divisions[0].warehouses)[0]);
|
||||
const [amt, setAmt] = useState("");
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
@ -27,11 +34,11 @@ export function ExportPopup(props: IProps): React.ReactElement {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
function onCityChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
function onCityChange(event: SelectChangeEvent<string>): void {
|
||||
setCity(event.target.value);
|
||||
}
|
||||
|
||||
function onIndustryChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
function onIndustryChange(event: SelectChangeEvent<string>): void {
|
||||
setIndustry(event.target.value);
|
||||
}
|
||||
|
||||
@ -45,7 +52,7 @@ export function ExportPopup(props: IProps): React.ReactElement {
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function removeExport(exp: Export): void {
|
||||
@ -58,7 +65,7 @@ export function ExportPopup(props: IProps): React.ReactElement {
|
||||
rerender();
|
||||
}
|
||||
|
||||
const currentDivision = props.corp.divisions.find((division: IIndustry) => division.name === industry);
|
||||
const currentDivision = corp.divisions.find((division: IIndustry) => division.name === industry);
|
||||
if (currentDivision === undefined)
|
||||
throw new Error(`Export popup somehow ended up with undefined division '${currentDivision}'`);
|
||||
const possibleCities = Object.keys(currentDivision.warehouses).filter(
|
||||
@ -69,45 +76,48 @@ export function ExportPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Select the industry and city to export this material to, as well as how much of this material to export per
|
||||
second. You can set the export amount to 'MAX' to export all of the materials in this warehouse.
|
||||
</p>
|
||||
<select className="dropdown" onChange={onIndustryChange} defaultValue={industry}>
|
||||
{props.corp.divisions.map((division: IIndustry) => (
|
||||
<option key={division.name} value={division.name}>
|
||||
</Typography>
|
||||
<Select onChange={onIndustryChange} value={industry}>
|
||||
{corp.divisions.map((division: IIndustry) => (
|
||||
<MenuItem key={division.name} value={division.name}>
|
||||
{division.name}
|
||||
</option>
|
||||
</MenuItem>
|
||||
))}
|
||||
</select>
|
||||
<select className="dropdown" onChange={onCityChange} defaultValue={city}>
|
||||
</Select>
|
||||
<Select onChange={onCityChange} value={city}>
|
||||
{possibleCities.map((cityName: string) => {
|
||||
if (currentDivision.warehouses[cityName] === 0) return;
|
||||
return (
|
||||
<option key={cityName} value={cityName}>
|
||||
<MenuItem key={cityName} value={cityName}>
|
||||
{cityName}
|
||||
</option>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
<input className="text-input" placeholder="Export amount / s" onChange={onAmtChange} />
|
||||
<button className="std-button" style={{ display: "inline-block" }} onClick={exportMaterial}>
|
||||
Export
|
||||
</button>
|
||||
<p>
|
||||
</Select>
|
||||
<TextField placeholder="Export amount / s" onChange={onAmtChange} value={amt} />
|
||||
<Button onClick={exportMaterial}>Export</Button>
|
||||
<Typography>
|
||||
Below is a list of all current exports of this material from this warehouse. Clicking on one of the exports
|
||||
below will REMOVE that export.
|
||||
</p>
|
||||
</Typography>
|
||||
{props.mat.exp.map((exp: Export, index: number) => (
|
||||
<div key={index} className="cmpy-mgmt-existing-export" onClick={() => removeExport(exp)}>
|
||||
Industry: {exp.ind}
|
||||
<br />
|
||||
City: {exp.city}
|
||||
<br />
|
||||
Amount/s: {exp.amt}
|
||||
</div>
|
||||
<Box display="flex" alignItems="center" key={index}>
|
||||
<Button sx={{ mx: 2 }} onClick={() => removeExport(exp)}>
|
||||
delete
|
||||
</Button>
|
||||
<Typography>
|
||||
Industry: {exp.ind}
|
||||
<br />
|
||||
City: {exp.city}
|
||||
<br />
|
||||
Amount/s: {exp.amt}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -136,6 +136,7 @@ function ManualManagement(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Select value={employee !== null ? employee.name : ""} onChange={employeeSelectorOnChange}>
|
||||
{employees}
|
||||
</Select>
|
||||
|
@ -259,10 +259,12 @@ function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.R
|
||||
|
||||
upgrades.push(
|
||||
<Tooltip key={index} title={upgrade[5]}>
|
||||
<Button onClick={onClick}>
|
||||
{upgrade[4]} -
|
||||
<MoneyCost money={cost} corp={corp} />
|
||||
</Button>
|
||||
<span>
|
||||
<Button disabled={corp.funds.lt(cost)} onClick={onClick}>
|
||||
{upgrade[4]} -
|
||||
<MoneyCost money={cost} corp={corp} />
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>,
|
||||
);
|
||||
}
|
||||
|
@ -3,26 +3,19 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { ExportPopup } from "./ExportPopup";
|
||||
import { MaterialMarketTaPopup } from "./MaterialMarketTaPopup";
|
||||
import { SellMaterialPopup } from "./SellMaterialPopup";
|
||||
import { PurchaseMaterialPopup } from "./PurchaseMaterialPopup";
|
||||
import { SmartSupplyModal } from "./SmartSupplyModal";
|
||||
import { ProductElem } from "./ProductElem";
|
||||
import { MaterialElem } from "./MaterialElem";
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
|
||||
import { isString } from "../../utils/helpers/isString";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyCost } from "./MoneyCost";
|
||||
import { isRelevantMaterial } from "./Helpers";
|
||||
import { IndustryProductEquation } from "./IndustryProductEquation";
|
||||
@ -35,190 +28,6 @@ import Paper from "@mui/material/Paper";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
interface IMaterialProps {
|
||||
warehouse: Warehouse;
|
||||
city: string;
|
||||
mat: Material;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Material type
|
||||
function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const division = useDivision();
|
||||
const warehouse = props.warehouse;
|
||||
const city = props.city;
|
||||
const mat = props.mat;
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
const office = division.offices[city];
|
||||
if (!(office instanceof OfficeSpace)) {
|
||||
throw new Error(`Could not get OfficeSpace object for this city (${city})`);
|
||||
}
|
||||
|
||||
// Numeraljs formatter
|
||||
const nf = "0.000";
|
||||
const nfB = "0.000a"; // For numbers that might be biger
|
||||
|
||||
// Total gain or loss of this material (per second)
|
||||
const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
|
||||
|
||||
// Flag that determines whether this industry is "new" and the current material should be
|
||||
// marked with flashing-red lights
|
||||
const tutorial =
|
||||
division.newInd && Object.keys(division.reqMats).includes(mat.name) && mat.buy === 0 && mat.imp === 0;
|
||||
|
||||
// Purchase material button
|
||||
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nfB)})`;
|
||||
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
||||
|
||||
function openPurchaseMaterialPopup(): void {
|
||||
const popupId = "cmpy-mgmt-material-purchase-popup";
|
||||
createPopup(popupId, PurchaseMaterialPopup, {
|
||||
mat: mat,
|
||||
industry: division,
|
||||
warehouse: warehouse,
|
||||
corp: corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
function openExportPopup(): void {
|
||||
const popupId = "cmpy-mgmt-export-popup";
|
||||
createPopup(popupId, ExportPopup, {
|
||||
mat: mat,
|
||||
corp: corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
// Sell material button
|
||||
let sellButtonText: JSX.Element;
|
||||
if (mat.sllman[0]) {
|
||||
if (isString(mat.sllman[1])) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
Sell ({numeralWrapper.format(mat.sll, nfB)}/{mat.sllman[1]})
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
sellButtonText = (
|
||||
<>
|
||||
Sell ({numeralWrapper.format(mat.sll, nfB)}/{numeralWrapper.format(mat.sllman[1] as number, nfB)})
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (mat.marketTa2) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.marketTa2Price} />
|
||||
</>
|
||||
);
|
||||
} else if (mat.marketTa1) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.bCost + markupLimit} />
|
||||
</>
|
||||
);
|
||||
} else if (mat.sCost) {
|
||||
if (isString(mat.sCost)) {
|
||||
const sCost = (mat.sCost as string).replace(/MP/g, mat.bCost + "");
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={eval(sCost)} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.sCost} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sellButtonText = <>Sell (0.000/0.000)</>;
|
||||
}
|
||||
|
||||
function openSellMaterialPopup(): void {
|
||||
const popupId = "cmpy-mgmt-material-sell-popup";
|
||||
createPopup(popupId, SellMaterialPopup, {
|
||||
mat: mat,
|
||||
corp: corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
function openMaterialMarketTaPopup(): void {
|
||||
const popupId = "cmpy-mgmt-export-popup";
|
||||
createPopup(popupId, MaterialMarketTaPopup, {
|
||||
mat: mat,
|
||||
industry: division,
|
||||
corp: corp,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
function shouldFlash(): boolean {
|
||||
return division.prodMats.includes(props.mat.name) && !mat.sllman[0];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-warehouse-material-div"}>
|
||||
<div style={{ display: "inline-block" }}>
|
||||
<p className={"tooltip"}>
|
||||
{mat.name}: {numeralWrapper.format(mat.qty, nfB)} ({numeralWrapper.format(totalGain, nfB)}/s)
|
||||
<span className={"tooltiptext"}>
|
||||
Buy: {numeralWrapper.format(mat.buy, nfB)} <br />
|
||||
Prod: {numeralWrapper.format(mat.prd, nfB)} <br />
|
||||
Sell: {numeralWrapper.format(mat.sll, nfB)} <br />
|
||||
Export: {numeralWrapper.format(mat.totalExp, nfB)} <br />
|
||||
Import: {numeralWrapper.format(mat.imp, nfB)}
|
||||
{corp.unlockUpgrades[2] === 1 && <br />}
|
||||
{corp.unlockUpgrades[2] === 1 && "Demand: " + numeralWrapper.format(mat.dmd, nf)}
|
||||
{corp.unlockUpgrades[3] === 1 && <br />}
|
||||
{corp.unlockUpgrades[3] === 1 && "Competition: " + numeralWrapper.format(mat.cmp, nf)}
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
MP: {numeralWrapper.formatMoney(mat.bCost)}
|
||||
<span className={"tooltiptext"}>
|
||||
Market Price: The price you would pay if you were to buy this material on the market
|
||||
</span>
|
||||
</p>{" "}
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Quality: {numeralWrapper.format(mat.qlt, "0.00a")}
|
||||
<span className={"tooltiptext"}>The quality of your material. Higher quality will lead to more sales</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "inline-block" }}>
|
||||
<Button
|
||||
className={purchaseButtonClass}
|
||||
onClick={openPurchaseMaterialPopup}
|
||||
disabled={props.warehouse.smartSupplyEnabled && Object.keys(division.reqMats).includes(props.mat.name)}
|
||||
>
|
||||
{purchaseButtonText}
|
||||
{tutorial && (
|
||||
<span className={"tooltiptext"}>Purchase your required materials to get production started!</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{corp.unlockUpgrades[0] === 1 && <Button onClick={openExportPopup}>Export</Button>}
|
||||
<br />
|
||||
|
||||
<Button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
|
||||
{sellButtonText}
|
||||
</Button>
|
||||
|
||||
{division.hasResearch("Market-TA.I") && <Button onClick={openMaterialMarketTaPopup}>Market-TA</Button>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
division: IIndustry;
|
||||
@ -289,7 +98,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
// Only create UI for materials that are relevant for the industry
|
||||
if (!isRelevantMaterial(matName, division)) continue;
|
||||
mats.push(
|
||||
<MaterialComponent
|
||||
<MaterialElem
|
||||
rerender={props.rerender}
|
||||
city={props.currentCity}
|
||||
key={matName}
|
||||
@ -327,7 +136,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-warehouse-panel"}>
|
||||
<Paper>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Tooltip title={props.warehouse.sizeUsed !== 0 ? breakdown : ""}>
|
||||
<Typography color={props.warehouse.sizeUsed >= props.warehouse.size ? "error" : "primary"}>
|
||||
@ -370,7 +179,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
{mats}
|
||||
|
||||
{products}
|
||||
</div>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ export function IssueDividendsModal(props: IProps): React.ReactElement {
|
||||
else {
|
||||
let p = parseFloat(event.target.value);
|
||||
if (p > 50) p = 50;
|
||||
if (p < 0) p = 0;
|
||||
setPercent(p);
|
||||
}
|
||||
}
|
||||
|
@ -57,23 +57,19 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
const maxNewSharesUnrounded = Math.round(corp.totalShares * 0.2);
|
||||
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
||||
|
||||
const newShares = Math.round((shares || 0) / 10e6) * 10e6;
|
||||
const disabled = shares === null || isNaN(newShares) || newShares < 10e6 || newShares > maxNewShares;
|
||||
|
||||
function issueNewShares(): void {
|
||||
if (shares === null) return;
|
||||
if (disabled) return;
|
||||
|
||||
const newSharePrice = Math.round(corp.sharePrice * 0.9);
|
||||
let newShares = shares;
|
||||
if (isNaN(newShares)) {
|
||||
dialogBoxCreate("Invalid input for number of new shares");
|
||||
return;
|
||||
}
|
||||
|
||||
// Round to nearest ten-millionth
|
||||
newShares = Math.round(newShares / 10e6) * 10e6;
|
||||
|
||||
if (newShares < 10e6 || newShares > maxNewShares) {
|
||||
dialogBoxCreate("Invalid input for number of new shares");
|
||||
return;
|
||||
}
|
||||
|
||||
const profit = newShares * newSharePrice;
|
||||
corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
|
||||
corp.totalShares += newShares;
|
||||
@ -128,7 +124,7 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
<EffectText shares={shares} />
|
||||
<TextField autoFocus placeholder="# New Shares" onChange={onChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={issueNewShares} sx={{ mx: 1 }}>
|
||||
<Button disabled={disabled} onClick={issueNewShares} sx={{ mx: 1 }}>
|
||||
Issue New Shares
|
||||
</Button>
|
||||
</Modal>
|
||||
|
204
src/Corporation/ui/MaterialElem.tsx
Normal file
204
src/Corporation/ui/MaterialElem.tsx
Normal file
@ -0,0 +1,204 @@
|
||||
// React Component for displaying an Industry's warehouse information
|
||||
// (right-side panel in the Industry UI)
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Material } from "../Material";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { ExportModal } from "./ExportModal";
|
||||
import { MaterialMarketTaModal } from "./MaterialMarketTaModal";
|
||||
import { SellMaterialModal } from "./SellMaterialModal";
|
||||
import { PurchaseMaterialModal } from "./PurchaseMaterialModal";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { isString } from "../../utils/helpers/isString";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
interface IMaterialProps {
|
||||
warehouse: Warehouse;
|
||||
city: string;
|
||||
mat: Material;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Material type
|
||||
export function MaterialElem(props: IMaterialProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const division = useDivision();
|
||||
const [purchaseMaterialOpen, setPurchaseMaterialOpen] = useState(false);
|
||||
const [exportOpen, setExportOpen] = useState(false);
|
||||
const [sellMaterialOpen, setSellMaterialOpen] = useState(false);
|
||||
const [materialMarketTaOpen, setMaterialMarketTaOpen] = useState(false);
|
||||
const warehouse = props.warehouse;
|
||||
const city = props.city;
|
||||
const mat = props.mat;
|
||||
const markupLimit = mat.getMarkupLimit();
|
||||
const office = division.offices[city];
|
||||
if (!(office instanceof OfficeSpace)) {
|
||||
throw new Error(`Could not get OfficeSpace object for this city (${city})`);
|
||||
}
|
||||
|
||||
// Numeraljs formatter
|
||||
const nf = "0.000";
|
||||
const nfB = "0.000a"; // For numbers that might be biger
|
||||
|
||||
// Total gain or loss of this material (per second)
|
||||
const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
|
||||
|
||||
// Flag that determines whether this industry is "new" and the current material should be
|
||||
// marked with flashing-red lights
|
||||
const tutorial =
|
||||
division.newInd && Object.keys(division.reqMats).includes(mat.name) && mat.buy === 0 && mat.imp === 0;
|
||||
|
||||
// Purchase material button
|
||||
const purchaseButtonText = `Buy (${numeralWrapper.format(mat.buy, nfB)})`;
|
||||
|
||||
// Sell material button
|
||||
let sellButtonText: JSX.Element;
|
||||
if (mat.sllman[0]) {
|
||||
if (isString(mat.sllman[1])) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
Sell ({numeralWrapper.format(mat.sll, nfB)}/{mat.sllman[1]})
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
sellButtonText = (
|
||||
<>
|
||||
Sell ({numeralWrapper.format(mat.sll, nfB)}/{numeralWrapper.format(mat.sllman[1] as number, nfB)})
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (mat.marketTa2) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.marketTa2Price} />
|
||||
</>
|
||||
);
|
||||
} else if (mat.marketTa1) {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.bCost + markupLimit} />
|
||||
</>
|
||||
);
|
||||
} else if (mat.sCost) {
|
||||
if (isString(mat.sCost)) {
|
||||
const sCost = (mat.sCost as string).replace(/MP/g, mat.bCost + "");
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={eval(sCost)} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
sellButtonText = (
|
||||
<>
|
||||
{sellButtonText} @ <Money money={mat.sCost} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sellButtonText = <>Sell (0.000/0.000)</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
<Box display="flex">
|
||||
<Box>
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Buy: {numeralWrapper.format(mat.buy, nfB)} <br />
|
||||
Prod: {numeralWrapper.format(mat.prd, nfB)} <br />
|
||||
Sell: {numeralWrapper.format(mat.sll, nfB)} <br />
|
||||
Export: {numeralWrapper.format(mat.totalExp, nfB)} <br />
|
||||
Import: {numeralWrapper.format(mat.imp, nfB)}
|
||||
{corp.unlockUpgrades[2] === 1 && <br />}
|
||||
{corp.unlockUpgrades[2] === 1 && "Demand: " + numeralWrapper.format(mat.dmd, nf)}
|
||||
{corp.unlockUpgrades[3] === 1 && <br />}
|
||||
{corp.unlockUpgrades[3] === 1 && "Competition: " + numeralWrapper.format(mat.cmp, nf)}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>
|
||||
{mat.name}: {numeralWrapper.format(mat.qty, nfB)} ({numeralWrapper.format(totalGain, nfB)}/s)
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
Market Price: The price you would pay if you were to buy this material on the market
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>MP: {numeralWrapper.formatMoney(mat.bCost)}</Typography>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={<Typography>The quality of your material. Higher quality will lead to more sales</Typography>}
|
||||
>
|
||||
<Typography>Quality: {numeralWrapper.format(mat.qlt, "0.00a")}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Tooltip
|
||||
title={tutorial ? <Typography>Purchase your required materials to get production started!</Typography> : ""}
|
||||
>
|
||||
<span>
|
||||
<Button
|
||||
color={tutorial ? "error" : "primary"}
|
||||
onClick={() => setPurchaseMaterialOpen(true)}
|
||||
disabled={props.warehouse.smartSupplyEnabled && Object.keys(division.reqMats).includes(props.mat.name)}
|
||||
>
|
||||
{purchaseButtonText}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<PurchaseMaterialModal
|
||||
mat={mat}
|
||||
warehouse={warehouse}
|
||||
open={purchaseMaterialOpen}
|
||||
onClose={() => setPurchaseMaterialOpen(false)}
|
||||
/>
|
||||
|
||||
{corp.unlockUpgrades[0] === 1 && (
|
||||
<>
|
||||
<Button onClick={() => setExportOpen(true)}>Export</Button>
|
||||
|
||||
<ExportModal mat={mat} open={exportOpen} onClose={() => setExportOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
<br />
|
||||
|
||||
<Button
|
||||
color={division.prodMats.includes(props.mat.name) && !mat.sllman[0] ? "error" : "primary"}
|
||||
onClick={() => setSellMaterialOpen(true)}
|
||||
>
|
||||
{sellButtonText}
|
||||
</Button>
|
||||
<SellMaterialModal mat={mat} open={sellMaterialOpen} onClose={() => setSellMaterialOpen(false)} />
|
||||
{division.hasResearch("Market-TA.I") && (
|
||||
<>
|
||||
<Button onClick={() => setMaterialMarketTaOpen(true)}>Market-TA</Button>
|
||||
|
||||
<MaterialMarketTaModal
|
||||
mat={mat}
|
||||
open={materialMarketTaOpen}
|
||||
onClose={() => setMaterialMarketTaOpen(false)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -1,16 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { Material } from "../Material";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useDivision } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
|
||||
interface IMarketTA2Props {
|
||||
industry: IIndustry;
|
||||
mat: Material;
|
||||
}
|
||||
|
||||
function MarketTA2(props: IMarketTA2Props): React.ReactElement {
|
||||
if (!props.industry.hasResearch("Market-TA.II")) return <></>;
|
||||
const division = useDivision();
|
||||
if (!division.hasResearch("Market-TA.II")) return <></>;
|
||||
|
||||
const [newCost, setNewCost] = useState<number>(props.mat.bCost);
|
||||
const setRerender = useState(false)[1];
|
||||
@ -47,50 +52,47 @@ function MarketTA2(props: IMarketTA2Props): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<br />
|
||||
<u>
|
||||
<strong>Market-TA.II</strong>
|
||||
</u>
|
||||
<br />
|
||||
<Typography variant="h4">Market-TA.II</Typography>
|
||||
<br />
|
||||
<Typography>
|
||||
If you sell at {numeralWrapper.formatMoney(sCost)}, then you will sell{" "}
|
||||
{numeralWrapper.format(markup, "0.00000")}x as much compared to if you sold at market price.
|
||||
</p>
|
||||
<input className="text-input" type="number" style={{ marginTop: "4px" }} onChange={onChange} value={newCost} />
|
||||
<div style={{ display: "block" }}>
|
||||
<label className="tooltip" htmlFor="cmpy-mgmt-marketa2-checkbox" style={{ color: "white" }}>
|
||||
Use Market-TA.II for Auto-Sale Price
|
||||
<span className="tooltiptext">
|
||||
If this is enabled, then this Material will automatically be sold at the optimal price such that the amount
|
||||
sold matches the amount produced. (i.e. the highest possible price, while still ensuring that all produced
|
||||
materials will be sold)
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
id="cmpy-mgmt-marketa2-checkbox"
|
||||
type="checkbox"
|
||||
onChange={onMarketTA2}
|
||||
checked={props.mat.marketTa2}
|
||||
style={{ margin: "3px" }}
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
</Typography>
|
||||
<TextField type="number" onChange={onChange} value={newCost} />
|
||||
<br />
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa2} onChange={onMarketTA2} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the optimal price such that the
|
||||
amount sold matches the amount produced. (i.e. the highest possible price, while still ensuring that all
|
||||
produced materials will be sold)
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.II for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
|
||||
<Typography>
|
||||
Note that Market-TA.II overrides Market-TA.I. This means that if both are enabled, then Market-TA.II will take
|
||||
effect, not Market-TA.I
|
||||
</p>
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
industry: IIndustry;
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player use the Market TA research for Materials
|
||||
export function MaterialMarketTaPopup(props: IProps): React.ReactElement {
|
||||
export function MaterialMarketTaModal(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@ -103,33 +105,30 @@ export function MaterialMarketTaPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<u>
|
||||
<strong>Market-TA.I</strong>
|
||||
</u>
|
||||
<br />
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography variant="h4">Market-TA.I</Typography>
|
||||
<Typography>
|
||||
The maximum sale price you can mark this up to is {numeralWrapper.formatMoney(props.mat.bCost + markupLimit)}.
|
||||
This means that if you set the sale price higher than this, you will begin to experience a loss in number of
|
||||
sales
|
||||
</p>
|
||||
<div style={{ display: "block" }}>
|
||||
<label className="tooltip" htmlFor="cmpy-mgmt-marketa1-checkbox" style={{ color: "white" }}>
|
||||
Use Market-TA.I for Auto-Sale Price
|
||||
<span className="tooltiptext">
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
|
||||
(i.e. the price shown above)
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
id="cmpy-mgmt-marketa1-checkbox"
|
||||
type="checkbox"
|
||||
onChange={onMarketTA1}
|
||||
checked={props.mat.marketTa1}
|
||||
style={{ margin: "3px" }}
|
||||
/>
|
||||
</div>
|
||||
<MarketTA2 mat={props.mat} industry={props.industry} />
|
||||
</>
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Switch checked={props.mat.marketTa1} onChange={onMarketTA1} />}
|
||||
label={
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I
|
||||
(i.e. the price shown above)
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Use Market-TA.I for Auto-Sale Price</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
<MarketTA2 mat={props.mat} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -220,7 +220,11 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
|
||||
</Tooltip>
|
||||
<SellSharesModal open={sellSharesOpen} onClose={() => setSellSharesOpen(false)} rerender={rerender} />
|
||||
<Tooltip title={<Typography>Buy back shares you that previously issued or sold at market price.</Typography>}>
|
||||
<Button onClick={() => setBuybackSharesOpen(true)}>Buyback shares</Button>
|
||||
<span>
|
||||
<Button disabled={corp.issuedShares > 0.5} onClick={() => setBuybackSharesOpen(true)}>
|
||||
Buyback shares
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
<BuybackSharesModal open={buybackSharesOpen} onClose={() => setBuybackSharesOpen(false)} rerender={rerender} />
|
||||
<br />
|
||||
|
@ -1,13 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { MaterialSizes } from "../MaterialSizes";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { Material } from "../Material";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { BuyMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IBulkPurchaseTextProps {
|
||||
warehouse: Warehouse;
|
||||
@ -36,15 +38,14 @@ function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
interface IBPProps {
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
industry: IIndustry;
|
||||
warehouse: Warehouse;
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
function BulkPurchase(props: IProps): React.ReactElement {
|
||||
function BulkPurchase(props: IBPProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [buyAmt, setBuyAmt] = useState("");
|
||||
|
||||
function bulkPurchase(): void {
|
||||
@ -61,15 +62,14 @@ function BulkPurchase(props: IProps): React.ReactElement {
|
||||
dialogBoxCreate("Invalid input amount");
|
||||
} else {
|
||||
const cost = amount * props.mat.bCost;
|
||||
if (props.corp.funds.gt(cost)) {
|
||||
props.corp.funds = props.corp.funds.minus(cost);
|
||||
if (corp.funds.gt(cost)) {
|
||||
corp.funds = corp.funds.minus(cost);
|
||||
props.mat.qty += amount;
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford this purchase.`);
|
||||
return;
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,28 +83,34 @@ function BulkPurchase(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Typography>
|
||||
Enter the amount of {props.mat.name} you would like to bulk purchase. This purchases the specified amount
|
||||
instantly (all at once).
|
||||
</p>
|
||||
</Typography>
|
||||
<BulkPurchaseText warehouse={props.warehouse} mat={props.mat} amount={buyAmt} />
|
||||
<input
|
||||
<TextField
|
||||
value={buyAmt}
|
||||
onChange={onChange}
|
||||
type="number"
|
||||
placeholder="Bulk Purchase amount"
|
||||
style={{ margin: "5px" }}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button className="std-button" onClick={bulkPurchase}>
|
||||
Confirm Bulk Purchase
|
||||
</button>
|
||||
<Button onClick={bulkPurchase}>Confirm Bulk Purchase</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
warehouse: Warehouse;
|
||||
}
|
||||
|
||||
// Create a popup that lets the player purchase a Material
|
||||
export function PurchaseMaterialPopup(props: IProps): React.ReactElement {
|
||||
const [buyAmt, setBuyAmt] = useState(props.mat.buy ? props.mat.buy : null);
|
||||
export function PurchaseMaterialModal(props: IProps): React.ReactElement {
|
||||
const division = useDivision();
|
||||
const [buyAmt, setBuyAmt] = useState(props.mat.buy ? props.mat.buy : 0);
|
||||
|
||||
function purchaseMaterial(): void {
|
||||
if (buyAmt === null) return;
|
||||
@ -114,12 +120,12 @@ export function PurchaseMaterialPopup(props: IProps): React.ReactElement {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function clearPurchase(): void {
|
||||
props.mat.buy = 0;
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
@ -131,35 +137,26 @@ export function PurchaseMaterialPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Enter the amount of {props.mat.name} you would like to purchase per second. This material's cost changes
|
||||
constantly.
|
||||
</p>
|
||||
<input
|
||||
onChange={onChange}
|
||||
className="text-input"
|
||||
autoFocus={true}
|
||||
placeholder="Purchase amount"
|
||||
type="number"
|
||||
style={{ margin: "5px" }}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button onClick={purchaseMaterial} className="std-button">
|
||||
Confirm
|
||||
</button>
|
||||
<button onClick={clearPurchase} className="std-button">
|
||||
Clear Purchase
|
||||
</button>
|
||||
{props.industry.hasResearch("Bulk Purchasing") && (
|
||||
<BulkPurchase
|
||||
corp={props.corp}
|
||||
mat={props.mat}
|
||||
industry={props.industry}
|
||||
warehouse={props.warehouse}
|
||||
popupId={props.popupId}
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<>
|
||||
<Typography>
|
||||
Enter the amount of {props.mat.name} you would like to purchase per second. This material's cost changes
|
||||
constantly.
|
||||
</Typography>
|
||||
<TextField
|
||||
value={buyAmt}
|
||||
onChange={onChange}
|
||||
autoFocus={true}
|
||||
placeholder="Purchase amount"
|
||||
type="number"
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<Button onClick={purchaseMaterial}>Confirm</Button>
|
||||
<Button onClick={clearPurchase}>Clear Purchase</Button>
|
||||
{division.hasResearch("Bulk Purchasing") && (
|
||||
<BulkPurchase onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
|
||||
)}
|
||||
</>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import { Material } from "../Material";
|
||||
import { SellMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
function initialPrice(mat: Material): string {
|
||||
let val = mat.sCost ? mat.sCost + "" : "";
|
||||
@ -16,13 +18,13 @@ function initialPrice(mat: Material): string {
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
mat: Material;
|
||||
corp: ICorporation;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
// Create a popup that let the player manage sales of a material
|
||||
export function SellMaterialPopup(props: IProps): React.ReactElement {
|
||||
export function SellMaterialModal(props: IProps): React.ReactElement {
|
||||
const [amt, setAmt] = useState<string>(props.mat.sllman[1] ? props.mat.sllman[1] + "" : "");
|
||||
const [price, setPrice] = useState<string>(initialPrice(props.mat));
|
||||
|
||||
@ -32,8 +34,7 @@ export function SellMaterialPopup(props: IProps): React.ReactElement {
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
|
||||
removePopup(props.popupId);
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
@ -49,8 +50,8 @@ export function SellMaterialPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter the maximum amount of {props.mat.name} you would like to sell per second, as well as the price at which
|
||||
you would like to sell at.
|
||||
<br />
|
||||
@ -70,30 +71,18 @@ export function SellMaterialPopup(props: IProps): React.ReactElement {
|
||||
When setting the sell price, you can use the 'MP' variable to designate a dynamically changing price that
|
||||
depends on the market price. For example, if you set the sell price to 'MP+10' then it will always be sold at
|
||||
$10 above the market price.
|
||||
</p>
|
||||
</Typography>
|
||||
<br />
|
||||
<input
|
||||
className="text-input"
|
||||
<TextField
|
||||
value={amt}
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
placeholder="Sell amount"
|
||||
style={{ marginTop: "4px" }}
|
||||
onChange={onAmtChange}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<input
|
||||
className="text-input"
|
||||
value={price}
|
||||
type="text"
|
||||
placeholder="Sell price"
|
||||
style={{ marginTop: "4px" }}
|
||||
onChange={onPriceChange}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<button className="std-button" onClick={sellMaterial}>
|
||||
Confirm
|
||||
</button>
|
||||
</>
|
||||
<TextField value={price} type="text" placeholder="Sell price" onChange={onPriceChange} onKeyDown={onKeyDown} />
|
||||
<Button onClick={sellMaterial}>Confirm</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -23,6 +23,8 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [shares, setShares] = useState<number | null>(null);
|
||||
|
||||
const disabled = shares === null || isNaN(shares) || shares <= 0 || shares > corp.numShares;
|
||||
|
||||
function changeShares(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
if (event.target.value === "") setShares(null);
|
||||
else setShares(Math.round(parseFloat(event.target.value)));
|
||||
@ -47,42 +49,37 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
function sell(): void {
|
||||
if (shares === null) return;
|
||||
if (isNaN(shares) || shares <= 0) {
|
||||
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
||||
} else if (shares > corp.numShares) {
|
||||
dialogBoxCreate("ERROR: You don't have this many shares to sell");
|
||||
} else {
|
||||
const stockSaleResults = corp.calculateShareSale(shares);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
if (disabled) return;
|
||||
const stockSaleResults = corp.calculateShareSale(shares);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
|
||||
corp.numShares -= shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`);
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
corp.numShares -= shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`);
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
corp.issuedShares += shares;
|
||||
corp.sharePrice = newSharePrice;
|
||||
corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit);
|
||||
player.recordMoneySource(profit, "corporation");
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Sold ${numeralWrapper.formatMoney(shares)} shares for ` +
|
||||
`${numeralWrapper.formatMoney(profit)}. ` +
|
||||
`The corporation's stock price fell to ${numeralWrapper.formatMoney(corp.sharePrice)} ` +
|
||||
`as a result of dilution.`,
|
||||
);
|
||||
|
||||
props.rerender();
|
||||
}
|
||||
corp.issuedShares += shares;
|
||||
corp.sharePrice = newSharePrice;
|
||||
corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit);
|
||||
player.recordMoneySource(profit, "corporation");
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
`Sold {numeralWrapper.formatMoney(shares)} shares for ` +
|
||||
`${numeralWrapper.formatMoney(profit)}. ` +
|
||||
`The corporation's stock price fell to ${numeralWrapper.formatMoney(corp.sharePrice)} ` +
|
||||
`as a result of dilution.`,
|
||||
);
|
||||
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
@ -112,7 +109,7 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
onChange={changeShares}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<Button onClick={sell} sx={{ mx: 1 }}>
|
||||
<Button disabled={disabled} onClick={sell} sx={{ mx: 1 }}>
|
||||
Sell shares
|
||||
</Button>
|
||||
</Modal>
|
||||
|
@ -11,6 +11,37 @@ import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
interface IUpgradeButton {
|
||||
cost: number;
|
||||
size: number;
|
||||
corp: ICorporation;
|
||||
office: OfficeSpace;
|
||||
onClose: () => void;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
function UpgradeSizeButton(props: IUpgradeButton): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
function upgradeSize(cost: number, size: number): void {
|
||||
if (corp.funds.lt(cost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpgradeOfficeSize(corp, props.office, size);
|
||||
props.rerender();
|
||||
props.onClose();
|
||||
}
|
||||
return (
|
||||
<Tooltip title={numeralWrapper.formatMoney(props.cost)}>
|
||||
<span>
|
||||
<Button disabled={corp.funds.lt(props.cost)} onClick={() => upgradeSize(props.cost, props.size)}>
|
||||
+{props.size}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
@ -48,44 +79,35 @@ export function UpgradeOfficeSizeModal(props: IProps): React.ReactElement {
|
||||
}
|
||||
const upgradeCostMax = CorporationConstants.OfficeInitialCost * mult;
|
||||
|
||||
function upgradeSize(cost: number, size: number): void {
|
||||
if (corp.funds.lt(cost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpgradeOfficeSize(corp, props.office, size);
|
||||
props.rerender();
|
||||
|
||||
props.rerender();
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
interface IUpgradeButton {
|
||||
cost: number;
|
||||
size: number;
|
||||
corp: ICorporation;
|
||||
}
|
||||
|
||||
function UpgradeSizeButton(props: IUpgradeButton): React.ReactElement {
|
||||
return (
|
||||
<Tooltip title={numeralWrapper.formatMoney(props.cost)}>
|
||||
<span>
|
||||
<Button disabled={corp.funds.lt(props.cost)} onClick={() => upgradeSize(props.cost, props.size)}>
|
||||
+{props.size}
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>Increase the size of your office space to fit additional employees!</Typography>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Typography>Upgrade size: </Typography>
|
||||
<UpgradeSizeButton corp={corp} cost={upgradeCost} size={CorporationConstants.OfficeInitialSize} />
|
||||
<UpgradeSizeButton corp={corp} cost={upgradeCost15} size={CorporationConstants.OfficeInitialSize * 5} />
|
||||
<UpgradeSizeButton corp={corp} cost={upgradeCostMax} size={maxNum * CorporationConstants.OfficeInitialSize} />
|
||||
<UpgradeSizeButton
|
||||
onClose={props.onClose}
|
||||
rerender={props.rerender}
|
||||
office={props.office}
|
||||
corp={corp}
|
||||
cost={upgradeCost}
|
||||
size={CorporationConstants.OfficeInitialSize}
|
||||
/>
|
||||
<UpgradeSizeButton
|
||||
onClose={props.onClose}
|
||||
rerender={props.rerender}
|
||||
office={props.office}
|
||||
corp={corp}
|
||||
cost={upgradeCost15}
|
||||
size={CorporationConstants.OfficeInitialSize * 5}
|
||||
/>
|
||||
<UpgradeSizeButton
|
||||
onClose={props.onClose}
|
||||
rerender={props.rerender}
|
||||
office={props.office}
|
||||
corp={corp}
|
||||
cost={upgradeCostMax}
|
||||
size={maxNum * CorporationConstants.OfficeInitialSize}
|
||||
/>
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -65,24 +65,18 @@ const GangNames = [
|
||||
"The Black Hand",
|
||||
];
|
||||
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
const [sleevesOpen, setSleevesOpen] = useState(false);
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
// Enabling this breaks donations.
|
||||
// useEffect(() => {
|
||||
// const id = setInterval(rerender, 200);
|
||||
// return () => clearInterval(id);
|
||||
// }, []);
|
||||
|
||||
const faction = props.faction;
|
||||
interface IMainProps {
|
||||
faction: Faction;
|
||||
rerender: () => void;
|
||||
onAugmentations: () => void;
|
||||
}
|
||||
|
||||
function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(false);
|
||||
const [sleevesOpen, setSleevesOpen] = useState(false);
|
||||
const p = player;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
function manageGang(faction: Faction): void {
|
||||
// If player already has a gang, just go to the gang UI
|
||||
@ -99,16 +93,6 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
// Route to the main faction page
|
||||
function routeToMain(): void {
|
||||
setPurchasingAugs(false);
|
||||
}
|
||||
|
||||
// Route to the purchase augmentation UI for this faction
|
||||
function routeToPurchaseAugs(): void {
|
||||
setPurchasingAugs(true);
|
||||
}
|
||||
|
||||
function startFieldWork(faction: Faction): void {
|
||||
player.startFactionFieldWork(router, faction);
|
||||
}
|
||||
@ -126,85 +110,96 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
||||
player.startFactionSecurityWork(router, faction);
|
||||
}
|
||||
|
||||
function MainPage({ faction }: { faction: Faction }): React.ReactElement {
|
||||
const p = player;
|
||||
const factionInfo = faction.getInfo();
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = p.inGang() && p.getGangName() === faction.name;
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = p.inGang() && p.getGangName() === faction.name;
|
||||
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
|
||||
// should be shown
|
||||
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
|
||||
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
|
||||
// should be shown
|
||||
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
const canPurchaseSleeves = faction.name === "The Covenant" && p.bitNodeN >= 10 && SourceFileFlags[10];
|
||||
|
||||
const canPurchaseSleeves = faction.name === "The Covenant" && p.bitNodeN >= 10 && SourceFileFlags[10];
|
||||
|
||||
let canAccessGang = p.canAccessGang() && GangNames.includes(faction.name);
|
||||
if (p.inGang()) {
|
||||
if (p.getGangName() !== faction.name) {
|
||||
canAccessGang = false;
|
||||
} else if (p.getGangName() === faction.name) {
|
||||
canAccessGang = true;
|
||||
}
|
||||
let canAccessGang = p.canAccessGang() && GangNames.includes(faction.name);
|
||||
if (p.inGang()) {
|
||||
if (p.getGangName() !== faction.name) {
|
||||
canAccessGang = false;
|
||||
} else if (p.getGangName() === faction.name) {
|
||||
canAccessGang = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => router.toFactions()}>Back</Button>
|
||||
<Typography variant="h4" color="primary">
|
||||
{faction.name}
|
||||
</Typography>
|
||||
<Info faction={faction} factionInfo={factionInfo} />
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
||||
{!isPlayersGang && factionInfo.offerHackingMission && (
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={() => startHackingMission(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerSecurityWork && (
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offersWork() && (
|
||||
<DonateOption
|
||||
faction={faction}
|
||||
p={player}
|
||||
rerender={rerender}
|
||||
favorToDonate={favorToDonate}
|
||||
disabled={!canDonate}
|
||||
/>
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={routeToPurchaseAugs} />
|
||||
{canPurchaseSleeves && (
|
||||
<>
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={() => setSleevesOpen(true)}
|
||||
/>
|
||||
<CovenantPurchasesRoot open={sleevesOpen} onClose={() => setSleevesOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={routeToMain} />
|
||||
) : (
|
||||
<MainPage faction={faction} />
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => router.toFactions()}>Back</Button>
|
||||
<Typography variant="h4" color="primary">
|
||||
{faction.name}
|
||||
</Typography>
|
||||
<Info faction={faction} factionInfo={factionInfo} />
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
||||
{!isPlayersGang && factionInfo.offerHackingMission && (
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={() => startHackingMission(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerSecurityWork && (
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offersWork() && (
|
||||
<DonateOption
|
||||
faction={faction}
|
||||
p={player}
|
||||
rerender={rerender}
|
||||
favorToDonate={favorToDonate}
|
||||
disabled={!canDonate}
|
||||
/>
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={onAugmentations} />
|
||||
{canPurchaseSleeves && (
|
||||
<>
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={() => setSleevesOpen(true)}
|
||||
/>
|
||||
<CovenantPurchasesRoot open={sleevesOpen} onClose={() => setSleevesOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 200);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const faction = props.faction;
|
||||
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(false);
|
||||
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={() => setPurchasingAugs(false)} />
|
||||
) : (
|
||||
<MainPage rerender={rerender} faction={faction} onAugmentations={() => setPurchasingAugs(true)} />
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Implementation for what happens when you destroy a BitNode
|
||||
*/
|
||||
import React from "react";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeSourceFile } from "./Prestige";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
@ -58,7 +59,15 @@ function giveSourceFile(bitNodeNumber: number): void {
|
||||
Player.intelligence = 1;
|
||||
}
|
||||
dialogBoxCreate(
|
||||
"You received a Source-File for destroying a BitNode!<br><br>" + sourceFile.name + "<br><br>" + sourceFile.info,
|
||||
<>
|
||||
You received a Source-File for destroying a BitNode!
|
||||
<br />
|
||||
<br />
|
||||
{sourceFile.name}
|
||||
<br />
|
||||
<br />
|
||||
{sourceFile.info}
|
||||
</>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,20 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children: JSX.Element[] | JSX.Element | React.ReactElement[] | React.ReactElement;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Modal = (props: IProps): React.ReactElement => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<M open={props.open} onClose={props.onClose} closeAfterTransition className={classes.modal}>
|
||||
<M
|
||||
disableRestoreFocus
|
||||
disableScrollLock
|
||||
open={props.open}
|
||||
onClose={props.onClose}
|
||||
closeAfterTransition
|
||||
className={classes.modal}
|
||||
>
|
||||
<Fade in={props.open}>
|
||||
<div className={classes.paper}>
|
||||
<Box sx={{ m: 2 }}>{props.children}</Box>
|
||||
|
Loading…
Reference in New Issue
Block a user