convert some corp to mui

This commit is contained in:
Olivier Gagnon 2021-09-30 13:51:55 -04:00
parent 5cce1c255c
commit 510fcedf90
12 changed files with 691 additions and 656 deletions

@ -385,9 +385,6 @@ export class Industry implements IIndustry {
const prod = this.products[prodName];
if (prod === undefined) continue;
warehouse.sizeUsed += prod.data[warehouse.loc][0] * prod.siz;
if (prod.data[warehouse.loc][0] > 0) {
warehouse.breakdown += prodName + ": " + formatNumber(prod.data[warehouse.loc][0] * prod.siz, 0) + "<br>";
}
}
}
}

@ -15,10 +15,6 @@ interface IConstructorParams {
}
export class Warehouse {
// Text that describes how the space in this Warehouse is being used
// Used to create a tooltip in the UI
breakdown = "";
// Warehouse's level, which affects its maximum size
level = 1;
@ -90,14 +86,10 @@ export class Warehouse {
// Re-calculate how much space is being used by this Warehouse
updateMaterialSizeUsed(): void {
this.sizeUsed = 0;
this.breakdown = "";
for (const matName in this.materials) {
const mat = this.materials[matName];
if (MaterialSizes.hasOwnProperty(matName)) {
this.sizeUsed += mat.qty * MaterialSizes[matName];
if (mat.qty > 0) {
this.breakdown += matName + ": " + numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0") + "<br>";
}
}
}
if (this.sizeUsed > this.size) {

@ -9,6 +9,7 @@ import { Warehouse } from "../Warehouse";
import { OfficeSpace } from "../OfficeSpace";
import { use } from "../../ui/Context";
import { useCorporation, useDivision } from "./Context";
import Box from "@mui/material/Box";
interface IProps {
city: string;
@ -22,12 +23,12 @@ export function Industry(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
return (
<div>
<div className={"cmpy-mgmt-industry-left-panel"}>
<Box display="flex">
<Box sx={{ width: "50%" }}>
<IndustryOverview rerender={props.rerender} currentCity={props.city} office={props.office} />
<IndustryOffice rerender={props.rerender} office={props.office} />
</div>
<div className={"cmpy-mgmt-industry-right-panel"}>
</Box>
<Box sx={{ width: "50%" }}>
<IndustryWarehouse
rerender={props.rerender}
player={player}
@ -36,7 +37,7 @@ export function Industry(props: IProps): React.ReactElement {
division={division}
warehouse={props.warehouse}
/>
</div>
</div>
</Box>
</Box>
);
}

@ -432,7 +432,7 @@ export function IndustryOffice(props: IProps): React.ReactElement {
<Tooltip title={<Typography>Automatically hires an employee and gives him/her a random name</Typography>}>
<span>
<Button disabled={props.office.atCapacity()} onClick={autohireEmployeeButtonOnClick}>
Autohire Employee
Hire Employee
</Button>
</span>
</Tooltip>

@ -1,101 +1,74 @@
// React Component for displaying an Industry's overview information
// (top-left panel in the Industry UI)
import React from "react";
import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { Industries } from "../IndustryData";
import { IndustryUpgrades } from "../IndustryUpgrades";
import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
import { MakeProductPopup } from "./MakeProductPopup";
import { MakeProductModal } from "./MakeProductModal";
import { ResearchPopup } from "./ResearchPopup";
import { createPopup } from "../../ui/React/createPopup";
import { Money } from "../../ui/React/Money";
import { MoneyRate } from "../../ui/React/MoneyRate";
import { StatsTable } from "../../ui/React/StatsTable";
import { StaticModal } from "../../ui/React/StaticModal";
import { MoneyCost } from "./MoneyCost";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Paper from "@mui/material/Paper";
import IconButton from "@mui/material/IconButton";
import HelpIcon from "@mui/icons-material/Help";
import Box from "@mui/material/Box";
interface IProps {
currentCity: string;
office: OfficeSpace;
rerender: () => void;
}
export function IndustryOverview(props: IProps): React.ReactElement {
function MakeProductButton(): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
function renderMakeProductButton(): React.ReactElement {
let createProductButtonText = "";
let createProductPopupText = "";
switch (division.type) {
case Industries.Food:
createProductButtonText = "Build Restaurant";
createProductPopupText = "Build and manage a new restaurant!";
break;
case Industries.Tobacco:
createProductButtonText = "Create Product";
createProductPopupText = "Create a new tobacco product!";
break;
case Industries.Pharmaceutical:
createProductButtonText = "Create Drug";
createProductPopupText = "Design and develop a new pharmaceutical drug!";
break;
case Industries.Computer:
case "Computer":
createProductButtonText = "Create Product";
createProductPopupText = "Design and manufacture a new computer hardware product!";
break;
case Industries.Robotics:
createProductButtonText = "Design Robot";
createProductPopupText = "Design and create a new robot or robotic system!";
break;
case Industries.Software:
createProductButtonText = "Develop Software";
createProductPopupText = "Develop a new piece of software!";
break;
case Industries.Healthcare:
createProductButtonText = "Build Hospital";
createProductPopupText = "Build and manage a new hospital!";
break;
case Industries.RealEstate:
createProductButtonText = "Develop Property";
createProductPopupText = "Develop a new piece of real estate property!";
break;
default:
createProductButtonText = "Create Product";
createProductPopupText = "Create a new product!";
return <></>;
}
createProductPopupText +=
"<br><br>To begin developing a product, " +
"first choose the city in which it will be designed. The stats of your employees " +
"in the selected city affect the properties of the finished product, such as its " +
"quality, performance, and durability.<br><br>" +
"You can also choose to invest money in the design and marketing of " +
"the product. Investing money in its design will result in a superior product. " +
"Investing money in marketing the product will help the product's sales.";
const [makeOpen, setMakeOpen] = useState(false);
const hasMaxProducts = division.hasMaximumNumberProducts();
const hasMaxProducts = division.hasMaximumNumberProducts();
function openMakeProductPopup(): void {
const popupId = "cmpy-mgmt-create-product-popup";
createPopup(popupId, MakeProductPopup, {
popupText: createProductPopupText,
division: division,
corp: corp,
popupId: popupId,
});
}
function shouldFlash(): boolean {
return Object.keys(division.products).length === 0;
}
function shouldFlash(): boolean {
return Object.keys(division.products).length === 0;
}
let createProductButtonText = "";
switch (division.type) {
case Industries.Food:
createProductButtonText = "Build Restaurant";
break;
case Industries.Tobacco:
createProductButtonText = "Create Product";
break;
case Industries.Pharmaceutical:
createProductButtonText = "Create Drug";
break;
case Industries.Computer:
case "Computer":
createProductButtonText = "Create Product";
break;
case Industries.Robotics:
createProductButtonText = "Design Robot";
break;
case Industries.Software:
createProductButtonText = "Develop Software";
break;
case Industries.Healthcare:
createProductButtonText = "Build Hospital";
break;
case Industries.RealEstate:
createProductButtonText = "Develop Property";
break;
default:
createProductButtonText = "Create Product";
return <></>;
}
return (
return (
<>
<Tooltip
title={
hasMaxProducts ? (
@ -107,225 +80,212 @@ export function IndustryOverview(props: IProps): React.ReactElement {
)
}
>
<Button color={shouldFlash() ? "error" : "primary"} onClick={openMakeProductPopup} disabled={corp.funds.lt(0)}>
<Button
color={shouldFlash() ? "error" : "primary"}
onClick={() => setMakeOpen(true)}
disabled={corp.funds.lt(0)}
>
{createProductButtonText}
</Button>
</Tooltip>
);
<MakeProductModal open={makeOpen} onClose={() => setMakeOpen(false)} />
</>
);
}
function Text(): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const [helpOpen, setHelpOpen] = useState(false);
const vechain = corp.unlockUpgrades[4] === 1;
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber();
let advertisingInfo = false;
const advertisingFactors = division.getAdvertisingFactors();
const awarenessFac = advertisingFactors[1];
const popularityFac = advertisingFactors[2];
const ratioFac = advertisingFactors[3];
const totalAdvertisingFac = advertisingFactors[0];
if (vechain) {
advertisingInfo = true;
}
function renderText(): React.ReactElement {
const vechain = corp.unlockUpgrades[4] === 1;
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber();
let advertisingInfo = false;
const advertisingFactors = division.getAdvertisingFactors();
const awarenessFac = advertisingFactors[1];
const popularityFac = advertisingFactors[2];
const ratioFac = advertisingFactors[3];
const totalAdvertisingFac = advertisingFactors[0];
if (vechain) {
advertisingInfo = true;
}
function productionMultHelpTipOnClick(): void {
// Wrapper for createProgressBarText()
// Converts the industry's "effectiveness factors"
// into a graphic (string) depicting how high that effectiveness is
function convertEffectFacToGraphic(fac: number): string {
return createProgressBarText({
progress: fac,
totalTicks: 20,
});
}
dialogBoxCreate(
"Owning Hardware, Robots, AI Cores, and Real Estate " +
"can boost your Industry's production. The effect these " +
"materials have on your production varies between Industries. " +
"For example, Real Estate may be very effective for some Industries, " +
"but ineffective for others.<br><br>" +
"This division's production multiplier is calculated by summing " +
"the individual production multiplier of each of its office locations. " +
"This production multiplier is applied to each office. Therefore, it is " +
"beneficial to expand into new cities as this can greatly increase the " +
"production multiplier of your entire Division.<br><br>" +
"Below are approximations for how effective each material is at boosting " +
"this industry's production multiplier (Bigger bars = more effective):<br><br>" +
`Hardware:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.hwFac)}<br>` +
`Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.robFac)}<br>` +
`AI Cores:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.aiFac)}<br>` +
`Real Estate: ${convertEffectFacToGraphic(division.reFac)}`,
);
}
function openResearchPopup(): void {
const popupId = "corporation-research-popup-box";
createPopup(popupId, ResearchPopup, {
industry: division,
popupId: popupId,
});
}
return (
<div>
<Typography>
Industry: {division.type} (Corp Funds: <Money money={corp.funds.toNumber()} />)
<br /> <br />
Awareness: {numeralWrapper.format(division.awareness, "0.000")} <br />
Popularity: {numeralWrapper.format(division.popularity, "0.000")} <br />
{advertisingInfo !== false && (
<p className={"tooltip"}>
Advertising Multiplier: x{numeralWrapper.format(totalAdvertisingFac, "0.000")}
<span className={"tooltiptext cmpy-mgmt-advertising-info"}>
Total multiplier for this industrys sales due to its awareness and popularity
<br />
Awareness Bonus: x{numeralWrapper.format(Math.pow(awarenessFac, 0.85), "0.000")}
<br />
Popularity Bonus: x{numeralWrapper.format(Math.pow(popularityFac, 0.85), "0.000")}
<br />
Ratio Multiplier: x{numeralWrapper.format(Math.pow(ratioFac, 0.85), "0.000")}
</span>
</p>
)}
{advertisingInfo}
</Typography>
<br />
<br />
<table>
<tbody>
<tr>
<td>
<p>Revenue: </p>
</td>
<td>
<p>
<Money money={division.lastCycleRevenue.toNumber()} /> / s
</p>
</td>
</tr>
<tr>
<td>
<p>Expenses: </p>
</td>
<td>
<p>
<Money money={division.lastCycleExpenses.toNumber()} /> / s
</p>
</td>
</tr>
<tr>
<td>
<p>Profit: </p>
</td>
<td>
<p>
<Money money={profit} /> / s
</p>
</td>
</tr>
</tbody>
</table>
<br />
<p className={"tooltip"}>
Production Multiplier: {numeralWrapper.format(division.prodMult, "0.00")}
<span className={"tooltiptext"}>
Production gain from owning production-boosting materials such as hardware, Robots, AI Cores, and Real
Estate
</span>
</p>
<div className={"help-tip"} onClick={productionMultHelpTipOnClick}>
?
</div>
<br /> <br />
<p className={"tooltip"}>
Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000a")}
<span className={"tooltiptext"}>
Scientific Research increases the quality of the materials and products that you produce.
</span>
</p>
<button className={"help-tip"} onClick={openResearchPopup}>
Research
</button>
</div>
);
function convertEffectFacToGraphic(fac: number): string {
return createProgressBarText({
progress: fac,
totalTicks: 20,
});
}
function renderUpgrades(): React.ReactElement[] {
const upgrades = [];
for (const index in IndustryUpgrades) {
const upgrade = IndustryUpgrades[index];
function openResearchPopup(): void {
const popupId = "corporation-research-popup-box";
createPopup(popupId, ResearchPopup, {
industry: division,
popupId: popupId,
});
}
// AutoBrew research disables the Coffee upgrade
if (division.hasResearch("AutoBrew") && upgrade[4] === "Coffee") {
continue;
}
const i = upgrade[0];
const baseCost = upgrade[1];
const priceMult = upgrade[2];
let cost = 0;
switch (i) {
case 0: //Coffee, cost is static per employee
cost = props.office.employees.length * baseCost;
break;
default:
cost = baseCost * Math.pow(priceMult, division.upgrades[i]);
break;
}
function onClick(): void {
if (corp.funds.lt(cost)) return;
corp.funds = corp.funds.minus(cost);
division.upgrade(upgrade, {
corporation: corp,
office: props.office,
});
props.rerender();
}
upgrades.push(
renderUpgrade({
key: index,
onClick: onClick,
text: (
return (
<div>
<Typography>
Industry: {division.type} (Corp Funds: <Money money={corp.funds.toNumber()} />)
</Typography>
<br />
<StatsTable
rows={[
["Awareness:", numeralWrapper.format(division.awareness, "0.000")],
["Popularity:", numeralWrapper.format(division.popularity, "0.000")],
]}
/>
{advertisingInfo !== false && (
<Tooltip
title={
<>
{upgrade[4]} - <MoneyCost money={cost} corp={corp} />
<Typography>Total multiplier for this industrys sales due to its awareness and popularity</Typography>
<StatsTable
rows={[
["Awareness Bonus:", "x" + numeralWrapper.format(Math.pow(awarenessFac, 0.85), "0.000")],
["Popularity Bonus:", "x" + numeralWrapper.format(Math.pow(popularityFac, 0.85), "0.000")],
["Ratio Multiplier:", "x" + numeralWrapper.format(Math.pow(ratioFac, 0.85), "0.000")],
]}
/>
</>
),
tooltip: upgrade[5],
}),
);
}
>
<Typography>Advertising Multiplier: x{numeralWrapper.format(totalAdvertisingFac, "0.000")}</Typography>
</Tooltip>
)}
<br />
<StatsTable
rows={[
["Revenue:", <MoneyRate money={division.lastCycleRevenue.toNumber()} />],
["Expenses:", <MoneyRate money={division.lastCycleExpenses.toNumber()} />],
["Profit:", <MoneyRate money={profit} />],
]}
/>
<br />
<Box display="flex" alignItems="center">
<Tooltip
title={
<Typography>
Production gain from owning production-boosting materials such as hardware, Robots, AI Cores, and Real
Estate.
</Typography>
}
>
<Typography>Production Multiplier: {numeralWrapper.format(division.prodMult, "0.00")}</Typography>
</Tooltip>
<IconButton onClick={() => setHelpOpen(true)}>
<HelpIcon />
</IconButton>
<StaticModal open={helpOpen} onClose={() => setHelpOpen(false)}>
<Typography>
Owning Hardware, Robots, AI Cores, and Real Estate can boost your Industry's production. The effect these
materials have on your production varies between Industries. For example, Real Estate may be very effective
for some Industries, but ineffective for others.
<br />
<br />
This division's production multiplier is calculated by summing the individual production multiplier of each
of its office locations. This production multiplier is applied to each office. Therefore, it is beneficial
to expand into new cities as this can greatly increase the production multiplier of your entire Division.
<br />
<br />
Below are approximations for how effective each material is at boosting this industry's production
multiplier (Bigger bars = more effective):
<br />
<br />
Hardware:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.hwFac)}
<br />
Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.robFac)}
<br />
AI Cores:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.aiFac)}
<br />
Real Estate: {convertEffectFacToGraphic(division.reFac)}
</Typography>
</StaticModal>
</Box>
<Box display="flex" alignItems="center">
<Tooltip
title={
<Typography>
Scientific Research increases the quality of the materials and products that you produce.
</Typography>
}
>
<Typography>Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000a")}</Typography>
</Tooltip>
<Button sx={{ mx: 1 }} onClick={openResearchPopup}>
Research
</Button>
</Box>
</div>
);
}
function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const upgrades = [];
for (const index in IndustryUpgrades) {
const upgrade = IndustryUpgrades[index];
// AutoBrew research disables the Coffee upgrade
if (division.hasResearch("AutoBrew") && upgrade[4] === "Coffee") {
continue;
}
return upgrades;
}
const i = upgrade[0];
const baseCost = upgrade[1];
const priceMult = upgrade[2];
let cost = 0;
switch (i) {
case 0: //Coffee, cost is static per employee
cost = props.office.employees.length * baseCost;
break;
default:
cost = baseCost * Math.pow(priceMult, division.upgrades[i]);
break;
}
interface IRenderUpgradeProps {
key: string;
onClick: () => void;
text: JSX.Element;
tooltip: string;
}
function onClick(): void {
if (corp.funds.lt(cost)) return;
corp.funds = corp.funds.minus(cost);
division.upgrade(upgrade, {
corporation: corp,
office: props.office,
});
props.rerender();
}
function renderUpgrade(props: IRenderUpgradeProps): React.ReactElement {
return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} onClick={props.onClick} key={props.key}>
{props.text}
{props.tooltip != null && <span className={"tooltiptext"}>{props.tooltip}</span>}
</div>
upgrades.push(
<Tooltip key={index} title={upgrade[5]}>
<Button onClick={onClick}>
{upgrade[4]} -&nbsp;
<MoneyCost money={cost} corp={corp} />
</Button>
</Tooltip>,
);
}
const makeProductButton = renderMakeProductButton();
return <>{upgrades}</>;
}
interface IProps {
currentCity: string;
office: OfficeSpace;
rerender: () => void;
}
export function IndustryOverview(props: IProps): React.ReactElement {
const division = useDivision();
return (
<Paper>
{renderText()}
<Text />
<br />
<Typography>Purchases & Upgrades</Typography>
{renderUpgrades()} <br />
{division.makesProducts && makeProductButton}
<Upgrades office={props.office} rerender={props.rerender} /> <br />
{division.makesProducts && <MakeProductButton />}
</Paper>
);
}

@ -1,6 +1,6 @@
// React Component for displaying an Industry's warehouse information
// (right-side panel in the Industry UI)
import React from "react";
import React, { useState } from "react";
import { CorporationConstants } from "../data/Constants";
import { OfficeSpace } from "../OfficeSpace";
@ -15,7 +15,8 @@ import { SellMaterialPopup } from "./SellMaterialPopup";
import { SellProductPopup } from "./SellProductPopup";
import { PurchaseMaterialPopup } from "./PurchaseMaterialPopup";
import { ProductMarketTaPopup } from "./ProductMarketTaPopup";
import { SmartSupplyPopup } from "./SmartSupplyPopup";
import { SmartSupplyModal } from "./SmartSupplyModal";
import { MaterialSizes } from "../MaterialSizes";
import { numeralWrapper } from "../../ui/numeralFormat";
import { createPopup } from "../../ui/React/createPopup";
@ -29,6 +30,13 @@ import { MoneyCost } from "./MoneyCost";
import { isRelevantMaterial } from "./Helpers";
import { IndustryProductEquation } from "./IndustryProductEquation";
import { PurchaseWarehouse } from "../Actions";
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 IProductProps {
corp: ICorporation;
@ -41,8 +49,8 @@ interface IProductProps {
// Creates the UI for a single Product type
function ProductComponent(props: IProductProps): React.ReactElement {
const corp = props.corp;
const division = props.division;
const corp = useCorporation();
const division = useDivision();
const city = props.city;
const product = props.product;
@ -136,7 +144,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
rerender: props.rerender,
product: product,
industry: division,
corp: props.corp,
corp: corp,
popupId: popupId,
player: props.player,
});
@ -164,21 +172,11 @@ function ProductComponent(props: IProductProps): React.ReactElement {
{hasUpgradeDashboard && (
<div>
<button className={"std-button"} onClick={openSellProductPopup}>
{sellButtonText}
</button>
<Button onClick={openSellProductPopup}>{sellButtonText}</Button>
<br />
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
{limitProductionButtonText}
</button>
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
Discontinue
</button>
{division.hasResearch("Market-TA.I") && (
<button className={"std-button"} onClick={openProductMarketTaPopup}>
Market-TA
</button>
)}
<Button onClick={openLimitProductProdutionPopup}>{limitProductionButtonText}</Button>
<Button onClick={openDiscontinueProductPopup}>Discontinue</Button>
{division.hasResearch("Market-TA.I") && <Button onClick={openProductMarketTaPopup}>Market-TA</Button>}
</div>
)}
</div>
@ -227,29 +225,17 @@ function ProductComponent(props: IProductProps): React.ReactElement {
</p>
<div>
<button className={"std-button"} onClick={openSellProductPopup}>
{sellButtonText}
</button>
<Button onClick={openSellProductPopup}>{sellButtonText}</Button>
<br />
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
{limitProductionButtonText}
</button>
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
Discontinue
</button>
{division.hasResearch("Market-TA.I") && (
<button className={"std-button"} onClick={openProductMarketTaPopup}>
Market-TA
</button>
)}
<Button onClick={openLimitProductProdutionPopup}>{limitProductionButtonText}</Button>
<Button onClick={openDiscontinueProductPopup}>Discontinue</Button>
{division.hasResearch("Market-TA.I") && <Button onClick={openProductMarketTaPopup}>Market-TA</Button>}
</div>
</div>
);
}
interface IMaterialProps {
corp: ICorporation;
division: IIndustry;
warehouse: Warehouse;
city: string;
mat: Material;
@ -258,8 +244,8 @@ interface IMaterialProps {
// Creates the UI for a single Material type
function MaterialComponent(props: IMaterialProps): React.ReactElement {
const corp = props.corp;
const division = props.division;
const corp = useCorporation();
const division = useDivision();
const warehouse = props.warehouse;
const city = props.city;
const mat = props.mat;
@ -291,7 +277,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
mat: mat,
industry: division,
warehouse: warehouse,
corp: props.corp,
corp: corp,
popupId: popupId,
});
}
@ -300,7 +286,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
const popupId = "cmpy-mgmt-export-popup";
createPopup(popupId, ExportPopup, {
mat: mat,
corp: props.corp,
corp: corp,
popupId: popupId,
});
}
@ -358,7 +344,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
const popupId = "cmpy-mgmt-material-sell-popup";
createPopup(popupId, SellMaterialPopup, {
mat: mat,
corp: props.corp,
corp: corp,
popupId: popupId,
});
}
@ -368,13 +354,13 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
createPopup(popupId, MaterialMarketTaPopup, {
mat: mat,
industry: division,
corp: props.corp,
corp: corp,
popupId: popupId,
});
}
function shouldFlash(): boolean {
return props.division.prodMats.includes(props.mat.name) && !mat.sllman[0];
return division.prodMats.includes(props.mat.name) && !mat.sllman[0];
}
return (
@ -409,33 +395,25 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
</div>
<div style={{ display: "inline-block" }}>
<button
<Button
className={purchaseButtonClass}
onClick={openPurchaseMaterialPopup}
disabled={props.warehouse.smartSupplyEnabled && Object.keys(props.division.reqMats).includes(props.mat.name)}
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>
</Button>
{corp.unlockUpgrades[0] === 1 && (
<button className={"std-button"} onClick={openExportPopup}>
Export
</button>
)}
{corp.unlockUpgrades[0] === 1 && <Button onClick={openExportPopup}>Export</Button>}
<br />
<button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
<Button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
{sellButtonText}
</button>
</Button>
{division.hasResearch("Market-TA.I") && (
<button className={"std-button"} onClick={openMaterialMarketTaPopup}>
Market-TA
</button>
)}
{division.hasResearch("Market-TA.I") && <Button onClick={openMaterialMarketTaPopup}>Market-TA</Button>}
</div>
</div>
);
@ -450,177 +428,188 @@ interface IProps {
rerender: () => void;
}
export function IndustryWarehouse(props: IProps): React.ReactElement {
function renderWarehouseUI(): React.ReactElement {
if (props.warehouse === 0) return <></>;
// General Storage information at the top
const sizeUsageStyle = {
color: props.warehouse.sizeUsed >= props.warehouse.size ? "red" : "white",
margin: "5px",
};
function WarehouseRoot(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const [smartSupplyOpen, setSmartSupplyOpen] = useState(false);
if (props.warehouse === 0) return <></>;
// Upgrade Warehouse size button
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, props.warehouse.level + 1);
const canAffordUpgrade = props.corp.funds.gt(sizeUpgradeCost);
const upgradeWarehouseClass = canAffordUpgrade ? "std-button" : "a-link-button-inactive";
function upgradeWarehouseOnClick(): void {
if (props.division === null) return;
if (props.warehouse === 0) return;
++props.warehouse.level;
props.warehouse.updateSize(props.corp, props.division);
props.corp.funds = props.corp.funds.minus(sizeUpgradeCost);
props.rerender();
}
function openSmartSupplyPopup(): void {
if (props.warehouse === 0) return;
const popupId = "cmpy-mgmt-smart-supply-popup";
createPopup(popupId, SmartSupplyPopup, {
division: props.division,
warehouse: props.warehouse,
corp: props.corp,
player: props.player,
popupId: popupId,
});
}
const ratioLines = [];
for (const matName in props.division.reqMats) {
if (props.division.reqMats.hasOwnProperty(matName)) {
const text = [" *", props.division.reqMats[matName], matName].join(" ");
ratioLines.push(
<div key={matName}>
<p>{text}</p>
</div>,
);
}
}
// Current State:
let stateText;
switch (props.division.state) {
case "START":
stateText = "Current state: Preparing...";
break;
case "PURCHASE":
stateText = "Current state: Purchasing materials...";
break;
case "PRODUCTION":
stateText = "Current state: Producing materials and/or products...";
break;
case "SALE":
stateText = "Current state: Selling materials and/or products...";
break;
case "EXPORT":
stateText = "Current state: Exporting materials and/or products...";
break;
default:
console.error(`Invalid state: ${props.division.state}`);
break;
}
// Create React components for materials
const mats = [];
for (const matName in props.warehouse.materials) {
if (props.warehouse.materials[matName] instanceof Material) {
// Only create UI for materials that are relevant for the industry
if (isRelevantMaterial(matName, props.division)) {
mats.push(
<MaterialComponent
rerender={props.rerender}
city={props.currentCity}
corp={props.corp}
division={props.division}
key={matName}
mat={props.warehouse.materials[matName]}
warehouse={props.warehouse}
/>,
);
}
}
}
// Create React components for products
const products = [];
if (props.division.makesProducts && Object.keys(props.division.products).length > 0) {
for (const productName in props.division.products) {
const product = props.division.products[productName];
if (product instanceof Product) {
products.push(
<ProductComponent
rerender={props.rerender}
player={props.player}
city={props.currentCity}
corp={props.corp}
division={props.division}
key={productName}
product={product}
/>,
);
}
}
}
return (
<div className={"cmpy-mgmt-warehouse-panel"}>
<p className={"tooltip"} style={sizeUsageStyle}>
Storage: {numeralWrapper.formatBigNumber(props.warehouse.sizeUsed)} /{" "}
{numeralWrapper.formatBigNumber(props.warehouse.size)}
<span className={"tooltiptext"} dangerouslySetInnerHTML={{ __html: props.warehouse.breakdown }}></span>
</p>
<button className={upgradeWarehouseClass} onClick={upgradeWarehouseOnClick}>
Upgrade Warehouse Size - <MoneyCost money={sizeUpgradeCost} corp={props.corp} />
</button>
<p>This industry uses the following equation for it's production: </p>
<br />
<br />
<IndustryProductEquation division={props.division} />
<br />
<br />
<p>
To get started with production, purchase your required materials or import them from another of your company's
divisions.
</p>
<br />
<p>{stateText}</p>
{props.corp.unlockUpgrades[1] && (
<>
<button className="std-button" onClick={openSmartSupplyPopup}>
Configure Smart Supply
</button>
</>
)}
{mats}
{products}
</div>
);
}
function purchaseWarehouse(division: IIndustry, city: string): void {
PurchaseWarehouse(props.corp, division, city);
// Upgrade Warehouse size button
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, props.warehouse.level + 1);
const canAffordUpgrade = corp.funds.gt(sizeUpgradeCost);
function upgradeWarehouseOnClick(): void {
if (division === null) return;
if (props.warehouse === 0) return;
if (!canAffordUpgrade) return;
++props.warehouse.level;
props.warehouse.updateSize(corp, division);
corp.funds = corp.funds.minus(sizeUpgradeCost);
props.rerender();
}
if (props.warehouse instanceof Warehouse) {
return renderWarehouseUI();
} else {
return (
<div className={"cmpy-mgmt-warehouse-panel"}>
<button
className={"std-button"}
onClick={() => purchaseWarehouse(props.division, props.currentCity)}
disabled={props.corp.funds.lt(CorporationConstants.WarehouseInitialCost)}
>
Purchase Warehouse (
<MoneyCost money={CorporationConstants.WarehouseInitialCost} corp={props.corp} />)
</button>
</div>
const ratioLines = [];
for (const matName in division.reqMats) {
if (division.reqMats.hasOwnProperty(matName)) {
const text = [" *", division.reqMats[matName], matName].join(" ");
ratioLines.push(
<div key={matName}>
<p>{text}</p>
</div>,
);
}
}
// Current State:
let stateText;
switch (division.state) {
case "START":
stateText = "Current state: Preparing...";
break;
case "PURCHASE":
stateText = "Current state: Purchasing materials...";
break;
case "PRODUCTION":
stateText = "Current state: Producing materials and/or products...";
break;
case "SALE":
stateText = "Current state: Selling materials and/or products...";
break;
case "EXPORT":
stateText = "Current state: Exporting materials and/or products...";
break;
default:
console.error(`Invalid state: ${division.state}`);
break;
}
// Create React components for materials
const mats = [];
for (const matName in props.warehouse.materials) {
if (!(props.warehouse.materials[matName] instanceof Material)) continue;
// Only create UI for materials that are relevant for the industry
if (!isRelevantMaterial(matName, division)) continue;
mats.push(
<MaterialComponent
rerender={props.rerender}
city={props.currentCity}
key={matName}
mat={props.warehouse.materials[matName]}
warehouse={props.warehouse}
/>,
);
}
// Create React components for products
const products = [];
if (division.makesProducts && Object.keys(division.products).length > 0) {
for (const productName in division.products) {
const product = division.products[productName];
if (!(product instanceof Product)) continue;
products.push(
<ProductComponent
rerender={props.rerender}
player={props.player}
city={props.currentCity}
corp={corp}
division={division}
key={productName}
product={product}
/>,
);
}
}
let breakdown = <></>;
for (const matName in props.warehouse.materials) {
if (matName === "RealEstate") continue;
const mat = props.warehouse.materials[matName];
if (!MaterialSizes.hasOwnProperty(matName)) continue;
if (mat.qty === 0) continue;
breakdown = (
<>
{breakdown}
{matName}: {numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0")}
<br />
</>
);
}
return (
<div className={"cmpy-mgmt-warehouse-panel"}>
<Box display="flex" alignItems="center">
<Tooltip title={props.warehouse.sizeUsed !== 0 ? breakdown : ""}>
<Typography color={props.warehouse.sizeUsed >= props.warehouse.size ? "error" : "primary"}>
Storage: {numeralWrapper.formatBigNumber(props.warehouse.sizeUsed)} /{" "}
{numeralWrapper.formatBigNumber(props.warehouse.size)}
</Typography>
</Tooltip>
<Button disabled={!canAffordUpgrade} onClick={upgradeWarehouseOnClick}>
Upgrade Warehouse Size -&nbsp;
<MoneyCost money={sizeUpgradeCost} corp={corp} />
</Button>
</Box>
<Typography>This industry uses the following equation for it's production: </Typography>
<br />
<Typography>
<IndustryProductEquation division={division} />
</Typography>
<br />
<Typography>
To get started with production, purchase your required materials or import them from another of your company's
divisions.
</Typography>
<br />
<Typography>{stateText}</Typography>
{corp.unlockUpgrades[1] && (
<>
<Button onClick={() => setSmartSupplyOpen(true)}>Configure Smart Supply</Button>
<SmartSupplyModal
open={smartSupplyOpen}
onClose={() => setSmartSupplyOpen(false)}
warehouse={props.warehouse}
/>
</>
)}
{mats}
{products}
</div>
);
}
export function IndustryWarehouse(props: IProps): React.ReactElement {
if (props.warehouse instanceof Warehouse) {
return <WarehouseRoot {...props} />;
} else {
return <EmptyWarehouse rerender={props.rerender} city={props.currentCity} />;
}
}
interface IEmptyProps {
city: string;
rerender: () => void;
}
function EmptyWarehouse(props: IEmptyProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const disabled = corp.funds.lt(CorporationConstants.WarehouseInitialCost);
function purchaseWarehouse(): void {
if (disabled) return;
PurchaseWarehouse(corp, division, props.city);
props.rerender();
}
return (
<Paper>
<Button onClick={purchaseWarehouse} disabled={disabled}>
Purchase Warehouse (
<MoneyCost money={CorporationConstants.WarehouseInitialCost} corp={corp} />)
</Button>
</Paper>
);
}

@ -25,9 +25,7 @@ export function MainPanel(props: IProps): React.ReactElement {
if (division === undefined) throw new Error("Cannot find division");
return (
<Context.Division.Provider value={division}>
<div id="cmpy-mgmt-panel">
<CityTabs rerender={props.rerender} city={CityName.Sector12} />
</div>
<CityTabs rerender={props.rerender} city={CityName.Sector12} />
</Context.Division.Provider>
);
}

@ -0,0 +1,193 @@
import React, { useState } from "react";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { Modal } from "../../ui/React/Modal";
import { Industries } from "../IndustryData";
import { MakeProduct } from "../Actions";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
interface IProps {
open: boolean;
onClose: () => void;
}
function productPlaceholder(tpe: string): string {
if (tpe === Industries.Food) {
return "Restaurant Name";
} else if (tpe === Industries.Healthcare) {
return "Hospital Name";
} else if (tpe === Industries.RealEstate) {
return "Property Name";
}
return "Product Name";
}
// Create a popup that lets the player create a product for their current industry
export function MakeProductModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const allCities = Object.keys(division.offices).filter((cityName: string) => division.offices[cityName] !== 0);
const [city, setCity] = useState(allCities.length > 0 ? allCities[0] : "");
const [name, setName] = useState("");
const [design, setDesign] = useState<number | null>(null);
const [marketing, setMarketing] = useState<number | null>(null);
if (division.hasMaximumNumberProducts()) return <></>;
let createProductPopupText = <></>;
switch (division.type) {
case Industries.Food:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Build and manage a new restaurant!
</>
);
break;
case Industries.Tobacco:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Create a new tobacco product!
</>
);
break;
case Industries.Pharmaceutical:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Design and develop a new pharmaceutical drug!
</>
);
break;
case Industries.Computer:
case "Computer":
createProductPopupText = (
<>
{createProductPopupText}
<br />
Design and manufacture a new computer hardware product!
</>
);
break;
case Industries.Robotics:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Design and create a new robot or robotic system!
</>
);
break;
case Industries.Software:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Develop a new piece of software!
</>
);
break;
case Industries.Healthcare:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Build and manage a new hospital!
</>
);
break;
case Industries.RealEstate:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Develop a new piece of real estate property!
</>
);
break;
default:
createProductPopupText = (
<>
{createProductPopupText}
<br />
Create a new product!
</>
);
return <></>;
}
createProductPopupText = (
<>
{createProductPopupText}
<br />
<br />
To begin developing a product, first choose the city in which it will be designed. The stats of your employees in
the selected city affect the properties of the finished product, such as its quality, performance, and durability.
<br />
<br />
You can also choose to invest money in the design and marketing of the product. Investing money in its design will
result in a superior product. Investing money in marketing the product will help the product's sales.
</>
);
function makeProduct(): void {
if (design === null || marketing === null) return;
try {
MakeProduct(corp, division, city, name, design, marketing);
} catch (err) {
dialogBoxCreate(err + "");
}
props.onClose();
}
function onCityChange(event: SelectChangeEvent<string>): void {
setCity(event.target.value);
}
function onProductNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
setName(event.target.value);
}
function onDesignChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.target.value === "") setDesign(null);
else setDesign(parseFloat(event.target.value));
}
function onMarketingChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.target.value === "") setMarketing(null);
else setMarketing(parseFloat(event.target.value));
}
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
if (event.keyCode === 13) makeProduct();
}
return (
<Modal open={props.open} onClose={props.onClose}>
<Typography>{createProductPopupText}</Typography>
<Select style={{ margin: "5px" }} onChange={onCityChange} defaultValue={city}>
{allCities.map((cityName: string) => (
<MenuItem key={cityName} value={cityName}>
{cityName}
</MenuItem>
))}
</Select>
<TextField onChange={onProductNameChange} placeholder={productPlaceholder(division.type)} />
<br />
<TextField onChange={onDesignChange} autoFocus={true} type="number" placeholder={"Design investment"} />
<TextField
onChange={onMarketingChange}
onKeyDown={onKeyDown}
type="number"
placeholder={"Marketing investment"}
/>
<Button onClick={makeProduct}>Develop Product</Button>
</Modal>
);
}

