CORPORATION: UI to display production and sales multipliers (#838)

This commit is contained in:
Jesse Clark 2023-10-07 20:22:28 -07:00 committed by GitHub
parent 269a74d5c0
commit 2f40b66789
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 186 additions and 98 deletions

@ -3,11 +3,11 @@
import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { CorpUnlockName, CorpEmployeeJob } from "@enums";
import { CorpUnlockName, CorpEmployeeJob, CorpUpgradeName, CorpProductResearchName } from "@enums";
import { BuyTea } from "../Actions";
import { MoneyCost } from "./MoneyCost";
import { formatCorpStat } from "../../ui/formatNumber";
import { formatBigNumber, formatCorpStat, formatCorpMultiplier } from "../../ui/formatNumber";
import { UpgradeOfficeSizeModal } from "./modals/UpgradeOfficeSizeModal";
import { ThrowPartyModal } from "./modals/ThrowPartyModal";
@ -27,6 +27,7 @@ import TableBody from "@mui/material/TableBody";
import TableRow from "@mui/material/TableRow";
import { TableCell } from "../../ui/React/Table";
import { Box } from "@mui/material";
import { StatsTable } from "../../ui/React/StatsTable";
interface OfficeProps {
office: OfficeSpace;
@ -98,6 +99,60 @@ function AutoManagement(props: OfficeProps): React.ReactElement {
const currUna = props.office.employeeJobs[CorpEmployeeJob.Unassigned];
const nextUna = props.office.employeeNextJobs[CorpEmployeeJob.Unassigned];
const totalMaterialProduction =
division.getOfficeProductivity(props.office) *
corp.getProductionMultiplier() *
division.productionMult *
division.getProductionMultiplier();
const materialBreakdown = (
<StatsTable
rows={[
["Employee Production:", formatBigNumber(division.getOfficeProductivity(props.office, { forProduct: false }))],
["Boosting Materials:", formatCorpMultiplier(division.productionMult)],
["Research:", formatCorpMultiplier(division.getProductionMultiplier())],
[`${CorpUpgradeName.SmartFactories}:`, formatCorpMultiplier(corp.getProductionMultiplier())],
[<b key={1}>Total Material Production:</b>, <b key={2}>{formatCorpStat(totalMaterialProduction)}</b>],
]}
/>
);
const totalProductProduction =
division.getOfficeProductivity(props.office, { forProduct: true }) *
corp.getProductionMultiplier() *
division.productionMult *
division.getProductionMultiplier() *
division.getProductProductionMultiplier();
const productBreakdown = (
<StatsTable
rows={[
["Employee Production:", formatBigNumber(division.getOfficeProductivity(props.office, { forProduct: true }))],
["Boosting Materials:", formatCorpMultiplier(division.productionMult)],
["Research:", formatCorpMultiplier(division.getProductionMultiplier())],
[`${CorpProductResearchName.Fulcrum}:`, formatCorpMultiplier(division.getProductProductionMultiplier())],
[`${CorpUpgradeName.SmartFactories}:`, formatCorpMultiplier(corp.getProductionMultiplier())],
[<b key={1}>Total Product Production:</b>, <b key={2}>{formatCorpStat(totalProductProduction)}</b>],
]}
/>
);
// Sale multipliers
const businessFactor = division.getBusinessFactor(props.office); //Business employee productivity
const [adsTotal] = division.getAdvertisingFactors(); //Awareness + popularity
const researchMult = division.getSalesMultiplier();
const upgradeMult = corp.getSalesMult();
const totalSaleMultiplier = businessFactor * adsTotal * researchMult * upgradeMult;
const salesBreakdown = (
<StatsTable
rows={[
["Business Employees:", formatCorpMultiplier(businessFactor)],
["Advertising:", formatCorpMultiplier(adsTotal)],
researchMult !== 1 ? ["Research:", formatCorpMultiplier(researchMult)] : [],
[`${CorpUpgradeName.ABCSalesBots}:`, formatCorpMultiplier(upgradeMult)],
[<b key={1}>Total Sales Multiplier:</b>, <b key={2}>{formatCorpMultiplier(totalSaleMultiplier)}</b>],
]}
/>
);
return (
<Table padding="none">
<TableBody>
@ -149,10 +204,12 @@ function AutoManagement(props: OfficeProps): React.ReactElement {
<TableCell>
<Tooltip
title={
<Typography>
The base amount of material this office can produce. Does not include production multipliers from
upgrades and materials. This value is based off the productivity of your Operations, Engineering,
and Management employees
<Typography component="div">
The amount of material this office can produce.
<br />
This value is based off the productivity of your
<br />
Operations, Engineering, and Management employees.
</Typography>
}
>
@ -160,39 +217,55 @@ function AutoManagement(props: OfficeProps): React.ReactElement {
</Tooltip>
</TableCell>
<TableCell>
<Typography align="right">{formatCorpStat(division.getOfficeProductivity(props.office))}</Typography>
<Tooltip title={materialBreakdown}>
<Typography align="right">{formatCorpStat(totalMaterialProduction)}</Typography>
</Tooltip>
</TableCell>
</TableRow>
{division.makesProducts ? (
<TableRow>
<TableCell>
<Tooltip
title={
<Typography component="div">
The amount of any given Product this office can produce.
<br />
This value is based off the productivity of your
<br />
Operations, Engineering, and Management employees.
</Typography>
}
>
<Typography>Product Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Tooltip title={productBreakdown}>
<Typography align="right">{formatCorpStat(totalProductProduction)}</Typography>
</Tooltip>
</TableCell>
</TableRow>
) : null}
<TableRow>
<TableCell>
<Tooltip
title={
<Typography>
The base amount of any given Product this office can produce. Does not include production
multipliers from upgrades and materials. This value is based off the productivity of your
Operations, Engineering, and Management employees
This office's sales effectivity for all materials and products.
<br />
It is based on your Business employees and your advertising.
<br />
This will be further modified by demand and competition for each item.
</Typography>
}
>
<Typography>Product Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography align="right">
{formatCorpStat(division.getOfficeProductivity(props.office, { forProduct: true }))}
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Tooltip
title={<Typography>The effect this office's 'Business' employees has on boosting sales</Typography>}
>
<Typography> Business Multiplier:</Typography>
<Typography>Sales Multiplier:</Typography>
</Tooltip>
</TableCell>
<TableCell align="right">
<Typography>x{formatCorpStat(division.getBusinessFactor(props.office))}</Typography>
<Tooltip title={salesBreakdown}>
<Typography>{formatCorpMultiplier(totalSaleMultiplier)}</Typography>
</Tooltip>
</TableCell>
</TableRow>
</>

@ -1,10 +1,11 @@
// React Component for displaying an Division's overview information
// (top-left panel in the Division UI)
import React, { useState } from "react";
import { MathJax } from "better-react-mathjax";
import { CorpUnlockName, IndustryType } from "@enums";
import { HireAdVert } from "../Actions";
import { formatBigNumber } from "../../ui/formatNumber";
import { formatBigNumber, formatCorpMultiplier } from "../../ui/formatNumber";
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
import { MakeProductModal } from "./modals/MakeProductModal";
import { ResearchModal } from "./modals/ResearchModal";
@ -134,18 +135,23 @@ export function DivisionOverview(props: DivisionOverviewProps): React.ReactEleme
<Tooltip
title={
<>
<Typography>Total multiplier for this industry's sales due to its awareness and popularity</Typography>
<Typography>Multiplier for this industry's sales due to its awareness and popularity.</Typography>
<br />
<MathJax>{`\\(\\text{${division.type} Industry: }\\alpha = ${division.advertisingFactor}\\)`}</MathJax>
<MathJax>{`\\(\\text{multiplier} = \\left((\\text{awareness}+1)^{\\alpha} \\times (\\text{popularity}+1)^{\\alpha} \\times \\frac{\\text{popularity}+0.001}{\\text{awareness}}\\right)^{0.85}\\)`}</MathJax>
<br />
<StatsTable
rows={[
["Awareness Bonus:", "x" + formatBigNumber(Math.pow(awarenessFac, 0.85))],
["Popularity Bonus:", "x" + formatBigNumber(Math.pow(popularityFac, 0.85))],
["Ratio Multiplier:", "x" + formatBigNumber(Math.pow(ratioFac, 0.85))],
["Awareness Bonus:", formatCorpMultiplier(Math.pow(awarenessFac, 0.85))],
["Popularity Bonus:", formatCorpMultiplier(Math.pow(popularityFac, 0.85))],
["Ratio Multiplier:", formatCorpMultiplier(Math.pow(ratioFac, 0.85))],
[<b key={1}>Total:</b>, <b key={2}>{formatCorpMultiplier(totalAdvertisingFac)}</b>],
]}
/>
</>
}
>
<Typography>Advertising Multiplier: x{formatBigNumber(totalAdvertisingFac)}</Typography>
<Typography>Advertising Multiplier: {formatCorpMultiplier(totalAdvertisingFac)}</Typography>
</Tooltip>
)}
<br />
@ -161,12 +167,13 @@ export function DivisionOverview(props: DivisionOverviewProps): React.ReactEleme
<Tooltip
title={
<>
Production gain from owning production-boosting materials such as hardware, Robots, AI Cores, and Real
Estate.
Production gain from owning production-boosting materials such as
<br />
hardware, Robots, AI Cores, and Real Estate.
</>
}
>
<Typography>Production Multiplier: {formatBigNumber(division.productionMult)}</Typography>
<Typography>Production Multiplier: {formatCorpMultiplier(division.productionMult)}</Typography>
</Tooltip>
<IconButton onClick={() => setHelpOpen(true)}>
<HelpIcon />
@ -211,10 +218,10 @@ export function DivisionOverview(props: DivisionOverviewProps): React.ReactEleme
<ButtonWithTooltip
normalTooltip={
<>
Hire AdVert.Inc to advertise your company. Each level of this upgrade grants your company a static
increase of 3 and 1 to its awareness and popularity, respectively. It will then increase your company's" +
awareness by 1%, and its popularity by a random percentage between 1% and 3%. These effects are increased
by other upgrades that increase the power of your advertising.
Hire <b>AdVert.Inc</b> to advertise your company. Each level of this upgrade grants your company a static
increase of 3 and 1 to its awareness and popularity, respectively. It will then increase your company's
awareness by 0.5%, and its popularity by a random percentage between 0.5% and 1.5%. These effects are
increased by other upgrades that increase the power of your advertising.
</>
}
disabledTooltip={division.getAdVertCost() > corp.funds ? "Insufficient corporation funds" : ""}

@ -13,6 +13,7 @@ import { isString } from "../../utils/helpers/string";
import { Money } from "../../ui/React/Money";
import { useCorporation, useDivision } from "./Context";
import { LimitMaterialProductionModal } from "./modals/LimitMaterialProductionModal";
import { StatsTable } from "../../ui/React/StatsTable";
interface IMaterialProps {
warehouse: Warehouse;
@ -79,33 +80,26 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
limitMaterialButtonText += " (" + formatCorpStat(mat.productionLimit) + ")";
}
// Material Gain details
const gainBreakdown = [
["Buy:", mat.buyAmount >= 1e33 ? mat.buyAmount.toExponential(3) : formatBigNumber(mat.buyAmount)],
["Prod:", formatBigNumber(mat.productionAmount)],
["Import:", formatBigNumber(mat.importAmount)],
["Export:", formatBigNumber(-mat.exportedLastCycle || 0)],
["Sell:", formatBigNumber(-mat.actualSellAmount || 0)],
];
if (corp.unlocks.has(CorpUnlockName.MarketResearchDemand)) {
gainBreakdown.push(["Demand:", formatCorpStat(mat.demand)]);
}
if (corp.unlocks.has(CorpUnlockName.MarketDataCompetition)) {
gainBreakdown.push(["Competition:", formatCorpStat(mat.competition)]);
}
return (
<Paper>
<Box sx={{ display: "grid", gridTemplateColumns: "2fr 1fr", m: "5px" }}>
<Box>
<Tooltip
title={
<Typography>
Buy: {mat.buyAmount >= 1e33 ? mat.buyAmount.toExponential(3) : formatBigNumber(mat.buyAmount)} <br />
Prod: {formatBigNumber(mat.productionAmount)} <br />
Sell: {formatBigNumber(mat.actualSellAmount)} <br />
Export: {formatBigNumber(mat.exportedLastCycle)} <br />
Import: {formatBigNumber(mat.importAmount)}
{corp.unlocks.has(CorpUnlockName.MarketResearchDemand) && (
<>
<br />
Demand: {formatCorpStat(mat.demand)}
</>
)}
{corp.unlocks.has(CorpUnlockName.MarketDataCompetition) && (
<>
<br />
Competition: {formatCorpStat(mat.competition)}
</>
)}
</Typography>
}
>
<Tooltip title={<StatsTable rows={gainBreakdown} />}>
<Typography>
{mat.name}: {formatBigNumber(mat.stored)} (
{totalGain >= 1e33 ? totalGain.toExponential(3) : formatBigNumber(totalGain)}/s)

@ -15,7 +15,7 @@ import * as corpConstants from "../data/Constants";
import { CorpUnlocks } from "../data/CorporationUnlocks";
import { CONSTANTS } from "../../Constants";
import { formatCorpStat, formatPercent, formatShares } from "../../ui/formatNumber";
import { formatCorpMultiplier, formatPercent, formatShares } from "../../ui/formatNumber";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { Money } from "../../ui/React/Money";
import { MoneyRate } from "../../ui/React/MoneyRate";
@ -45,7 +45,7 @@ export function Overview({ rerender }: IProps): React.ReactElement {
const multRows: string[][] = [];
function appendMult(name: string, value: number): void {
if (value === 1) return;
multRows.push([name, formatCorpStat(value)]);
multRows.push([name, formatCorpMultiplier(value)]);
}
appendMult("Production Multiplier: ", corp.getProductionMultiplier());
appendMult("Storage Multiplier: ", corp.getStorageMultiplier());
@ -79,18 +79,18 @@ export function Overview({ rerender }: IProps): React.ReactElement {
rows={[
[
"Owned Stock Shares:",
<>&nbsp;{formatShares(corp.numShares)}&nbsp;</>,
<>({formatPercent(corp.numShares / corp.totalShares)})</>,
formatShares(corp.numShares),
`(${formatPercent(corp.numShares / corp.totalShares)})`,
],
[
"Outstanding Shares:",
<>&nbsp;{formatShares(corp.issuedShares)}&nbsp;</>,
<>({formatPercent(corp.issuedShares / corp.totalShares)})</>,
formatShares(corp.issuedShares),
`(${formatPercent(corp.issuedShares / corp.totalShares)})`,
],
[
"Private Shares:",
<>&nbsp;{formatShares(corp.investorShares)}&nbsp;</>,
<>({formatPercent(corp.investorShares / corp.totalShares)})</>,
formatShares(corp.investorShares),
`(${formatPercent(corp.investorShares / corp.totalShares)})`,
],
]}
/>

@ -13,6 +13,7 @@ import { formatBigNumber, formatPercent } from "../../ui/formatNumber";
import { isString } from "../../utils/helpers/string";
import { Money } from "../../ui/React/Money";
import { useCorporation, useDivision } from "./Context";
import { StatsTable } from "../../ui/React/StatsTable";
interface IProductProps {
city: CityName;
@ -89,11 +90,12 @@ export function ProductElem(props: IProductProps): React.ReactElement {
<Box display="flex">
<Tooltip
title={
<Typography>
Prod: {formatBigNumber(product.cityData[city].productionAmount)}/s
<br />
Sell: {formatBigNumber(product.cityData[city].actualSellAmount)} /s
</Typography>
<StatsTable
rows={[
["Prod:", formatBigNumber(product.cityData[city].productionAmount)],
["Sell:", formatBigNumber(-product.cityData[city].actualSellAmount || 0)],
]}
/>
}
>
<Typography>

@ -1,5 +1,8 @@
import React, { useState } from "react";
import { Modal } from "../../../ui/React/Modal";
import { StatsTable } from "../../../ui/React/StatsTable";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { formatCorpMultiplier } from "../../../ui/formatNumber";
import { IndustryResearchTrees } from "../../data/IndustryData";
import * as corpConstants from "../../data/Constants";
import { Division } from "../../Division";
@ -7,7 +10,7 @@ import { Research } from "../../Actions";
import { Node } from "../../ResearchTree";
import { ResearchMap } from "../../ResearchMap";
import { Settings } from "../../../Settings/Settings";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import Button from "@mui/material/Button";
@ -144,15 +147,19 @@ export function ResearchModal(props: IProps): React.ReactElement {
Research points: {props.industry.researchPoints.toFixed(3)}
<br />
Multipliers from research:
<br />* Advertising Multiplier: x{researchTree.getAdvertisingMultiplier()}
<br />* Employee Charisma Multiplier: x{researchTree.getEmployeeChaMultiplier()}
<br />* Employee Creativity Multiplier: x{researchTree.getEmployeeCreMultiplier()}
<br />* Employee Efficiency Multiplier: x{researchTree.getEmployeeEffMultiplier()}
<br />* Employee Intelligence Multiplier: x{researchTree.getEmployeeIntMultiplier()}
<br />* Production Multiplier: x{researchTree.getProductionMultiplier()}
<br />* Sales Multiplier: x{researchTree.getSalesMultiplier()}
<br />* Scientific Research Multiplier: x{researchTree.getScientificResearchMultiplier()}
<br />* Storage Multiplier: x{researchTree.getStorageMultiplier()}
<StatsTable
rows={[
["Advertising Multiplier:", formatCorpMultiplier(researchTree.getAdvertisingMultiplier())],
["Employee Charisma Multiplier:", formatCorpMultiplier(researchTree.getEmployeeChaMultiplier())],
["Employee Creativity Multiplier:", formatCorpMultiplier(researchTree.getEmployeeCreMultiplier())],
["Employee Efficiency Multiplier:", formatCorpMultiplier(researchTree.getEmployeeEffMultiplier())],
["Employee Intelligence Multiplier:", formatCorpMultiplier(researchTree.getEmployeeIntMultiplier())],
["Production Multiplier:", formatCorpMultiplier(researchTree.getProductionMultiplier())],
["Sales Multiplier:", formatCorpMultiplier(researchTree.getSalesMultiplier())],
["Scientific Research Multiplier:", formatCorpMultiplier(researchTree.getScientificResearchMultiplier())],
["Storage Multiplier:", formatCorpMultiplier(researchTree.getStorageMultiplier())],
]}
/>
</Typography>
</Modal>
);

@ -1,29 +1,33 @@
import React from "react";
import React, { ReactNode, ReactElement } from "react";
import { Table, TableCell } from "./Table";
import TableBody from "@mui/material/TableBody";
import { Table as MuiTable } from "@mui/material";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import { TableBody, TableRow, Table as MuiTable, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
interface IProps {
rows: React.ReactNode[][];
interface StatsTableProps {
rows: ReactNode[][];
title?: string;
wide?: boolean;
}
export function StatsTable({ rows, title, wide }: IProps): React.ReactElement {
const useStyles = makeStyles({
firstCell: { textAlign: "left" },
nonFirstCell: { textAlign: "right", paddingLeft: "0.5em" },
});
export function StatsTable({ rows, title, wide }: StatsTableProps): ReactElement {
const T = wide ? MuiTable : Table;
const classes = useStyles();
return (
<>
{title && <Typography>{title}</Typography>}
<T size="small" padding="none">
<TableBody>
{rows.map((row: React.ReactNode[], i: number) => (
<TableRow key={i}>
{row.map((elem: React.ReactNode, i: number) => (
<TableCell key={i} align={i !== 0 ? "right" : "left"}>
<Typography noWrap>{elem}</Typography>
{rows.map((row, rowIndex) => (
<TableRow key={rowIndex}>
{row.map((cell, cellIndex) => (
<TableCell key={cellIndex} className={cellIndex === 0 ? classes.firstCell : classes.nonFirstCell}>
<Typography noWrap>{cell}</Typography>
</TableCell>
))}
</TableRow>

@ -151,6 +151,7 @@ export const formatPopulation = formatBigNumber;
export const formatSecurity = formatBigNumber;
export const formatStamina = formatBigNumber;
export const formatStaneksGiftCharge = formatBigNumber;
export const formatCorpMultiplier = (n: number) => "×" + formatBigNumber(n);
/** Format a number with suffixes starting at 1000 and 2 fractional digits */
export const formatQuality = (n: number) => formatNumber(n, 2);