CORPORATION: Corp changes prior to 2.3 finalization (#503)

This commit is contained in:
Snarling
2023-05-15 18:06:57 -04:00
committed by GitHub
parent e2e9b084bc
commit 2ae3ac52f1
135 changed files with 3106 additions and 3582 deletions
+5 -3
View File
@@ -8,6 +8,7 @@ import { useDivision } from "./Context";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import { CityName } from "../../Enums";
import { getRecordKeys } from "../../Types/Record";
interface IProps {
city: CityName | "Expand";
@@ -23,7 +24,7 @@ export function CityTabs(props: IProps): React.ReactElement {
mainContent = <ExpandNewCity cityStateSetter={setCity} />;
} else {
const office = division.offices[city];
if (office === 0) {
if (!office) {
setCity(CityName.Sector12);
return <></>;
}
@@ -31,7 +32,7 @@ export function CityTabs(props: IProps): React.ReactElement {
<Industry rerender={props.rerender} city={city} warehouse={division.warehouses[city]} office={office} />
);
}
const canExpand = Object.values(CityName).filter((cityName) => division.offices[cityName] === 0).length > 0;
const canExpand = Object.values(CityName).length > getRecordKeys(division.offices).length;
function handleChange(event: React.SyntheticEvent, tab: CityName | "Expand"): void {
setCity(tab);
}
@@ -40,7 +41,8 @@ export function CityTabs(props: IProps): React.ReactElement {
<>
<Tabs variant="fullWidth" value={city} onChange={handleChange} sx={{ maxWidth: "65vw" }}>
{Object.values(division.offices).map(
(office: OfficeSpace | 0) => office !== 0 && <Tab key={office.loc} label={office.loc} value={office.loc} />,
(office: OfficeSpace | 0) =>
office !== 0 && <Tab key={office.city} label={office.city} value={office.city} />,
)}
{canExpand && <Tab label={"Expand"} value={"Expand"} />}
</Tabs>
+3 -3
View File
@@ -1,11 +1,11 @@
import React, { useContext } from "react";
import { Corporation } from "../Corporation";
import { Industry } from "../Industry";
import { Division } from "../Division";
export const Context = {
Corporation: React.createContext<Corporation>({} as Corporation),
Division: React.createContext<Industry>({} as Industry),
Division: React.createContext<Division>({} as Division),
};
export const useCorporation = (): Corporation => useContext(Context.Corporation);
export const useDivision = (): Industry => useContext(Context.Division);
export const useDivision = (): Division => useContext(Context.Division);
+2 -6
View File
@@ -3,7 +3,6 @@
// divisions, see an overview of your corporation, or create a new industry
import React, { useState } from "react";
import { MainPanel } from "./MainPanel";
import { IndustryType } from "../data/Enums";
import { ExpandIndustryTab } from "./ExpandIndustryTab";
import { Player } from "@player";
import { Context } from "./Context";
@@ -22,16 +21,13 @@ export function CorporationRoot(): React.ReactElement {
setDivisionName(tab);
}
const canExpand =
Object.values(IndustryType).filter(
(industryType) => corporation.divisions.find((division) => division.type === industryType) === undefined,
).length > 0;
const canExpand = corporation.divisions.size < corporation.maxDivisions;
return (
<Context.Corporation.Provider value={corporation}>
<Tabs variant="scrollable" value={divisionName} onChange={handleChange} sx={{ maxWidth: "65vw" }} scrollButtons>
<Tab label={corporation.name} value={"Overview"} />
{corporation.divisions.map((div) => (
{[...corporation.divisions.values()].map((div) => (
<Tab key={div.name} label={div.name} value={div.name} />
))}
{canExpand && <Tab label={"Expand"} value={-1} />}
+13 -19
View File
@@ -6,13 +6,12 @@ import { useCorporation } from "./Context";
import { NewIndustry } from "../Actions";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import TextField from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem";
import Box from "@mui/material/Box";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { KEY } from "../../utils/helpers/keyCodes";
interface IProps {
setDivisionName: (name: string) => void;
}
@@ -26,10 +25,15 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
const data = IndustriesData[industry];
if (!data) return <></>;
const disabled = corp.funds < data.startingCost && corp.divisions.length < corp.maxDivisions;
const disabledText =
corp.divisions.size >= corp.maxDivisions
? "Corporation already has the maximum number of divisions"
: corp.funds < data.startingCost
? "Insufficient corporation funds"
: "";
function newIndustry(): void {
if (disabled) return;
if (disabledText) return;
try {
NewIndustry(corp, industry, name);
} catch (err) {
@@ -60,7 +64,7 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
return (
<>
<Typography>
{corp.name} has {corp.divisions.length}/{corp.maxDivisions} divisions.
{corp.name} has {corp.divisions.size} of {corp.maxDivisions} divisions.
</Typography>
<Typography>Create a new division to expand into a new industry:</Typography>
<Select value={industry} onChange={onIndustryChange}>
@@ -77,20 +81,10 @@ export function ExpandIndustryTab(props: IProps): React.ReactElement {
<Typography>Division name:</Typography>
<Box display="flex" alignItems="center">
<TextField
autoFocus={true}
value={name}
onChange={onNameChange}
onKeyDown={onKeyDown}
type="text"
InputProps={{
endAdornment: (
<Button disabled={disabled} sx={{ mx: 1 }} onClick={newIndustry}>
Expand
</Button>
),
}}
/>
<TextField autoFocus={true} value={name} onChange={onNameChange} onKeyDown={onKeyDown} type="text"></TextField>{" "}
<ButtonWithTooltip disabledTooltip={disabledText} onClick={newIndustry}>
Expand
</ButtonWithTooltip>
</Box>
</>
);
+9 -14
View File
@@ -1,13 +1,13 @@
import React, { useState } from "react";
import * as corpConstants from "../data/Constants";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { NewCity } from "../Actions";
import { purchaseOffice } from "../Actions";
import { MoneyCost } from "./MoneyCost";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import { CityName } from "../../Enums";
interface IProps {
@@ -17,10 +17,10 @@ interface IProps {
export function ExpandNewCity(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const possibleCities = Object.values(CityName).filter((cityName) => division.offices[cityName] === 0);
const possibleCities = Object.values(CityName).filter((cityName) => !(cityName in division.offices));
const [city, setCity] = useState(possibleCities[0]);
const disabled = corp.funds < corpConstants.officeInitialCost;
const disabledText = corp.funds < corpConstants.officeInitialCost ? "Insufficient corporation funds" : "";
function onCityChange(event: SelectChangeEvent): void {
setCity(event.target.value as CityName);
@@ -28,7 +28,7 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
function expand(): void {
try {
NewCity(corp, division, city);
purchaseOffice(corp, division, city);
} catch (err) {
dialogBoxCreate(err + "");
return;
@@ -44,21 +44,16 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
Would you like to expand into a new city by opening an office? This would cost{" "}
<MoneyCost money={corpConstants.officeInitialCost} corp={corp} />
</Typography>
<Select
endAdornment={
<Button onClick={expand} disabled={disabled}>
Confirm
</Button>
}
value={city}
onChange={onCityChange}
>
<Select value={city} onChange={onCityChange}>
{possibleCities.map((cityName: string) => (
<MenuItem key={cityName} value={cityName}>
{cityName}
</MenuItem>
))}
</Select>
<ButtonWithTooltip onClick={expand} disabledTooltip={disabledText}>
Confirm
</ButtonWithTooltip>
</>
);
}
+4 -4
View File
@@ -1,14 +1,14 @@
import { CorpMaterialName } from "@nsdefs";
import { Industry } from "../Industry";
import { Division } from "../Division";
// Returns a boolean indicating whether the given material is relevant for the
// current industry.
export function isRelevantMaterial(matName: CorpMaterialName, division: Industry): boolean {
export function isRelevantMaterial(matName: CorpMaterialName, division: Division): boolean {
// Materials that affect Production multiplier
const prodMultiplierMats: CorpMaterialName[] = ["Hardware", "Robots", "AI Cores", "Real Estate"];
if (Object.keys(division.reqMats).includes(matName)) return true;
if (division.prodMats.includes(matName)) return true;
if (Object.keys(division.requiredMaterials).includes(matName)) return true;
if (division.producedMaterials.includes(matName)) return true;
if (prodMultiplierMats.includes(matName)) return true;
return false;
+1 -1
View File
@@ -13,7 +13,7 @@ import { CityName } from "../../Enums";
interface IProps {
city: CityName;
warehouse: Warehouse | 0;
warehouse?: Warehouse;
office: OfficeSpace;
rerender: () => void;
}
+60 -67
View File
@@ -3,7 +3,7 @@
import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { EmployeePositions } from "../data/Enums";
import { CorpUnlockName, CorpEmployeeJob } from "../data/Enums";
import { BuyTea } from "../Actions";
import { MoneyCost } from "./MoneyCost";
@@ -15,7 +15,7 @@ import { Money } from "../../ui/React/Money";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
@@ -35,7 +35,7 @@ interface IProps {
interface IAutoAssignProps {
office: OfficeSpace;
job: EmployeePositions;
job: CorpEmployeeJob;
desc: string;
rerender: () => void;
}
@@ -53,7 +53,7 @@ function EmployeeCount(props: { num: number; next: number }): React.ReactElement
function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
const currJob = props.office.employeeJobs[props.job];
const nextJob = props.office.employeeNextJobs[props.job];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
const nextUna = props.office.employeeNextJobs[CorpEmployeeJob.Unassigned];
function assignEmployee(): void {
if (nextUna <= 0) return console.warn("Cannot assign employee. No unassigned employees available");
@@ -94,10 +94,9 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
function AutoManagement(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade
const currUna = props.office.employeeJobs[EmployeePositions.Unassigned];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
const currUna = props.office.employeeJobs[CorpEmployeeJob.Unassigned];
const nextUna = props.office.employeeNextJobs[CorpEmployeeJob.Unassigned];
return (
<Table padding="none">
@@ -115,7 +114,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<Typography>Avg Employee Morale:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{formatCorpStat(props.office.avgMor)}</Typography>
<Typography>{formatCorpStat(props.office.avgMorale)}</Typography>
</TableCell>
</TableRow>
<TableRow>
@@ -123,7 +122,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<Typography>Avg Employee Energy:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{formatCorpStat(props.office.avgEne)}</Typography>
<Typography>{formatCorpStat(props.office.avgEnergy)}</Typography>
</TableCell>
</TableRow>
<TableRow>
@@ -131,7 +130,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<Typography>Avg Employee Experience:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{formatCorpStat(props.office.totalExp / props.office.totalEmployees || 0)}</Typography>
<Typography>{formatCorpStat(props.office.totalExperience / props.office.numEmployees || 0)}</Typography>
</TableCell>
</TableRow>
<TableRow>
@@ -144,7 +143,7 @@ function AutoManagement(props: IProps): React.ReactElement {
</Typography>
</TableCell>
</TableRow>
{vechain && (
{corp.unlocks.has(CorpUnlockName.VeChain) && (
<>
<TableRow>
<TableCell>
@@ -201,14 +200,14 @@ function AutoManagement(props: IProps): React.ReactElement {
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Operations}
job={CorpEmployeeJob.Operations}
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Engineer}
job={CorpEmployeeJob.Engineer}
desc={
"Develops and maintains products and production systems. Increases the quality of everything you produce. Also increases the amount you produce (not as much as Operations, however)."
}
@@ -217,14 +216,14 @@ function AutoManagement(props: IProps): React.ReactElement {
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Business}
job={CorpEmployeeJob.Business}
desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Management}
job={CorpEmployeeJob.Management}
desc={
"Leads and oversees employees and office operations. Improves the effectiveness of Engineer and Operations employees."
}
@@ -233,7 +232,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.RandD}
job={CorpEmployeeJob.RandD}
desc={
"Research new innovative ways to improve the company. Generates Scientific Research. Also increases the quality of everything you produce (not as much as Engineer, however)."
}
@@ -242,7 +241,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Intern}
job={CorpEmployeeJob.Intern}
desc={
"Set employee to intern, which will increase some of their stats. Employees in intern do not affect any company operations, but gain increased exp and improve morale and energy."
}
@@ -260,32 +259,38 @@ export function IndustryOffice(props: IProps): React.ReactElement {
function autohireEmployeeButtonOnClick(): void {
if (props.office.atCapacity()) return;
props.office.hireRandomEmployee(EmployeePositions.Unassigned);
props.office.hireRandomEmployee(CorpEmployeeJob.Unassigned);
props.rerender();
}
const hireEmployeeDisabledText = props.office.atCapacity() ? "Insufficient office space" : "";
const teaDisabledText =
corp.funds < props.office.getTeaCost()
? "Insufficient corporation funds"
: props.office.teaPending
? "Tea is already pending for this cycle"
: "";
const partyPending = props.office.partyMult > 1;
const partyDisabledText =
corp.funds < 0 ? "Insufficient corporation funds" : partyPending ? "A party is already pending for this cycle" : "";
return (
<Paper>
<Typography>Office Space</Typography>
<Typography>
Size: {props.office.totalEmployees} / {props.office.size} employees
Size: {props.office.numEmployees} / {props.office.size} employees
</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: "1fr", width: "fit-content" }}>
<Box sx={{ gridTemplateColumns: "repeat(3, 1fr)" }}>
<Tooltip title={<Typography>Hires an employee</Typography>}>
<span>
<Button disabled={props.office.atCapacity()} onClick={autohireEmployeeButtonOnClick}>
Hire Employee
</Button>
</span>
</Tooltip>
<Tooltip title={<Typography>Upgrade the office's size so that it can hold more employees!</Typography>}>
<span>
<Button disabled={corp.funds < 0} onClick={() => setUpgradeOfficeSizeOpen(true)}>
Upgrade size
</Button>
</span>
</Tooltip>
<ButtonWithTooltip disabledTooltip={hireEmployeeDisabledText} onClick={autohireEmployeeButtonOnClick}>
Hire Employee
</ButtonWithTooltip>
<ButtonWithTooltip
normalTooltip={"Upgrade the office's size so that it can hold more employees!"}
onClick={() => setUpgradeOfficeSizeOpen(true)}
>
Upgrade size
</ButtonWithTooltip>
<UpgradeOfficeSizeModal
rerender={props.rerender}
office={props.office}
@@ -294,44 +299,32 @@ export function IndustryOffice(props: IProps): React.ReactElement {
/>
{!division.hasResearch("AutoBrew") && (
<>
<Tooltip
title={
<Typography>
Provide your employees with tea, increasing their energy by half the difference to 100%, plus 1.5%
</Typography>
}
>
<span>
<Button
disabled={corp.funds < props.office.getTeaCost() || props.office.teaPending}
onClick={() => BuyTea(corp, props.office)}
>
{props.office.teaPending ? (
"Buying tea..."
) : (
<span>
Buy Tea - <MoneyCost money={props.office.getTeaCost()} corp={corp} />
</span>
)}
</Button>
</span>
</Tooltip>
</>
<ButtonWithTooltip
normalTooltip={
"Provide your employees with tea, increasing their energy by half the difference to 100%, plus 1.5%"
}
disabledTooltip={teaDisabledText}
onClick={() => BuyTea(corp, props.office)}
>
{props.office.teaPending ? (
"Buying Tea"
) : (
<>
Buy Tea - <MoneyCost money={props.office.getTeaCost()} corp={corp} />
</>
)}
</ButtonWithTooltip>
)}
{!division.hasResearch("AutoPartyManager") && (
<>
<Tooltip title={<Typography>Throw an office party to increase your employee's morale</Typography>}>
<span>
<Button
disabled={corp.funds < 0 || props.office.partyMult > 1}
onClick={() => setThrowPartyOpen(true)}
>
{props.office.partyMult > 1 ? "Throwing Party..." : "Throw Party"}
</Button>
</span>
</Tooltip>
<ButtonWithTooltip
normalTooltip={"Throw an office party to increase your employees' morale"}
disabledTooltip={partyDisabledText}
onClick={() => setThrowPartyOpen(true)}
>
{props.office.partyMult > 1 ? "Throwing Party..." : "Throw Party"}
</ButtonWithTooltip>
<ThrowPartyModal
rerender={props.rerender}
office={props.office}
+39 -50
View File
@@ -2,7 +2,7 @@
// (top-left panel in the Industry UI)
import React, { useState } from "react";
import { IndustryType } from "../data/Enums";
import { CorpUnlockName, IndustryType } from "../data/Enums";
import { HireAdVert } from "../Actions";
import { formatBigNumber } from "../../ui/formatNumber";
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
@@ -16,6 +16,7 @@ import { MoneyCost } from "./MoneyCost";
import { useCorporation, useDivision } from "./Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import Tooltip from "@mui/material/Tooltip";
import Paper from "@mui/material/Paper";
import IconButton from "@mui/material/IconButton";
@@ -30,7 +31,7 @@ function MakeProductButton(): React.ReactElement {
const hasMaxProducts = division.hasMaximumNumberProducts();
function shouldFlash(): boolean {
return Object.keys(division.products).length === 0;
return division.products.size === 0;
}
function onButtonClick() {
@@ -69,38 +70,35 @@ function MakeProductButton(): React.ReactElement {
return <></>;
}
const disabledText = hasMaxProducts
? `${division.name} already has the maximum number of products (${division.getMaximumNumberProducts()})`
: corp.funds < 0
? "Insufficient corporation funds"
: "";
return (
<>
<Tooltip
title={
hasMaxProducts ? (
<Typography>
You have reached the maximum number of products: {division.getMaximumNumberProducts()}
</Typography>
) : (
""
)
}
<ButtonWithTooltip
disabledTooltip={disabledText}
onClick={onButtonClick}
buttonProps={{ color: shouldFlash() ? "error" : "primary" }}
>
<Button color={shouldFlash() ? "error" : "primary"} onClick={onButtonClick} disabled={corp.funds < 0}>
{createProductButtonText}
</Button>
</Tooltip>
{createProductButtonText}
</ButtonWithTooltip>
<MakeProductModal open={makeOpen} onClose={() => setMakeOpen(false)} />
</>
);
}
interface IProps {
interface IndustryOverviewProps {
rerender: () => void;
}
export function IndustryOverview(props: IProps): React.ReactElement {
export function IndustryOverview(props: IndustryOverviewProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const [helpOpen, setHelpOpen] = useState(false);
const [researchOpen, setResearchOpen] = useState(false);
const vechain = corp.unlockUpgrades[4] === 1;
const profit = division.lastCycleRevenue - division.lastCycleExpenses;
let advertisingInfo = false;
@@ -109,7 +107,7 @@ export function IndustryOverview(props: IProps): React.ReactElement {
const popularityFac = advertisingFactors[2];
const ratioFac = advertisingFactors[3];
const totalAdvertisingFac = advertisingFactors[0];
if (vechain) {
if (corp.unlocks.has(CorpUnlockName.VeChain)) {
advertisingInfo = true;
}
@@ -162,13 +160,13 @@ export function IndustryOverview(props: IProps): React.ReactElement {
<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: {formatBigNumber(division.prodMult)}</Typography>
<Typography>Production Multiplier: {formatBigNumber(division.productionMult)}</Typography>
</Tooltip>
<IconButton onClick={() => setHelpOpen(true)}>
<HelpIcon />
@@ -189,25 +187,19 @@ export function IndustryOverview(props: IProps): React.ReactElement {
multiplier (Bigger bars = more effective):
<br />
<br />
Hardware:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.hwFac)}
Hardware:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.hardwareFactor)}
<br />
Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.robFac)}
Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.robotFactor)}
<br />
AI Cores:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.aiFac)}
AI Cores:&nbsp;&nbsp;&nbsp; {convertEffectFacToGraphic(division.aiCoreFactor)}
<br />
Real Estate: {convertEffectFacToGraphic(division.reFac)}
Real Estate: {convertEffectFacToGraphic(division.realEstateFactor)}
</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: {formatBigNumber(division.sciResearch)}</Typography>
<Tooltip title={"Scientific Research increases the quality of the materials and products that you produce."}>
<Typography>Scientific Research: {formatBigNumber(division.researchPoints)}</Typography>
</Tooltip>
<Button sx={{ mx: 1 }} onClick={() => setResearchOpen(true)}>
Research
@@ -216,26 +208,23 @@ export function IndustryOverview(props: IProps): React.ReactElement {
</Box>
<br />
<Box display="flex" alignItems="center">
<Tooltip
title={
<Typography>
<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
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.
</Typography>
</>
}
disabledTooltip={division.getAdVertCost() > corp.funds ? "Insufficient corporation funds" : ""}
onClick={() => {
HireAdVert(corp, division);
props.rerender();
}}
>
<Button
disabled={division.getAdVertCost() > corp.funds}
onClick={function () {
HireAdVert(corp, division);
props.rerender();
}}
>
Hire AdVert -&nbsp; <MoneyCost money={division.getAdVertCost()} corp={corp} />
</Button>
</Tooltip>
Hire AdVert -&nbsp; <MoneyCost money={division.getAdVertCost()} corp={corp} />
</ButtonWithTooltip>
{division.makesProducts && <MakeProductButton />}
</Box>
</Paper>
@@ -1,20 +1,20 @@
import React from "react";
import { Industry } from "../Industry";
import { Division } from "../Division";
import { MathJax } from "better-react-mathjax";
import { CorpMaterialName } from "@nsdefs";
interface IProps {
division: Industry;
division: Division;
}
export function IndustryProductEquation(props: IProps): React.ReactElement {
const reqs = [];
for (const reqMat of Object.keys(props.division.reqMats) as CorpMaterialName[]) {
const reqAmt = props.division.reqMats[reqMat];
for (const reqMat of Object.keys(props.division.requiredMaterials) as CorpMaterialName[]) {
const reqAmt = props.division.requiredMaterials[reqMat];
if (reqAmt === undefined) continue;
reqs.push(String.raw`${reqAmt}\text{ }${reqMat}`);
}
const prod = props.division.prodMats.map((p) => `1\\text{ }${p}`);
const prod = props.division.producedMaterials.map((p) => `1\\text{ }${p}`);
if (props.division.makesProducts) {
prod.push("Products");
}
+35 -61
View File
@@ -12,26 +12,28 @@ import { MaterialInfo } from "../MaterialInfo";
import { formatBigNumber, formatMaterialSize } from "../../ui/formatNumber";
import { Corporation } from "../Corporation";
import { Industry } from "../Industry";
import { Division } from "../Division";
import { MoneyCost } from "./MoneyCost";
import { isRelevantMaterial } from "./Helpers";
import { IndustryProductEquation } from "./IndustryProductEquation";
import { PurchaseWarehouse } from "../Actions";
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 { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
import { CityName } from "../../Enums";
import { CorpUnlockName } from "../data/Enums";
interface IProps {
corp: Corporation;
division: Industry;
warehouse: Warehouse | 0;
division: Division;
warehouse?: Warehouse;
currentCity: CityName;
rerender: () => void;
}
@@ -48,14 +50,13 @@ function WarehouseRoot(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const [smartSupplyOpen, setSmartSupplyOpen] = useState(false);
if (props.warehouse === 0) return <></>;
if (!props.warehouse) return <></>;
// Upgrade Warehouse size button
const sizeUpgradeCost = corpConstants.warehouseSizeUpgradeCostBase * Math.pow(1.07, props.warehouse.level + 1);
const canAffordUpgrade = corp.funds > sizeUpgradeCost;
function upgradeWarehouseOnClick(): void {
if (division === null) return;
if (props.warehouse === 0) return;
if (!props.warehouse) return;
if (!canAffordUpgrade) return;
++props.warehouse.level;
props.warehouse.updateSize(corp, division);
@@ -93,7 +94,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
for (const matName of Object.values(corpConstants.materialNames)) {
if (!props.warehouse.materials[matName]) continue;
// Only create UI for materials that are relevant for the industry or in stock
const isInStock = props.warehouse.materials[matName].qty > 0;
const isInStock = props.warehouse.materials[matName].stored > 0;
const isRelevant = isRelevantMaterial(matName, division);
if (!isInStock && !isRelevant) continue;
mats.push(
@@ -108,51 +109,31 @@ function WarehouseRoot(props: IProps): React.ReactElement {
}
// Create React components for products
const products = [];
if (division.makesProducts && Object.keys(division.products).length > 0) {
for (const productName of Object.keys(division.products)) {
const product = division.products[productName];
if (!product) continue;
products.push(
const productElements = [];
if (division.makesProducts && division.products.size > 0) {
for (const [productName, product] of division.products) {
productElements.push(
<ProductElem rerender={props.rerender} city={props.currentCity} key={productName} product={product} />,
);
}
}
const breakdownItems: JSX.Element[] = [];
for (const matName of Object.values(corpConstants.materialNames)) {
const breakdownItems: string[] = [];
for (const matName of corpConstants.materialNames) {
const mat = props.warehouse.materials[matName];
if (!Object.hasOwn(MaterialInfo, matName)) continue;
if (mat.qty === 0) continue;
breakdownItems.push(
<>
{matName}: {formatMaterialSize(mat.qty * MaterialInfo[matName].size)}
</>,
);
if (mat.stored === 0) continue;
breakdownItems.push(`${matName}: ${formatMaterialSize(mat.stored * MaterialInfo[matName].size)}`);
}
for (const prodName of Object.keys(division.products)) {
const prod = division.products[prodName];
if (prod === undefined) continue;
for (const [prodName, product] of division.products) {
breakdownItems.push(
<>
{prodName}: {formatMaterialSize(prod.data[props.warehouse.loc][0] * prod.siz)}
</>,
`${prodName}: ${formatMaterialSize(product.cityData[props.currentCity].stored * product.size)}`,
);
}
let breakdown;
if (breakdownItems && breakdownItems.length > 0) {
breakdown = breakdownItems.reduce(
(previous: JSX.Element, current: JSX.Element): JSX.Element =>
(previous && (
<>
{previous}
<br />
{current}
</>
)) || <>{current}</>,
);
if (breakdownItems.length > 0) {
breakdown = breakdownItems.map((item, i) => <p key={i}>{item}</p>);
} else {
breakdown = <>No items in storage.</>;
}
@@ -160,27 +141,20 @@ function WarehouseRoot(props: IProps): React.ReactElement {
return (
<Paper>
<Box display="flex" alignItems="center">
<Tooltip
title={
props.warehouse.sizeUsed !== 0 ? (
<Typography>
<>{breakdown}</>
</Typography>
) : (
""
)
}
>
<Tooltip title={breakdown}>
<Typography color={props.warehouse.sizeUsed >= props.warehouse.size ? "error" : "primary"}>
Storage: {formatBigNumber(props.warehouse.sizeUsed)} / {formatBigNumber(props.warehouse.size)}
</Typography>
</Tooltip>
</Box>
<Button disabled={!canAffordUpgrade} onClick={upgradeWarehouseOnClick}>
<ButtonWithTooltip
disabledTooltip={canAffordUpgrade ? "" : "Insufficient corporation funds"}
onClick={upgradeWarehouseOnClick}
>
Upgrade Warehouse Size -&nbsp;
<MoneyCost money={sizeUpgradeCost} corp={corp} />
</Button>
</ButtonWithTooltip>
<Typography>This industry uses the following equation for its production: </Typography>
<br />
@@ -196,7 +170,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
<Typography className={classes.retainHeight}>{stateText}</Typography>
{corp.unlockUpgrades[1] && (
{corp.unlocks.has(CorpUnlockName.SmartSupply) && (
<>
<Button onClick={() => setSmartSupplyOpen(true)}>Configure Smart Supply</Button>
<SmartSupplyModal
@@ -209,7 +183,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
{mats}
{products}
{productElements}
</Paper>
);
}
@@ -230,18 +204,18 @@ interface IEmptyProps {
function EmptyWarehouse(props: IEmptyProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const disabled = corp.funds < corpConstants.warehouseInitialCost;
function purchaseWarehouse(): void {
if (disabled) return;
PurchaseWarehouse(corp, division, props.city);
const disabledText = corp.funds < corpConstants.warehouseInitialCost ? "Insufficient corporation funds" : "";
function newWarehouse(): void {
if (disabledText) return;
purchaseWarehouse(corp, division, props.city);
props.rerender();
}
return (
<Paper>
<Button onClick={purchaseWarehouse} disabled={disabled}>
<ButtonWithTooltip onClick={newWarehouse} disabledTooltip={disabledText}>
Purchase Warehouse (
<MoneyCost money={corpConstants.warehouseInitialCost} corp={corp} />)
</Button>
</ButtonWithTooltip>
</Paper>
);
}
+20 -21
View File
@@ -2,49 +2,48 @@
import React from "react";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { CorporationUpgrade } from "../data/CorporationUpgrades";
import { LevelUpgrade } from "../Actions";
import { CorpUpgrades } from "../data/CorporationUpgrades";
import { MoneyCost } from "./MoneyCost";
import { useCorporation } from "./Context";
import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
import { calculateMaxAffordableUpgrade, calculateUpgradeCost } from "../helpers";
import { CorpUpgradeName } from "../data/Enums";
import { PositiveInteger } from "../../types";
interface IProps {
upgrade: CorporationUpgrade;
amount: number | "MAX";
upgradeName: CorpUpgradeName;
mult: PositiveInteger | "MAX";
rerender: () => void;
}
export function LevelableUpgrade(props: IProps): React.ReactElement {
export function LevelableUpgrade({ upgradeName, mult, rerender }: IProps): React.ReactElement {
const corp = useCorporation();
const data = props.upgrade;
const level = corp.upgrades[data.index];
const amount = props.amount;
const data = CorpUpgrades[upgradeName];
const level = corp.upgrades[upgradeName].level;
const maxUpgrades = amount === "MAX" ? calculateMaxAffordableUpgrade(corp, data, amount) : amount;
const cost = calculateUpgradeCost(corp, data, maxUpgrades);
const amount = mult === "MAX" ? calculateMaxAffordableUpgrade(corp, data, mult) : mult;
const cost = amount === 0 ? 0 : calculateUpgradeCost(corp, data, amount);
const tooltip = data.desc;
function onClick(): void {
if (corp.funds < cost) return;
try {
LevelUpgrade(corp, props.upgrade, maxUpgrades);
} catch (err) {
dialogBoxCreate(err + "");
}
props.rerender();
const message = corp.purchaseUpgrade(upgradeName, amount);
if (message) dialogBoxCreate(`Could not upgrade ${upgradeName} ${amount} times:\n${message}`);
rerender();
}
return (
<Grid item xs={4}>
<Box display="flex" alignItems="center" flexDirection="row-reverse">
<Button disabled={corp.funds < cost} sx={{ mx: 1 }} onClick={onClick}>
+{maxUpgrades} -&nbsp;
<MoneyCost money={cost} corp={corp} />
</Button>
<ButtonWithTooltip
disabledTooltip={corp.funds < cost || amount === 0 ? "Insufficient corporation funds" : ""}
onClick={onClick}
>
+{amount} -&nbsp; <MoneyCost money={cost} corp={corp} />
</ButtonWithTooltip>
<Tooltip title={tooltip}>
<Typography>
{data.name} - lvl {level}
+2 -7
View File
@@ -4,7 +4,6 @@
import React from "react";
import { CityTabs } from "./CityTabs";
import { Industry } from "../Industry";
import { Context, useCorporation } from "./Context";
import { CityName } from "../../Enums";
@@ -16,12 +15,8 @@ interface IProps {
export function MainPanel(props: IProps): React.ReactElement {
const corp = useCorporation();
const division =
props.divisionName !== "Overview"
? corp.divisions.find((division: Industry) => division.name === props.divisionName)
: undefined; // use undefined because find returns undefined
if (division === undefined) throw new Error("Cannot find division");
const division = corp.divisions.get(props.divisionName);
if (!division) throw new Error("Cannot find division");
return (
<Context.Division.Provider value={division}>
<CityTabs rerender={props.rerender} city={CityName.Sector12} />
+42 -31
View File
@@ -22,6 +22,7 @@ import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import { LimitMaterialProductionModal } from "./modals/LimitMaterialProductionModal";
import { CityName } from "../../Enums";
import { CorpUnlockName } from "../data/Enums";
interface IMaterialProps {
warehouse: Warehouse;
@@ -50,29 +51,33 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
}
// Total gain or loss of this material (per second)
const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
const totalGain =
mat.buyAmount + mat.productionAmount + mat.importAmount - mat.actualSellAmount - mat.exportedLastCycle;
// 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;
division.newInd &&
Object.keys(division.requiredMaterials).includes(mat.name) &&
mat.buyAmount === 0 &&
mat.importAmount === 0;
// Purchase material button
const purchaseButtonText = `Buy (${formatBigNumber(mat.buy)})`;
const purchaseButtonText = `Buy (${formatBigNumber(mat.buyAmount)})`;
// Sell material button
let sellButtonText: JSX.Element;
if (mat.sllman[0]) {
if (isString(mat.sllman[1])) {
if (mat.desiredSellAmount) {
if (isString(mat.desiredSellAmount)) {
sellButtonText = (
<>
Sell ({formatBigNumber(mat.sll)}/{mat.sllman[1]})
Sell ({formatBigNumber(mat.actualSellAmount)}/{mat.desiredSellAmount[1]})
</>
);
} else {
sellButtonText = (
<>
Sell ({formatBigNumber(mat.sll)}/{formatBigNumber(mat.sllman[1])})
Sell ({formatBigNumber(mat.actualSellAmount)}/{formatBigNumber(mat.desiredSellAmount)})
</>
);
}
@@ -86,12 +91,12 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
} else if (mat.marketTa1) {
sellButtonText = (
<>
{sellButtonText} @ <Money money={mat.bCost + markupLimit} />
{sellButtonText} @ <Money money={mat.marketPrice + markupLimit} />
</>
);
} else if (mat.sCost) {
if (isString(mat.sCost)) {
const sCost = mat.sCost.replace(/MP/g, mat.bCost + "");
} else if (mat.desiredSellPrice) {
if (isString(mat.desiredSellPrice)) {
const sCost = mat.desiredSellPrice.replace(/MP/g, mat.marketPrice + "");
sellButtonText = (
<>
{sellButtonText} @ <Money money={eval(sCost)} />
@@ -100,7 +105,7 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
} else {
sellButtonText = (
<>
{sellButtonText} @ <Money money={mat.sCost} />
{sellButtonText} @ <Money money={mat.desiredSellPrice} />
</>
);
}
@@ -111,8 +116,8 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
// Limit Production button
let limitMaterialButtonText = "Limit Material";
if (mat.prdman[0]) {
limitMaterialButtonText += " (" + formatCorpStat(mat.prdman[1]) + ")";
if (mat.productionLimit !== null) {
limitMaterialButtonText += " (" + formatCorpStat(mat.productionLimit) + ")";
}
return (
@@ -122,20 +127,28 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
<Tooltip
title={
<Typography>
Buy: {mat.buy >= 1e33 ? mat.buy.toExponential(3) : formatBigNumber(mat.buy)} <br />
Prod: {formatBigNumber(mat.prd)} <br />
Sell: {formatBigNumber(mat.sll)} <br />
Export: {formatBigNumber(mat.totalExp)} <br />
Import: {formatBigNumber(mat.imp)}
{corp.unlockUpgrades[2] === 1 && <br />}
{corp.unlockUpgrades[2] === 1 && "Demand: " + formatCorpStat(mat.dmd)}
{corp.unlockUpgrades[3] === 1 && <br />}
{corp.unlockUpgrades[3] === 1 && "Competition: " + formatCorpStat(mat.cmp)}
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>
}
>
<Typography>
{mat.name}: {formatBigNumber(mat.qty)} (
{mat.name}: {formatBigNumber(mat.stored)} (
{totalGain >= 1e33 ? totalGain.toExponential(3) : formatBigNumber(totalGain)}/s)
</Typography>
</Tooltip>
@@ -146,12 +159,12 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
</Typography>
}
>
<Typography>MP: {formatMoney(mat.bCost)}</Typography>
<Typography>MP: {formatMoney(mat.marketPrice)}</Typography>
</Tooltip>
<Tooltip
title={<Typography>The quality of your material. Higher quality will lead to more sales</Typography>}
>
<Typography>Quality: {formatQuality(mat.qlt)}</Typography>
<Typography>Quality: {formatQuality(mat.quality)}</Typography>
</Tooltip>
</Box>
@@ -167,13 +180,11 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
mat={mat}
warehouse={warehouse}
open={purchaseMaterialOpen}
disablePurchaseLimit={
props.warehouse.smartSupplyEnabled && Object.keys(division.reqMats).includes(props.mat.name)
}
disablePurchaseLimit={props.warehouse.smartSupplyEnabled && props.mat.name in division.requiredMaterials}
onClose={() => setPurchaseMaterialOpen(false)}
/>
{corp.unlockUpgrades[0] === 1 && (
{corp.unlocks.has(CorpUnlockName.Export) && (
<>
<Button onClick={() => setExportOpen(true)}>Export</Button>
@@ -182,7 +193,7 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
)}
<Button
color={division.prodMats.includes(props.mat.name) && !mat.sllman[0] ? "error" : "primary"}
color={division.producedMaterials.includes(props.mat.name) && !mat.desiredSellAmount ? "error" : "primary"}
onClick={() => setSellMaterialOpen(true)}
>
{sellButtonText}
+14 -36
View File
@@ -7,44 +7,22 @@ import React from "react";
import { PurchaseMultipliers } from "../data/Constants";
import Button from "@mui/material/Button";
interface IMultiplierProps {
disabled: boolean;
onClick: () => void;
text: string;
}
function MultiplierButton(props: IMultiplierProps): React.ReactElement {
return (
<Button disabled={props.disabled} onClick={props.onClick}>
{props.text}
</Button>
);
}
import { PositiveInteger } from "../../types";
import { getRecordEntries } from "../../Types/Record";
interface IProps {
purchaseMultiplier: number | string;
onClicks: (() => void)[];
selectedMultiplier: PositiveInteger | "MAX";
setMultiplier: (mult: PositiveInteger | "MAX") => void;
}
export function MultiplierButtons(props: IProps): React.ReactElement {
if (props.purchaseMultiplier == null) {
throw new Error(`MultiplierButtons constructed without required props`);
}
const mults = ["x1", "x5", "x10", "x50", "x100", "MAX"];
const onClicks = props.onClicks;
const buttons = [];
for (let i = 0; i < mults.length; ++i) {
const mult = mults[i];
const btnProps = {
disabled: props.purchaseMultiplier === PurchaseMultipliers[mult],
onClick: onClicks[i],
text: mult,
};
buttons.push(<MultiplierButton key={mult} {...btnProps} />);
}
return <>{buttons}</>;
export function MultiplierButtons({ selectedMultiplier, setMultiplier }: IProps): JSX.Element {
return (
<>
{getRecordEntries<string, PositiveInteger | "MAX">(PurchaseMultipliers).map(([text, mult]) => (
<Button key={text} onClick={() => setMultiplier(mult)} disabled={mult === selectedMultiplier}>
{text}
</Button>
))}
</>
);
}
+88 -88
View File
@@ -1,7 +1,7 @@
// React Component for displaying Corporation Overview info
import React, { useState } from "react";
import { LevelableUpgrade } from "./LevelableUpgrade";
import { UnlockUpgrade } from "./UnlockUpgrade";
import { Unlock } from "./Unlock";
import { BribeFactionModal } from "./modals/BribeFactionModal";
import { SellSharesModal } from "./modals/SellSharesModal";
import { BuybackSharesModal } from "./modals/BuybackSharesModal";
@@ -12,8 +12,7 @@ import { GoPublicModal } from "./modals/GoPublicModal";
import { Factions } from "../../Faction/Factions";
import * as corpConstants from "../data/Constants";
import { CorporationUnlockUpgrade, CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
import { CorporationUpgrade, CorporationUpgradeIndex, CorporationUpgrades } from "../data/CorporationUpgrades";
import { CorpUnlocks } from "../data/CorporationUnlocks";
import { CONSTANTS } from "../../Constants";
import { formatCorpStat, formatPercent, formatShares } from "../../ui/formatNumber";
@@ -25,13 +24,15 @@ import { Player } from "@player";
import { useCorporation } from "./Context";
import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Grid from "@mui/material/Grid";
import { MultiplierButtons } from "./MultiplierButtons";
import { SellCorporationModal } from "./modals/SellCorporationModal";
import { SellDivisionModal } from "./modals/SellDivisionModal";
import { getRecordKeys } from "../../Types/Record";
import { PositiveInteger } from "../../types";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
interface IProps {
rerender: () => void;
@@ -50,11 +51,11 @@ export function Overview({ rerender }: IProps): React.ReactElement {
appendMult("Storage Multiplier: ", corp.getStorageMultiplier());
appendMult("Advertising Multiplier: ", corp.getAdvertisingMultiplier());
appendMult("Empl. Creativity Multiplier: ", corp.getEmployeeCreMultiplier());
appendMult("Empl. Charisma Multiplier: ", corp.getEmployeeChaMultiplier());
appendMult("Empl. Intelligence Multiplier: ", corp.getEmployeeIntMultiplier());
appendMult("Empl. Efficiency Multiplier: ", corp.getEmployeeEffMultiplier());
appendMult("Sales Multiplier: ", corp.getSalesMultiplier());
appendMult("Scientific Research Multiplier: ", corp.getScientificResearchMultiplier());
appendMult("Empl. Charisma Multiplier: ", corp.getEmployeeChaMult());
appendMult("Empl. Intelligence Multiplier: ", corp.getEmployeeIntMult());
appendMult("Empl. Efficiency Multiplier: ", corp.getEmployeeEffMult());
appendMult("Sales Multiplier: ", corp.getSalesMult());
appendMult("Scientific Research Multiplier: ", corp.getScientificResearchMult());
return (
<>
@@ -90,23 +91,24 @@ export function Overview({ rerender }: IProps): React.ReactElement {
<StatsTable rows={multRows} />
<br />
<BonusTime />
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", width: "fit-content" }}>
<Tooltip
title={
<Typography>
<div>
<ButtonWithTooltip
normalTooltip={
<>
Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' This is a .lit file
that guides you through the beginning of setting up a Corporation and provides some tips/pointers for
helping you get started with managing it.
</Typography>
</>
}
onClick={() => corp.getStarterGuide()}
>
<Button onClick={() => corp.getStarterGuide()}>Getting Started Guide</Button>
</Tooltip>
{corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />}
Getting Started Guide
</ButtonWithTooltip>
<BribeButton />
{corp.divisions.length != 0 ? <SellDivisionButton /> : <></>}
{corp.divisions.size > 0 && <SellDivisionButton />}
<RestartButton />
</Box>
</div>
<div>{corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />}</div>
<br />
<Upgrades rerender={rerender} />
</>
@@ -129,21 +131,24 @@ function PrivateButtons({ rerender }: IPrivateButtonsProps): React.ReactElement
return (
<>
<Tooltip title={<Typography>{findInvestorsTooltip}</Typography>}>
<Button disabled={!fundingAvailable} onClick={() => setFindInvestorsopen(true)}>
Find Investors
</Button>
</Tooltip>
<Tooltip
title={
<Typography>
<ButtonWithTooltip
normalTooltip={findInvestorsTooltip}
disabledTooltip={fundingAvailable ? "" : "Max funding rounds already reached"}
onClick={() => setFindInvestorsopen(true)}
>
Find Investors
</ButtonWithTooltip>
<ButtonWithTooltip
normalTooltip={
<>
Become a publicly traded and owned entity. Going public involves issuing shares for an IPO. Once you are a
public company, your shares will be traded on the stock market.
</Typography>
</>
}
onClick={() => setGoPublicopen(true)}
>
<Button onClick={() => setGoPublicopen(true)}>Go Public</Button>
</Tooltip>
Go Public
</ButtonWithTooltip>
<FindInvestorsModal open={findInvestorsopen} onClose={() => setFindInvestorsopen(false)} rerender={rerender} />
<GoPublicModal open={goPublicopen} onClose={() => setGoPublicopen(false)} rerender={rerender} />
</>
@@ -157,45 +162,37 @@ interface IUpgradeProps {
function Upgrades({ rerender }: IUpgradeProps): React.ReactElement {
const corp = useCorporation();
// Don't show upgrades
if (corp.divisions.length <= 0) {
if (corp.divisions.size === 0) {
return <Typography variant="h4">Upgrades are unlocked once you create an industry.</Typography>;
}
const [purchaseMultiplier, setPurchaseMultiplier] = useState<number | "MAX">(corpConstants.PurchaseMultipliers.x1);
const [purchaseMultiplier, setPurchaseMultiplier] = useState<PositiveInteger | "MAX">(
corpConstants.PurchaseMultipliers.x1,
);
// onClick event handlers for purchase multiplier buttons
const purchaseMultiplierOnClicks = [
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.x1),
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.x5),
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.x10),
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.x50),
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.x100),
() => setPurchaseMultiplier(corpConstants.PurchaseMultipliers.MAX),
];
const unlocksNotOwned = Object.values(CorpUnlocks)
.filter((unlock) => !corp.unlocks.has(unlock.name))
.map(({ name }) => <Unlock rerender={rerender} name={name} key={name} />);
return (
<>
<Paper sx={{ p: 1, my: 1 }}>
<Typography variant="h4">Unlocks</Typography>
<Grid container>
{Object.values(CorporationUnlockUpgrades).map((upgrade: CorporationUnlockUpgrade) => (
<UnlockUpgrade rerender={rerender} upgradeData={upgrade} key={upgrade.index} />
))}
{unlocksNotOwned.length ? unlocksNotOwned : <Typography>All unlocks are owned.</Typography>}
</Grid>
</Paper>
<Paper sx={{ p: 1, my: 1 }}>
<Typography variant="h4">Upgrades</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={purchaseMultiplier} />
<MultiplierButtons setMultiplier={setPurchaseMultiplier} selectedMultiplier={purchaseMultiplier} />
</Grid>
</Grid>
<Grid container>
{corp.upgrades
.map((level: number, i: number) => CorporationUpgrades[i as CorporationUpgradeIndex])
.map((upgrade: CorporationUpgrade) => (
<LevelableUpgrade rerender={rerender} upgrade={upgrade} key={upgrade.index} amount={purchaseMultiplier} />
))}
{getRecordKeys(corp.upgrades).map((name) => (
<LevelableUpgrade rerender={rerender} upgradeName={name} key={name} mult={purchaseMultiplier} />
))}
</Grid>
</Paper>
</>
@@ -228,29 +225,36 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
return (
<>
<Tooltip title={<Typography>{sellSharesTooltip}</Typography>}>
<Button disabled={sellSharesOnCd} onClick={() => setSellSharesOpen(true)}>
Sell Shares
</Button>
</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 disabled={corp.issuedShares < 1} onClick={() => setBuybackSharesOpen(true)}>
Buyback shares
</Button>
</Tooltip>
<BuybackSharesModal open={buybackSharesOpen} onClose={() => setBuybackSharesOpen(false)} rerender={rerender} />
<Tooltip title={<Typography>{issueNewSharesTooltip}</Typography>}>
<Button disabled={issueNewSharesOnCd} onClick={() => setIssueNewSharesOpen(true)}>
Issue New Shares
</Button>
</Tooltip>
<IssueNewSharesModal open={issueNewSharesOpen} onClose={() => setIssueNewSharesOpen(false)} />
<Tooltip
title={<Typography>Manage the dividends that are paid out to shareholders (including yourself)</Typography>}
<ButtonWithTooltip
normalTooltip={sellSharesTooltip}
disabledTooltip={sellSharesOnCd ? "On cooldown" : ""}
onClick={() => setSellSharesOpen(true)}
>
<Button onClick={() => setIssueDividendsOpen(true)}>Issue Dividends</Button>
</Tooltip>
Sell Shares
</ButtonWithTooltip>
<SellSharesModal open={sellSharesOpen} onClose={() => setSellSharesOpen(false)} rerender={rerender} />
<ButtonWithTooltip
normalTooltip={"Buy back shares you that previously issued or sold at market price."}
disabledTooltip={corp.issuedShares < 1 ? "No shares available to buy back" : ""}
onClick={() => setBuybackSharesOpen(true)}
>
Buyback shares
</ButtonWithTooltip>
<BuybackSharesModal open={buybackSharesOpen} onClose={() => setBuybackSharesOpen(false)} rerender={rerender} />
<ButtonWithTooltip
normalTooltip={issueNewSharesTooltip}
disabledTooltip={issueNewSharesOnCd ? "On cooldown" : ""}
onClick={() => setIssueNewSharesOpen(true)}
>
Issue New Shares
</ButtonWithTooltip>
<IssueNewSharesModal open={issueNewSharesOpen} onClose={() => setIssueNewSharesOpen(false)} />
<ButtonWithTooltip
normalTooltip={"Manage the dividends that are paid out to shareholders (including yourself)"}
onClick={() => setIssueDividendsOpen(true)}
>
Issue Dividends
</ButtonWithTooltip>
<IssueDividendsModal open={issueDividendsOpen} onClose={() => setIssueDividendsOpen(false)} />
</>
);
@@ -270,17 +274,13 @@ function BribeButton(): React.ReactElement {
return (
<>
<Tooltip
title={
canBribe
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
: "Your Corporation is not powerful enough to bribe Faction leaders"
}
<ButtonWithTooltip
normalTooltip={"Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"}
disabledTooltip={canBribe ? "" : "Your Corporation is not powerful enough to bribe Faction leaders"}
onClick={openBribe}
>
<Button disabled={!canBribe} onClick={openBribe}>
Bribe Factions
</Button>
</Tooltip>
Bribe Factions
</ButtonWithTooltip>
<BribeFactionModal open={open} onClose={() => setOpen(false)} />
</>
);
@@ -294,9 +294,9 @@ function SellDivisionButton(): React.ReactElement {
}
return (
<>
<Tooltip title={"Sell a division to make room for other divisions"}>
<Button onClick={sellDiv}>Sell division</Button>
</Tooltip>
<ButtonWithTooltip normalTooltip={"Sell a division to make room for other divisions"} onClick={sellDiv}>
Sell division
</ButtonWithTooltip>
<SellDivisionModal open={open} onClose={() => setOpen(false)} />
</>
);
@@ -311,9 +311,9 @@ function RestartButton(): React.ReactElement {
return (
<>
<Tooltip title={"Sell corporation and start over"}>
<Button onClick={restart}>Sell CEO position</Button>
</Tooltip>
<ButtonWithTooltip normalTooltip={"Sell corporation and start over"} onClick={restart}>
Sell CEO position
</ButtonWithTooltip>
<SellCorporationModal open={open} onClose={() => setOpen(false)} />
</>
);
+48 -37
View File
@@ -1,5 +1,6 @@
import React, { useState } from "react";
import type { CityName } from "src/Enums";
import * as corpConstants from "../data/Constants";
import { Product } from "../Product";
import { DiscontinueProductModal } from "./modals/DiscontinueProductModal";
@@ -19,9 +20,10 @@ import Tooltip from "@mui/material/Tooltip";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import { CorpUnlockName } from "../data/Enums";
interface IProductProps {
city: string;
city: CityName;
product: Product;
rerender: () => void;
}
@@ -41,21 +43,22 @@ export function ProductElem(props: IProductProps): React.ReactElement {
const hasUpgradeDashboard = division.hasResearch("uPgrade: Dashboard");
// Total product gain = production - sale
const totalGain = product.data[city][1] - product.data[city][2];
const totalGain = product.cityData[city].productionAmount - product.cityData[city].actualSellAmount;
// Sell button
let sellButtonText: JSX.Element;
if (product.sllman[city][0]) {
if (isString(product.sllman[city][1])) {
const desiredSellAmount = product.cityData[city].desiredSellAmount;
if (desiredSellAmount !== null) {
if (isString(desiredSellAmount)) {
sellButtonText = (
<>
Sell ({formatBigNumber(product.data[city][2])}/{product.sllman[city][1]})
Sell ({formatBigNumber(product.cityData[city].actualSellAmount)}/{desiredSellAmount})
</>
);
} else {
sellButtonText = (
<>
Sell ({formatBigNumber(product.data[city][2])}/{formatBigNumber(product.sllman[city][1])})
Sell ({formatBigNumber(product.cityData[city].actualSellAmount)}/{formatBigNumber(desiredSellAmount)})
</>
);
}
@@ -70,15 +73,16 @@ export function ProductElem(props: IProductProps): React.ReactElement {
</>
);
} else if (product.marketTa1) {
const markupLimit = product.rat / product.mku;
const markupLimit = product.rating / product.markup;
sellButtonText = (
<>
{sellButtonText} @ <Money money={product.pCost + markupLimit} />
{sellButtonText} @ <Money money={product.productionCost + markupLimit} />
</>
);
} else if (product.sCost[city]) {
if (isString(product.sCost[city])) {
const sCost = (product.sCost[city] as string).replace(/MP/g, product.pCost + product.rat / product.mku + "");
} else if (product.cityData[city].desiredSellPrice) {
const desiredSellPrice = product.cityData[city].desiredSellPrice;
if (isString(desiredSellPrice)) {
const sCost = desiredSellPrice.replace(/MP/g, product.productionCost + product.rating / product.markup + "");
sellButtonText = (
<>
{sellButtonText} @ <Money money={eval(sCost)} />
@@ -87,27 +91,26 @@ export function ProductElem(props: IProductProps): React.ReactElement {
} else {
sellButtonText = (
<>
{sellButtonText} @ <Money money={product.sCost[city]} />
{sellButtonText} @ <Money money={product.cityData[city].desiredSellPrice} />
</>
);
}
}
// Limit Production button
let limitProductionButtonText = "Limit Production";
if (product.prdman[city][0]) {
limitProductionButtonText += " (" + formatCorpStat(product.prdman[city][1]) + ")";
}
const productionLimit = product.cityData[city].productionLimit;
const limitProductionButtonText =
"Limit Production" + (productionLimit !== null ? " (" + formatCorpStat(productionLimit) + ")" : "");
return (
<Paper>
{!product.fin ? (
{!product.finished ? (
<>
<Typography>
Designing {product.name} (req. Operations/Engineers in {product.createCity})...
Designing {product.name} (req. Operations/Engineers in {product.creationCity})...
</Typography>
<br />
<Typography>{formatPercent(product.prog / 100, 2)} complete</Typography>
<Typography>{formatPercent(product.developmentProgress / 100, 2)} complete</Typography>
<Button onClick={() => setCancelOpen(true)}>Cancel</Button>
<CancelProductModal
product={product}
@@ -122,14 +125,14 @@ export function ProductElem(props: IProductProps): React.ReactElement {
<Tooltip
title={
<Typography>
Prod: {formatBigNumber(product.data[city][1])}/s
Prod: {formatBigNumber(product.cityData[city].productionAmount)}/s
<br />
Sell: {formatBigNumber(product.data[city][2])} /s
Sell: {formatBigNumber(product.cityData[city].actualSellAmount)} /s
</Typography>
}
>
<Typography>
{product.name}: {formatBigNumber(product.data[city][0])} ({formatBigNumber(totalGain)}
{product.name}: {formatBigNumber(product.cityData[city].stored)} ({formatBigNumber(totalGain)}
/s)
</Typography>
</Tooltip>
@@ -139,27 +142,35 @@ export function ProductElem(props: IProductProps): React.ReactElement {
title={
<Typography>
Effective rating is calculated from product rating and the quality of materials used <br />
Rating: {formatCorpStat(product.rat)} <br /> <br />
Quality: {formatCorpStat(product.qlt)} <br />
Performance: {formatCorpStat(product.per)} <br />
Durability: {formatCorpStat(product.dur)} <br />
Reliability: {formatCorpStat(product.rel)} <br />
Aesthetics: {formatCorpStat(product.aes)} <br />
Features: {formatCorpStat(product.fea)}
{corp.unlockUpgrades[2] === 1 && <br />}
{corp.unlockUpgrades[2] === 1 && "Demand: " + formatCorpStat(product.dmd)}
{corp.unlockUpgrades[3] === 1 && <br />}
{corp.unlockUpgrades[3] === 1 && "Competition: " + formatCorpStat(product.cmp)}
Rating: {formatCorpStat(product.rating)} <br /> <br />
Quality: {formatCorpStat(product.stats.quality)} <br />
Performance: {formatCorpStat(product.stats.performance)} <br />
Durability: {formatCorpStat(product.stats.durability)} <br />
Reliability: {formatCorpStat(product.stats.reliability)} <br />
Aesthetics: {formatCorpStat(product.stats.aesthetics)} <br />
Features: {formatCorpStat(product.stats.features)}
{corp.unlocks.has(CorpUnlockName.MarketResearchDemand) && (
<>
<br />
{"Demand: " + formatCorpStat(product.demand)}
</>
)}
{corp.unlocks.has(CorpUnlockName.MarketDataCompetition) && (
<>
<br />
{"Competition: " + formatCorpStat(product.competition)}
</>
)}
</Typography>
}
>
<Typography>Effective rating: {formatCorpStat(product.data[city][3])}</Typography>
<Typography>Effective rating: {formatCorpStat(product.cityData[city].effectiveRating)}</Typography>
</Tooltip>
</Box>
<Box display="flex">
<Tooltip title={<Typography>An estimate of the material cost it takes to create this Product.</Typography>}>
<Typography>
Est. Production Cost: {formatMoney(product.pCost / corpConstants.baseProductProfitMult)}
Est. Production Cost: {formatMoney(product.productionCost / corpConstants.baseProductProfitMult)}
</Typography>
</Tooltip>
</Box>
@@ -172,7 +183,7 @@ export function ProductElem(props: IProductProps): React.ReactElement {
</Typography>
}
>
<Typography>Est. Market Price: {formatMoney(product.pCost)}</Typography>
<Typography>Est. Market Price: {formatMoney(product.productionCost)}</Typography>
</Tooltip>
</Box>
<Button onClick={() => setDiscontinueOpen(true)}>Discontinue</Button>
@@ -185,7 +196,7 @@ export function ProductElem(props: IProductProps): React.ReactElement {
</>
)}
{(hasUpgradeDashboard || product.fin) && (
{(hasUpgradeDashboard || product.finished) && (
<>
<Button onClick={() => setSellOpen(true)}>{sellButtonText}</Button>
<SellProductModal product={product} city={city} open={sellOpen} onClose={() => setSellOpen(false)} />
@@ -1,47 +1,40 @@
// React Components for the Unlock upgrade buttons on the overview page
import React from "react";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { CorporationUnlockUpgrade } from "../data/CorporationUnlockUpgrades";
import { CorpUnlocks } from "../data/CorporationUnlocks";
import { useCorporation } from "./Context";
import { UnlockUpgrade as UU } from "../Actions";
import { MoneyCost } from "./MoneyCost";
import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
import { CorpUnlockName } from "../data/Enums";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
interface IProps {
upgradeData: CorporationUnlockUpgrade;
interface UnlockProps {
name: CorpUnlockName;
rerender: () => void;
}
export function UnlockUpgrade(props: IProps): React.ReactElement {
export function Unlock(props: UnlockProps): React.ReactElement {
const corp = useCorporation();
const data = props.upgradeData;
const data = CorpUnlocks[props.name];
const tooltip = data.desc;
const price = corp.unlockUpgrades[data.index] === 0 ? data.price : 0;
const price = data.price;
function onClick(): void {
if (corp.unlockUpgrades[data.index] === 1) return;
if (corp.funds < data.price) return;
try {
UU(corp, props.upgradeData);
} catch (err) {
dialogBoxCreate(err + "");
}
// corp.unlock handles displaying a dialog on failure
const message = corp.purchaseUnlock(props.name);
if (message) dialogBoxCreate(`Error while attempting to purchase ${props.name}:\n${message}`);
// Rerenders the parent, which should remove this item if the purchase was successful
props.rerender();
}
return (
<Grid item xs={4}>
<Box display="flex" alignItems="center" flexDirection="row-reverse">
<Button
disabled={corp.funds < data.price || corp.unlockUpgrades[data.index] === 1}
sx={{ mx: 1 }}
onClick={onClick}
>
<Button disabled={corp.funds < data.price || corp.unlocks.has(props.name)} sx={{ mx: 1 }} onClick={onClick}>
<MoneyCost money={price} corp={corp} />
</Button>
<Tooltip title={tooltip}>
@@ -4,11 +4,12 @@ import { formatBigNumber, formatMoney } from "../../../ui/formatNumber";
import { Player } from "@player";
import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
import { NumberInput } from "../../../ui/React/NumberInput";
import { BuyBackShares } from "../../Actions";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { KEY } from "../../../utils/helpers/keyCodes";
import { isPositiveInteger } from "../../../types";
interface IProps {
open: boolean;
@@ -24,15 +25,16 @@ 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;
const disabledText = !isPositiveInteger(shares)
? "Number of shares must be a positive integer"
: shares > corp.issuedShares
? "There are not enough shares available to buyback this many"
: shares * buybackPrice > Player.money
? "Insufficient player funds"
: "";
function buy(): void {
if (disabled) return;
if (disabledText) return;
try {
BuyBackShares(corp, shares);
} catch (err) {
@@ -82,9 +84,9 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
<CostIndicator />
<br />
<NumberInput autoFocus={true} placeholder="Shares to buyback" onChange={setShares} onKeyDown={onKeyDown} />
<Button disabled={disabled} onClick={buy}>
<ButtonWithTooltip disabledTooltip={disabledText} onClick={buy}>
Buy shares
</Button>
</ButtonWithTooltip>
</Modal>
);
}
@@ -17,7 +17,7 @@ interface IProps {
export function CancelProductModal(props: IProps): React.ReactElement {
const division = useDivision();
function cancel(): void {
division.discontinueProduct(props.product);
division.discontinueProduct(props.product.name);
props.onClose();
props.rerender();
}
@@ -6,7 +6,7 @@ import { Router } from "../../../ui/GameRoot";
import { Page } from "../../../ui/Router";
import { Player } from "@player";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
import TextField from "@mui/material/TextField";
interface IProps {
@@ -16,12 +16,15 @@ interface IProps {
export function CreateCorporationModal(props: IProps): React.ReactElement {
const canSelfFund = Player.canAfford(150e9);
const [name, setName] = useState("");
if (!Player.canAccessCorporation() || Player.corporation) {
props.onClose();
return <></>;
}
const [name, setName] = useState("");
const disabledTextForNoName = name === "" ? "Enter a name for the corporation" : "";
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
setName(event.target.value);
}
@@ -62,13 +65,16 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
</Typography>
<TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} />
{Player.bitNodeN === 3 && (
<Button onClick={seed} disabled={name == ""}>
<ButtonWithTooltip onClick={seed} disabledTooltip={disabledTextForNoName}>
Use seed money
</Button>
</ButtonWithTooltip>
)}
<Button onClick={selfFund} disabled={name == "" || !canSelfFund}>
<ButtonWithTooltip
onClick={selfFund}
disabledTooltip={disabledTextForNoName || canSelfFund ? "" : "Insufficient player funds"}
>
Self-Fund (<Money money={150e9} forPurchase={true} />)
</Button>
</ButtonWithTooltip>
</Modal>
);
}
@@ -17,7 +17,7 @@ interface IProps {
export function DiscontinueProductModal(props: IProps): React.ReactElement {
const division = useDivision();
function discontinue(): void {
division.discontinueProduct(props.product);
division.discontinueProduct(props.product.name);
props.onClose();
props.rerender();
}
+40 -41
View File
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Material } from "../../Material";
import { Export } from "../../Export";
import { Industry } from "../../Industry";
import { Division } from "../../Division";
import { ExportMaterial } from "../../Actions";
import { Modal } from "../../../ui/React/Modal";
import { useCorporation } from "../Context";
@@ -15,6 +15,7 @@ import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { CityName } from "../../../Enums";
import { useRerender } from "../../../ui/React/hooks";
import { getRecordKeys } from "../../../Types/Record";
interface IProps {
open: boolean;
@@ -25,33 +26,35 @@ interface IProps {
// Create a popup that lets the player manage exports
export function ExportModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const possibleDivisions = corp.divisions.filter((division: Industry) => isRelevantMaterial(props.mat.name, division));
const possibleDivisions = [...corp.divisions.values()].filter((division: Division) => {
return isRelevantMaterial(props.mat.name, division);
});
if (possibleDivisions.length === 0) throw new Error("Export popup created with no divisions.");
const defaultDivision = possibleDivisions[0];
if (Object.keys(defaultDivision.warehouses).length === 0)
throw new Error("Export popup created in a division with no warehouses.");
const [industry, setIndustry] = useState<string>(defaultDivision.name);
const [city, setCity] = useState(Object.keys(defaultDivision.warehouses)[0] as CityName);
const [amt, setAmt] = useState("");
const [targetDivision, setTargetDivision] = useState(defaultDivision);
const [targetCity, setTargetCity] = useState(CityName.Sector12);
const [exportAmount, setExportAmount] = useState("");
const rerender = useRerender();
function onCityChange(event: SelectChangeEvent): void {
setCity(event.target.value as CityName);
function onCityChange(event: SelectChangeEvent<CityName>): void {
setTargetCity(event.target.value as CityName);
}
function onIndustryChange(event: SelectChangeEvent): void {
const div = event.target.value;
setIndustry(div);
setCity(Object.keys(corp.divisions[0].warehouses)[0] as CityName);
function onTargetDivisionChange(event: SelectChangeEvent): void {
const division = corp.divisions.get(event.target.value);
if (!division) return;
setTargetDivision(division);
}
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
setAmt(event.target.value);
setExportAmount(event.target.value);
}
function exportMaterial(): void {
try {
ExportMaterial(industry, city, props.mat, amt, currentDivision);
ExportMaterial(targetDivision.name, targetCity, props.mat, exportAmount, targetDivision);
} catch (err) {
dialogBoxCreate(err + "");
}
@@ -59,23 +62,22 @@ export function ExportModal(props: IProps): React.ReactElement {
}
function removeExport(exp: Export): void {
for (let i = 0; i < props.mat.exp.length; ++i) {
if (props.mat.exp[i].ind !== exp.ind || props.mat.exp[i].city !== exp.city || props.mat.exp[i].amt !== exp.amt)
for (let i = 0; i < props.mat.exports.length; ++i) {
if (
props.mat.exports[i].division !== exp.division ||
props.mat.exports[i].city !== exp.city ||
props.mat.exports[i].amount !== exp.amount
)
continue;
props.mat.exp.splice(i, 1);
props.mat.exports.splice(i, 1);
break;
}
rerender();
}
const currentDivision = corp.divisions.find((division: Industry) => division.name === industry);
if (currentDivision === undefined)
throw new Error(`Export popup somehow ended up with undefined division '${currentDivision}'`);
const possibleCities = (Object.keys(currentDivision.warehouses) as CityName[]).filter(
(city) => currentDivision.warehouses[city] !== 0,
);
if (possibleCities.length > 0 && !possibleCities.includes(city)) {
setCity(possibleCities[0]);
const possibleCities = getRecordKeys(targetDivision.warehouses);
if (possibleCities.length > 0 && !possibleCities.includes(targetCity)) {
setTargetCity(possibleCities[0]);
}
return (
@@ -102,42 +104,39 @@ export function ExportModal(props: IProps): React.ReactElement {
<br />
For example: setting the amount "(EINV-20)/10" would try to export all except 20 of the material.
</Typography>
<Select onChange={onIndustryChange} value={industry}>
{corp.divisions
.filter((division: Industry) => isRelevantMaterial(props.mat.name, division))
.map((division: Industry) => (
<Select onChange={onTargetDivisionChange} value={targetDivision.name}>
{[...corp.divisions.values()]
.filter((division) => isRelevantMaterial(props.mat.name, division))
.map((division) => (
<MenuItem key={division.name} value={division.name}>
{division.name}
</MenuItem>
))}
</Select>
<Select onChange={onCityChange} value={city}>
{possibleCities.map((cityName) => {
if (currentDivision.warehouses[cityName] === 0) return;
return (
<MenuItem key={cityName} value={cityName}>
{cityName}
</MenuItem>
);
})}
<Select onChange={onCityChange} value={targetCity}>
{possibleCities.map((cityName) => (
<MenuItem key={cityName} value={cityName}>
{cityName}
</MenuItem>
))}
</Select>
<TextField placeholder="Export amount / s" onChange={onAmtChange} value={amt} />
<TextField placeholder="Export amount / s" onChange={onAmtChange} value={exportAmount} />
<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.
</Typography>
{props.mat.exp.map((exp: Export, index: number) => (
{props.mat.exports.map((exp: Export, index: number) => (
<Box display="flex" alignItems="center" key={index}>
<Button sx={{ mx: 2 }} onClick={() => removeExport(exp)}>
delete
</Button>
<Typography>
Industry: {exp.ind}
Industry: {exp.division}
<br />
City: {exp.city}
<br />
Amount/s: {exp.amt}
Amount/s: {exp.amount}
</Typography>
</Box>
))}
+13 -12
View File
@@ -4,10 +4,11 @@ import { Modal } from "../../../ui/React/Modal";
import { formatMoney, formatShares } from "../../../ui/formatNumber";
import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { ButtonWithTooltip } from "../../../ui/Components/ButtonWithTooltip";
import { NumberInput } from "../../../ui/React/NumberInput";
import Box from "@mui/material/Box";
import { KEY } from "../../../utils/helpers/keyCodes";
import { isPositiveInteger } from "../../../types";
interface IProps {
open: boolean;
@@ -23,14 +24,7 @@ export function GoPublicModal(props: IProps): React.ReactElement {
function goPublic(): void {
const initialSharePrice = corp.valuation / corp.totalShares;
if (isNaN(shares)) {
dialogBoxCreate("Invalid value for number of issued shares");
return;
}
if (shares > corp.numShares) {
dialogBoxCreate("Error: You don't have that many shares to issue!");
return;
}
if (shares >= corp.numShares || (shares !== 0 && !isPositiveInteger(shares))) return;
corp.public = true;
corp.sharePrice = initialSharePrice;
corp.issuedShares = shares;
@@ -47,6 +41,13 @@ export function GoPublicModal(props: IProps): React.ReactElement {
if (event.key === KEY.ENTER) goPublic();
}
const disabledText =
shares >= corp.numShares
? "Cannot issue this many shares"
: shares !== 0 && !isPositiveInteger(shares)
? "Must issue an non-negative integer number of shares"
: "";
return (
<Modal open={props.open} onClose={props.onClose}>
<Typography>
@@ -55,13 +56,13 @@ export function GoPublicModal(props: IProps): React.ReactElement {
be deposited directly into your Corporation's funds).
<br />
<br />
You have a total of {formatShares(corp.numShares)}-1 shares that you can issue. You cannot sell all your shares.
You can issue some, but not all, of your {formatShares(corp.numShares)} shares.
</Typography>
<Box display="flex" alignItems="center">
<NumberInput onChange={setShares} autoFocus placeholder="Shares to issue" onKeyDown={onKeyDown} />
<Button disabled={shares < 0 || shares >= corp.numShares} sx={{ mx: 1 }} onClick={goPublic}>
<ButtonWithTooltip disabledTooltip={disabledText} onClick={goPublic}>
Go Public
</Button>
</ButtonWithTooltip>
</Box>
</Modal>
);
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import { Product } from "../../Product";
import type { CityName } from "../../../Enums";
import type { Product } from "../../Product";
import { LimitProductProduction } from "../../Actions";
import { Modal } from "../../../ui/React/Modal";
import Typography from "@mui/material/Typography";
@@ -11,7 +12,7 @@ interface IProps {
open: boolean;
onClose: () => void;
product: Product;
city: string;
city: CityName;
}
// Create a popup that lets the player limit the production of a product
@@ -13,6 +13,7 @@ import Select, { SelectChangeEvent } from "@mui/material/Select";
import { KEY } from "../../../utils/helpers/keyCodes";
import { NumberInput } from "../../../ui/React/NumberInput";
import { CityName } from "../../../Enums";
import { getRecordKeys } from "../../../Types/Record";
interface IProps {
open: boolean;
@@ -34,8 +35,8 @@ function productPlaceholder(type: string): string {
export function MakeProductModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const allCities = Object.values(CityName).filter((cityName) => division.offices[cityName] !== 0);
const [city, setCity] = useState(allCities.length > 0 ? allCities[0] : CityName.Sector12);
const availableCities = getRecordKeys(division.offices);
const [city, setCity] = useState(availableCities.length > 0 ? availableCities[0] : CityName.Sector12);
const [name, setName] = useState("");
const [design, setDesign] = useState<number>(NaN);
const [marketing, setMarketing] = useState<number>(NaN);
@@ -80,7 +81,7 @@ export function MakeProductModal(props: IProps): React.ReactElement {
will result in a superior product. Investing money in marketing the product will help the product's sales.
</Typography>
<Select style={{ margin: "5px" }} onChange={onCityChange} defaultValue={city}>
{allCities.map((cityName: string) => (
{availableCities.map((cityName: string) => (
<MenuItem key={cityName} value={cityName}>
{cityName}
</MenuItem>
@@ -63,8 +63,8 @@ export function MaterialMarketTaModal(props: IProps): React.ReactElement {
<>
<Typography variant="h4">Market-TA.I</Typography>
<Typography>
The maximum sale price you can mark this up to is {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
The maximum sale price you can mark this up to is {formatMoney(props.mat.marketPrice + markupLimit)}. This
means that if you set the sale price higher than this, you will begin to experience a loss in number of sales
<br></br>
<br></br>
If this is enabled, then this Material will automatically be sold at the price identified by Market-TA.I (i.e.
@@ -48,7 +48,7 @@ interface IProps {
// Create a popup that lets the player use the Market TA research for Products
export function ProductMarketTaModal(props: IProps): React.ReactElement {
const markupLimit = props.product.rat / props.product.mku;
const markupLimit = props.product.rating / props.product.markup;
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@@ -64,8 +64,9 @@ export function ProductMarketTaModal(props: IProps): React.ReactElement {
<>
<Typography variant="h4">Market-TA.I</Typography>
<Typography>
The maximum sale price you can mark this up to is {formatMoney(props.product.pCost + markupLimit)}. This means
that if you set the sale price higher than this, you will begin to experience a loss in number of sales
The maximum sale price you can mark this up to is {formatMoney(props.product.productionCost + markupLimit)}.
This means that if you set the sale price higher than this, you will begin to experience a loss in number of
sales
<br></br>
<br></br>
If this is enabled, then this product will automatically be sold at the price identified by Market-TA.I (i.e.
@@ -31,7 +31,7 @@ function BulkPurchaseSection(props: IBPProps): React.ReactElement {
function BulkPurchaseText(props: IBulkPurchaseTextProps): React.ReactElement {
const parsedAmt = parseFloat(props.amount);
const cost = parsedAmt * props.mat.bCost;
const cost = parsedAmt * props.mat.marketPrice;
const matSize = MaterialInfo[props.mat.name].size;
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
@@ -110,7 +110,7 @@ interface IProps {
// Create a popup that lets the player purchase a Material
export function PurchaseMaterialModal(props: IProps): React.ReactElement {
const [buyAmt, setBuyAmt] = useState(props.mat.buy ? props.mat.buy : 0);
const [buyAmt, setBuyAmt] = useState(props.mat.buyAmount ? props.mat.buyAmount : 0);
function purchaseMaterial(): void {
if (buyAmt === null) return;
@@ -124,7 +124,7 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
}
function clearPurchase(): void {
props.mat.buy = 0;
props.mat.buyAmount = 0;
props.onClose();
}
@@ -138,29 +138,27 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
return (
<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.
{props.disablePurchaseLimit ? "Note: Purchase amount is disabled as smart supply is enabled" : ""}
</Typography>
<TextField
value={buyAmt}
onChange={onChange}
autoFocus={true}
placeholder="Purchase amount"
type="number"
disabled={props.disablePurchaseLimit}
onKeyDown={onKeyDown}
/>
<Button disabled={props.disablePurchaseLimit} onClick={purchaseMaterial}>
Confirm
</Button>
<Button disabled={props.disablePurchaseLimit} onClick={clearPurchase}>
Clear Purchase
</Button>
{<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />}
</>
<Typography>
Enter the amount of {props.mat.name} you would like to purchase per second. This material's cost changes
constantly.
{props.disablePurchaseLimit ? "Note: Purchase amount is disabled as smart supply is enabled" : ""}
</Typography>
<TextField
value={buyAmt}
onChange={onChange}
autoFocus={true}
placeholder="Purchase amount"
type="number"
disabled={props.disablePurchaseLimit}
onKeyDown={onKeyDown}
/>
<Button disabled={props.disablePurchaseLimit} onClick={purchaseMaterial}>
Confirm
</Button>
<Button disabled={props.disablePurchaseLimit} onClick={clearPurchase}>
Clear Purchase
</Button>
{<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />}
</Modal>
);
}
+12 -12
View File
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { Modal } from "../../../ui/React/Modal";
import { IndustryResearchTrees } from "../../IndustryData";
import * as corpConstants from "../../data/Constants";
import { Industry } from "../../Industry";
import { Division } from "../../Division";
import { Research } from "../../Actions";
import { Node } from "../../ResearchTree";
import { ResearchMap } from "../../ResearchMap";
@@ -20,13 +20,13 @@ import CheckIcon from "@mui/icons-material/Check";
interface INodeProps {
n: Node | null;
division: Industry;
division: Division;
}
function Upgrade({ n, division }: INodeProps): React.ReactElement {
const [open, setOpen] = useState(false);
if (n === null) return <></>;
const r = ResearchMap[n.text];
let disabled = division.sciResearch < r.cost || n.researched;
const r = ResearchMap[n.researchName];
let disabled = division.researchPoints < r.cost || n.researched;
const parent = n.parent;
if (parent !== null) {
disabled = disabled || !parent.researched;
@@ -35,14 +35,14 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
function research(): void {
if (n === null || disabled) return;
try {
Research(division, n.text);
Research(division, n.researchName);
} catch (err) {
dialogBoxCreate(err + "");
return;
}
dialogBoxCreate(
`Researched ${n.text}. It may take a market cycle (~${corpConstants.secondsPerMarketCycle} seconds) before the effects of the Research apply.`,
`Researched ${n.researchName}. It may take a market cycle (~${corpConstants.secondsPerMarketCycle} seconds) before the effects of the Research apply.`,
);
}
@@ -58,7 +58,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
<Typography>
Research points: {r.cost}
<br />
{r.desc}
{r.description}
</Typography>
}
>
@@ -78,7 +78,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
style={{ width: "100%", textAlign: "left", justifyContent: "unset" }}
>
{n.researched && <CheckIcon sx={{ mr: 1 }} />}
{n.text}
{n.researchName}
</Button>
</span>,
)}
@@ -104,7 +104,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
}}
>
{n.researched && <CheckIcon sx={{ mr: 1 }} />}
{n.text}
{n.researchName}
</Button>
</span>,
)}
@@ -118,7 +118,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
<Collapse in={open} unmountOnExit>
<Box m={1}>
{n.children.map((m) => (
<Upgrade key={m.text} division={division} n={m} />
<Upgrade key={m.researchName} division={division} n={m} />
))}
</Box>
</Collapse>
@@ -129,7 +129,7 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
interface IProps {
open: boolean;
onClose: () => void;
industry: Industry;
industry: Division;
}
// Create the Research Tree UI for this Industry
@@ -141,7 +141,7 @@ export function ResearchModal(props: IProps): React.ReactElement {
<Modal open={props.open} onClose={props.onClose}>
<Upgrade division={props.industry} n={researchTree.root} />
<Typography sx={{ mt: 1 }}>
Research points: {props.industry.sciResearch.toFixed(3)}
Research points: {props.industry.researchPoints.toFixed(3)}
<br />
Multipliers from research:
<br />* Advertising Multiplier: x{researchTree.getAdvertisingMultiplier()}
+43 -60
View File
@@ -1,18 +1,17 @@
import React, { useState } from "react";
import type { Industry } from "src/Corporation/Industry";
import { Modal } from "../../../ui/React/Modal";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import MenuItem from "@mui/material/MenuItem";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { useCorporation } from "../../ui/Context";
import { CityName } from "@nsdefs";
import { CityName } from "../../../Enums";
import * as corpConstants from "../../data/Constants";
import { formatMoney, formatNumber } from "../../../ui/formatNumber";
import { removeIndustry } from "../../Actions";
import { formatMoney } from "../../../ui/formatNumber";
import { removeIndustry as removeDivision } from "../../Actions";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { getRecordKeys } from "../../../Types/Record";
interface IProps {
open: boolean;
@@ -21,81 +20,65 @@ interface IProps {
export function SellDivisionModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const allIndustries = Object.values(corp.divisions).sort();
const [industry, setIndustry] = useState(allIndustries[0]);
const allDivisions = [...corp.divisions.values()];
const [divisionToSell, setDivisionToSell] = useState(allDivisions[0]);
if (allDivisions.length === 0) return <></>;
const price = calculatePrice();
function calculatePrice() {
let price = industry.startingCost;
for (const city in industry.offices) {
if (industry.offices[city as CityName] === 0) continue;
if (city === "Sector-12") continue;
let price = divisionToSell.startingCost;
for (const city of getRecordKeys(divisionToSell.offices)) {
if (city === CityName.Sector12) continue;
price += corpConstants.officeInitialCost;
if (industry.warehouses[city as CityName] !== 0) price += corpConstants.warehouseInitialCost;
if (divisionToSell.warehouses[city]) price += corpConstants.warehouseInitialCost;
}
price /= 2;
return price;
}
function onIndustryChange(event: SelectChangeEvent): void {
setIndustry(corp.divisions.find((div) => div.name === event.target.value) as Industry);
}
function sum(total: number, num: number) {
return total + num;
function onDivisionChange(event: SelectChangeEvent): void {
const div = corp.divisions.get(event.target.value);
if (!div) return;
setDivisionToSell(div);
}
function sellDivision() {
removeIndustry(corp, industry.name);
removeDivision(corp, divisionToSell.name);
corp.funds += price;
props.onClose();
dialogBoxCreate(
<>
Sold {industry.name} for {formatMoney(price)}, you now have space for{" "}
{corp.maxDivisions - corp.divisions.length} more divisions.
</>,
`Sold ${divisionToSell.name} for ${formatMoney(price)}, you now have space for ${
corp.maxDivisions - corp.divisions.size
} more divisions.`,
);
}
return (
<Modal open={props.open} onClose={props.onClose}>
<Typography>
Would you like to sell a division?
<br></br>
You'll get back half the money you've spent on starting the division and expanding to offices and warehouses.
</Typography>
<Select value={industry.name} onChange={onIndustryChange}>
{allIndustries.map((industry) => (
<MenuItem key={industry.name} value={industry.name}>
{industry.name}
</MenuItem>
))}
</Select>
<Typography>
Division {industry.name} has:
<br></br>- Profit: ${formatNumber((industry.lastCycleRevenue - industry.lastCycleExpenses) / 10)} / sec
<br></br>- Cities:{" "}
{Object.keys(industry.offices)
.map((city) => (industry.offices[city as CityName] ? 1 : 0))
.reduce(sum, 0)}
<br></br>- Warehouses:{" "}
{Object.keys(industry.warehouses)
.map((city) => (industry.warehouses[city as CityName] ? 1 : 0))
.reduce(sum, 0)}
{industry.makesProducts ?? (
<Typography>
{" "}
<br></br>- Products: {industry.products.length}{" "}
</Typography>
)}
<br></br>
<br></br>
Sell price: {formatNumber(price)}
</Typography>
<Button disabled={false} onClick={sellDivision}>
Sell division
</Button>
<>
<Typography>
Would you like to sell a division?
<br></br>
You'll get back half the money you've spent on starting the division and expanding to offices and warehouses.
</Typography>
<Select value={divisionToSell.name} onChange={onDivisionChange}>
{allDivisions.map((div) => (
<MenuItem key={div.name} value={div.name}>
{div.name}
</MenuItem>
))}
</Select>
<Typography>Division {divisionToSell.name} has:</Typography>
<Typography>
Profit: {formatMoney((divisionToSell.lastCycleRevenue - divisionToSell.lastCycleExpenses) / 10)} / sec{" "}
</Typography>
<Typography>Cities:{getRecordKeys(divisionToSell.offices).length}</Typography>
<Typography>Warehouses:{getRecordKeys(divisionToSell.warehouses).length}</Typography>
{divisionToSell.makesProducts ?? <Typography>Products: {divisionToSell.products.size}</Typography>}
<br />
<Typography>Sell price: {formatMoney(price)}</Typography>
<Button onClick={sellDivision}>Sell division</Button>
</>
</Modal>
);
}
@@ -9,7 +9,7 @@ import Button from "@mui/material/Button";
import { KEY } from "../../../utils/helpers/keyCodes";
function initialPrice(mat: Material): string {
let val = mat.sCost ? mat.sCost + "" : "";
let val = mat.desiredSellPrice ? mat.desiredSellPrice + "" : "";
if (mat.marketTa2) {
val += " (Market-TA.II)";
} else if (mat.marketTa1) {
@@ -26,7 +26,7 @@ interface IProps {
// Create a popup that let the player manage sales of a material
export function SellMaterialModal(props: IProps): React.ReactElement {
const [amt, setAmt] = useState<string>(props.mat.sllman[1] ? props.mat.sllman[1] + "" : "");
const [amt, setAmt] = useState<string>(props.mat.desiredSellAmount + "");
const [price, setPrice] = useState<string>(initialPrice(props.mat));
function sellMaterial(): void {
@@ -10,9 +10,10 @@ import Button from "@mui/material/Button";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import { KEY } from "../../../utils/helpers/keyCodes";
import { CityName } from "../../../Enums";
function initialPrice(product: Product, city: string): string {
let val = product.sCost[city] ? product.sCost[city] + "" : "";
function initialPrice(product: Product, city: CityName): string {
let val = String(product.cityData[city].desiredSellPrice || "");
if (product.marketTa2) {
val += " (Market-TA.II)";
} else if (product.marketTa1) {
@@ -25,15 +26,13 @@ interface IProps {
open: boolean;
onClose: () => void;
product: Product;
city: string;
city: CityName;
}
// Create a popup that let the player manage sales of a material
export function SellProductModal(props: IProps): React.ReactElement {
const [checked, setChecked] = useState(true);
const [iQty, setQty] = useState<string>(
props.product.sllman[props.city][1] ? props.product.sllman[props.city][1] : "",
);
const [iQty, setQty] = useState<string>((props.product.cityData[props.city].desiredSellAmount ?? "").toString());
const [px, setPx] = useState<string>(initialPrice(props.product, props.city));
function onCheckedChange(event: React.ChangeEvent<HTMLInputElement>): void {
@@ -82,7 +82,7 @@ export function SmartSupplyModal(props: IProps): React.ReactElement {
const mats = [];
for (const matName of Object.values(materialNames)) {
if (!props.warehouse.materials[matName]) continue;
if (!Object.keys(division.reqMats).includes(matName)) continue;
if (!Object.keys(division.requiredMaterials).includes(matName)) continue;
mats.push(<SSoption key={matName} warehouse={props.warehouse} matName={matName} />);
}
@@ -23,7 +23,7 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
const corp = useCorporation();
const [cost, setCost] = useState(0);
const totalCost = cost * props.office.totalEmployees;
const totalCost = cost * props.office.numEmployees;
const canParty = corp.funds >= totalCost;
function changeCost(event: React.ChangeEvent<HTMLInputElement>): void {
let x = parseFloat(event.target.value);