@ -1,108 +0,0 @@
import React, { useState } from "react";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { removePopup } from "../../ui/React/createPopup";
import { Industries } from "../IndustryData";
import { ICorporation } from "../ICorporation";
import { IIndustry } from "../IIndustry";
import { MakeProduct } from "../Actions";
interface IProps {
popupText: string;
division: IIndustry;
corp: ICorporation;
popupId: string;
}
function productPlaceholder(tpe: string): string {
if (tpe === Industries.Food) {
return "Restaurant Name";
} else if (tpe === Industries.Healthcare) {
return "Hospital Name";
} else if (tpe === Industries.RealEstate) {
return "Property Name";
}
return "Product Name";
}
// Create a popup that lets the player create a product for their current industry
export function MakeProductPopup(props: IProps): React.ReactElement {
const allCities = Object.keys(props.division.offices).filter(
(cityName: string) => props.division.offices[cityName] !== 0,
);
const [city, setCity] = useState(allCities.length > 0 ? allCities[0] : "");
const [name, setName] = useState("");
const [design, setDesign] = useState<number | null>(null);
const [marketing, setMarketing] = useState<number | null>(null);
if (props.division.hasMaximumNumberProducts()) return <></>;
function makeProduct(): void {
if (design === null || marketing === null) return;
try {
MakeProduct(props.corp, props.division, city, name, design, marketing);
} catch (err) {
dialogBoxCreate(err + "");
}
removePopup(props.popupId);
}
function onCityChange(event: React.ChangeEvent<HTMLSelectElement>): void {
setCity(event.target.value);
}
function onProductNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
setName(event.target.value);
}
function onDesignChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.target.value === "") setDesign(null);
else setDesign(parseFloat(event.target.value));
}
function onMarketingChange(event: React.ChangeEvent<HTMLInputElement>): void {
if (event.target.value === "") setMarketing(null);
else setMarketing(parseFloat(event.target.value));
}
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
if (event.keyCode === 13) makeProduct();
}
return (
<>
<p dangerouslySetInnerHTML={{ __html: props.popupText }} />
<select className="dropdown" style={{ margin: "5px" }} onChange={onCityChange} defaultValue={city}>
{allCities.map((cityName: string) => (
<option key={cityName} value={cityName}>
{cityName}
</option>
))}
</select>
<input
onChange={onProductNameChange}
className="text-input"
style={{ margin: "5px" }}
placeholder={productPlaceholder(props.division.type)}
/>
<br />
<input
onChange={onDesignChange}
autoFocus={true}
type="number"
className="text-input"
style={{ margin: "5px" }}
placeholder={"Design investment"}
/>
<input
onChange={onMarketingChange}
onKeyDown={onKeyDown}
type="number"
className="text-input"
style={{ margin: "5px" }}
placeholder={"Marketing investment"}
/>
<button className="std-button" onClick={makeProduct}>
Develop Product
</button>
</>
);
}

