From 2f40b667898c6608c0523216d477153c4534539b Mon Sep 17 00:00:00 2001 From: Jesse Clark Date: Sat, 7 Oct 2023 20:22:28 -0700 Subject: [PATCH] CORPORATION: UI to display production and sales multipliers (#838) --- src/Corporation/ui/DivisionOffice.tsx | 125 ++++++++++++++++---- src/Corporation/ui/DivisionOverview.tsx | 33 ++++-- src/Corporation/ui/MaterialElem.tsx | 40 +++---- src/Corporation/ui/Overview.tsx | 16 +-- src/Corporation/ui/ProductElem.tsx | 12 +- src/Corporation/ui/modals/ResearchModal.tsx | 27 +++-- src/ui/React/StatsTable.tsx | 30 +++-- src/ui/formatNumber.ts | 1 + 8 files changed, 186 insertions(+), 98 deletions(-) diff --git a/src/Corporation/ui/DivisionOffice.tsx b/src/Corporation/ui/DivisionOffice.tsx index 7a59e5673..84eafd54a 100644 --- a/src/Corporation/ui/DivisionOffice.tsx +++ b/src/Corporation/ui/DivisionOffice.tsx @@ -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 = ( + Total Material Production:, {formatCorpStat(totalMaterialProduction)}], + ]} + /> + ); + + const totalProductProduction = + division.getOfficeProductivity(props.office, { forProduct: true }) * + corp.getProductionMultiplier() * + division.productionMult * + division.getProductionMultiplier() * + division.getProductProductionMultiplier(); + const productBreakdown = ( + Total Product Production:, {formatCorpStat(totalProductProduction)}], + ]} + /> + ); + + // 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 = ( + Total Sales Multiplier:, {formatCorpMultiplier(totalSaleMultiplier)}], + ]} + /> + ); + return ( @@ -149,10 +204,12 @@ function AutoManagement(props: OfficeProps): React.ReactElement { - 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 + + The amount of material this office can produce. +
+ This value is based off the productivity of your +
+ Operations, Engineering, and Management employees.
} > @@ -160,39 +217,55 @@ function AutoManagement(props: OfficeProps): React.ReactElement {
- {formatCorpStat(division.getOfficeProductivity(props.office))} + + {formatCorpStat(totalMaterialProduction)} + + {division.makesProducts ? ( + + + + The amount of any given Product this office can produce. +
+ This value is based off the productivity of your +
+ Operations, Engineering, and Management employees. + + } + > + Product Production: +
+
+ + + {formatCorpStat(totalProductProduction)} + + +
+ ) : null} - 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. +
+ It is based on your Business employees and your advertising. +
+ This will be further modified by demand and competition for each item. } > - Product Production: -
-
- - - {formatCorpStat(division.getOfficeProductivity(props.office, { forProduct: true }))} - - -
- - - The effect this office's 'Business' employees has on boosting sales} - > - Business Multiplier: + Sales Multiplier: - x{formatCorpStat(division.getBusinessFactor(props.office))} + + {formatCorpMultiplier(totalSaleMultiplier)} + diff --git a/src/Corporation/ui/DivisionOverview.tsx b/src/Corporation/ui/DivisionOverview.tsx index 1caec8606..1360d58f8 100644 --- a/src/Corporation/ui/DivisionOverview.tsx +++ b/src/Corporation/ui/DivisionOverview.tsx @@ -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 - Total multiplier for this industry's sales due to its awareness and popularity + Multiplier for this industry's sales due to its awareness and popularity. +
+ {`\\(\\text{${division.type} Industry: }\\alpha = ${division.advertisingFactor}\\)`} + {`\\(\\text{multiplier} = \\left((\\text{awareness}+1)^{\\alpha} \\times (\\text{popularity}+1)^{\\alpha} \\times \\frac{\\text{popularity}+0.001}{\\text{awareness}}\\right)^{0.85}\\)`} +
Total:, {formatCorpMultiplier(totalAdvertisingFac)}], ]} /> } > - Advertising Multiplier: x{formatBigNumber(totalAdvertisingFac)} + Advertising Multiplier: {formatCorpMultiplier(totalAdvertisingFac)}
)}
@@ -161,12 +167,13 @@ export function DivisionOverview(props: DivisionOverviewProps): React.ReactEleme - 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 +
+ hardware, Robots, AI Cores, and Real Estate. } > - Production Multiplier: {formatBigNumber(division.productionMult)} + Production Multiplier: {formatCorpMultiplier(division.productionMult)}
setHelpOpen(true)}> @@ -211,10 +218,10 @@ export function DivisionOverview(props: DivisionOverviewProps): React.ReactEleme - 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 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 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" : ""} diff --git a/src/Corporation/ui/MaterialElem.tsx b/src/Corporation/ui/MaterialElem.tsx index 46a377e71..60c0933ce 100644 --- a/src/Corporation/ui/MaterialElem.tsx +++ b/src/Corporation/ui/MaterialElem.tsx @@ -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 ( - - Buy: {mat.buyAmount >= 1e33 ? mat.buyAmount.toExponential(3) : formatBigNumber(mat.buyAmount)}
- Prod: {formatBigNumber(mat.productionAmount)}
- Sell: {formatBigNumber(mat.actualSellAmount)}
- Export: {formatBigNumber(mat.exportedLastCycle)}
- Import: {formatBigNumber(mat.importAmount)} - {corp.unlocks.has(CorpUnlockName.MarketResearchDemand) && ( - <> -
- Demand: {formatCorpStat(mat.demand)} - - )} - {corp.unlocks.has(CorpUnlockName.MarketDataCompetition) && ( - <> -
- Competition: {formatCorpStat(mat.competition)} - - )} - - } - > + }> {mat.name}: {formatBigNumber(mat.stored)} ( {totalGain >= 1e33 ? totalGain.toExponential(3) : formatBigNumber(totalGain)}/s) diff --git a/src/Corporation/ui/Overview.tsx b/src/Corporation/ui/Overview.tsx index 6ba08887c..4f7091250 100644 --- a/src/Corporation/ui/Overview.tsx +++ b/src/Corporation/ui/Overview.tsx @@ -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:", - <> {formatShares(corp.numShares)} , - <>({formatPercent(corp.numShares / corp.totalShares)}), + formatShares(corp.numShares), + `(${formatPercent(corp.numShares / corp.totalShares)})`, ], [ "Outstanding Shares:", - <> {formatShares(corp.issuedShares)} , - <>({formatPercent(corp.issuedShares / corp.totalShares)}), + formatShares(corp.issuedShares), + `(${formatPercent(corp.issuedShares / corp.totalShares)})`, ], [ "Private Shares:", - <> {formatShares(corp.investorShares)} , - <>({formatPercent(corp.investorShares / corp.totalShares)}), + formatShares(corp.investorShares), + `(${formatPercent(corp.investorShares / corp.totalShares)})`, ], ]} /> diff --git a/src/Corporation/ui/ProductElem.tsx b/src/Corporation/ui/ProductElem.tsx index a5fa62833..dc3b32779 100644 --- a/src/Corporation/ui/ProductElem.tsx +++ b/src/Corporation/ui/ProductElem.tsx @@ -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 { - Prod: {formatBigNumber(product.cityData[city].productionAmount)}/s -
- Sell: {formatBigNumber(product.cityData[city].actualSellAmount)} /s -
+ } > diff --git a/src/Corporation/ui/modals/ResearchModal.tsx b/src/Corporation/ui/modals/ResearchModal.tsx index 9852b34f3..04a1466e5 100644 --- a/src/Corporation/ui/modals/ResearchModal.tsx +++ b/src/Corporation/ui/modals/ResearchModal.tsx @@ -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)}
Multipliers from research: -
* Advertising Multiplier: x{researchTree.getAdvertisingMultiplier()} -
* Employee Charisma Multiplier: x{researchTree.getEmployeeChaMultiplier()} -
* Employee Creativity Multiplier: x{researchTree.getEmployeeCreMultiplier()} -
* Employee Efficiency Multiplier: x{researchTree.getEmployeeEffMultiplier()} -
* Employee Intelligence Multiplier: x{researchTree.getEmployeeIntMultiplier()} -
* Production Multiplier: x{researchTree.getProductionMultiplier()} -
* Sales Multiplier: x{researchTree.getSalesMultiplier()} -
* Scientific Research Multiplier: x{researchTree.getScientificResearchMultiplier()} -
* Storage Multiplier: x{researchTree.getStorageMultiplier()} +
); diff --git a/src/ui/React/StatsTable.tsx b/src/ui/React/StatsTable.tsx index f5808b653..b9b7f0915 100644 --- a/src/ui/React/StatsTable.tsx +++ b/src/ui/React/StatsTable.tsx @@ -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 && {title}} - {rows.map((row: React.ReactNode[], i: number) => ( - - {row.map((elem: React.ReactNode, i: number) => ( - - {elem} + {rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + {cell} ))} diff --git a/src/ui/formatNumber.ts b/src/ui/formatNumber.ts index 63a80627c..724d478b2 100644 --- a/src/ui/formatNumber.ts +++ b/src/ui/formatNumber.ts @@ -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);