mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-05-02 22:07:06 +02:00
CORPORATION: Corp changes prior to 2.3 finalization (#503)
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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} />}
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { CityName } from "../../Enums";
|
||||
|
||||
interface IProps {
|
||||
city: CityName;
|
||||
warehouse: Warehouse | 0;
|
||||
warehouse?: Warehouse;
|
||||
office: OfficeSpace;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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: {convertEffectFacToGraphic(division.hwFac)}
|
||||
Hardware: {convertEffectFacToGraphic(division.hardwareFactor)}
|
||||
<br />
|
||||
Robots: {convertEffectFacToGraphic(division.robFac)}
|
||||
Robots: {convertEffectFacToGraphic(division.robotFactor)}
|
||||
<br />
|
||||
AI Cores: {convertEffectFacToGraphic(division.aiFac)}
|
||||
AI Cores: {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 - <MoneyCost money={division.getAdVertCost()} corp={corp} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
Hire AdVert - <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");
|
||||
}
|
||||
|
||||
@@ -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 -
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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} -
|
||||
<MoneyCost money={cost} corp={corp} />
|
||||
</Button>
|
||||
<ButtonWithTooltip
|
||||
disabledTooltip={corp.funds < cost || amount === 0 ? "Insufficient corporation funds" : ""}
|
||||
onClick={onClick}
|
||||
>
|
||||
+{amount} - <MoneyCost money={cost} corp={corp} />
|
||||
</ButtonWithTooltip>
|
||||
<Tooltip title={tooltip}>
|
||||
<Typography>
|
||||
{data.name} - lvl {level}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)} />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user