@ -6,6 +6,7 @@ import { CorporationConstants } from "../data/Constants";
import { Treant } from "treant-js";
import { IIndustry } from "../IIndustry";
import { Research } from "../Actions";
import Typography from "@mui/material/Typography";
interface IProps {
industry: IIndustry;

@ -1,12 +1,14 @@
import React, { useState } from "react";
import { Warehouse } from "../Warehouse";
import { ICorporation } from "../ICorporation";
import { IIndustry } from "../IIndustry";
import { SetSmartSupply, SetSmartSupplyUseLeftovers } from "../Actions";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Material } from "../Material";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { Modal } from "../../ui/React/Modal";
import { useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
interface ILeftoverProps {
matName: string;
@ -26,33 +28,31 @@ function Leftover(props: ILeftoverProps): React.ReactElement {
setChecked(event.target.checked);
}
const matNameId = `${props.matName}-use-leftovers`;
return (
<div key={props.matName}>
<label style={{ color: "white" }} htmlFor={matNameId}>
{props.warehouse.materials[props.matName].name}
</label>
<input type={"checkbox"} id={matNameId} onChange={onChange} style={{ margin: "3px" }} checked={checked} />
<>
<FormControlLabel
control={<Switch checked={checked} onChange={onChange} />}
label={<Typography>{props.warehouse.materials[props.matName].name}</Typography>}
/>
<br />
</div>
</>
);
}
interface IProps {
division: IIndustry;
open: boolean;
onClose: () => void;
warehouse: Warehouse;
corp: ICorporation;
player: IPlayer;
popupId: string;
}
export function SmartSupplyPopup(props: IProps): React.ReactElement {
export function SmartSupplyModal(props: IProps): React.ReactElement {
const division = useDivision();
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
}
// Smart Supply Checkbox
const smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
function smartSupplyOnChange(e: React.ChangeEvent<HTMLInputElement>): void {
SetSmartSupply(props.warehouse, e.target.checked);
rerender();
@ -62,25 +62,21 @@ export function SmartSupplyPopup(props: IProps): React.ReactElement {
const mats = [];
for (const matName in props.warehouse.materials) {
if (!(props.warehouse.materials[matName] instanceof Material)) continue;
if (!Object.keys(props.division.reqMats).includes(matName)) continue;
if (!Object.keys(division.reqMats).includes(matName)) continue;
mats.push(<Leftover key={matName} warehouse={props.warehouse} matName={matName} />);
}
return (
<>
<label style={{ color: "white" }} htmlFor={smartSupplyCheckboxId}>
Enable Smart Supply
</label>
<input
type={"checkbox"}
id={smartSupplyCheckboxId}
onChange={smartSupplyOnChange}
style={{ margin: "3px" }}
checked={props.warehouse.smartSupplyEnabled}
/>
<br />
<p>Use materials already in the warehouse instead of buying new ones, if available:</p>
{mats}
</>
<Modal open={props.open} onClose={props.onClose}>
<>
<FormControlLabel
control={<Switch checked={props.warehouse.smartSupplyEnabled} onChange={smartSupplyOnChange} />}
label={<Typography>Enable Smart Supply</Typography>}
/>
<br />
<Typography>Use materials already in the warehouse instead of buying new ones, if available:</Typography>
{mats}
</>
</Modal>
);
}

@ -0,0 +1,16 @@
import React from "react";
import { Modal } from "./Modal";
interface IProps {
open: boolean;
onClose: () => void;
children: JSX.Element[] | JSX.Element | React.ReactElement[] | React.ReactElement;
}
export function StaticModal(props: IProps): React.ReactElement {
return (
<Modal open={props.open} onClose={props.onClose}>
{props.children}
</Modal>
);
}