more conversion

This commit is contained in:
Olivier Gagnon 2021-09-01 22:16:48 -04:00
parent 65158e4db7
commit d3aeda8ad5
13 changed files with 404 additions and 343 deletions

@ -0,0 +1,73 @@
import { ICorporation } from "./ICorporation";
import { IIndustry } from "./IIndustry";
import { IndustryStartingCosts } from "./IndustryData";
import { Industry } from "./Industry";
import { CorporationConstants } from "./data/Constants";
import { OfficeSpace } from "./OfficeSpace";
import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade } from "./data/CorporationUpgrades";
export function NewIndustry(corporation: ICorporation, industry: string, name: string): void {
for (let i = 0; i < corporation.divisions.length; ++i) {
if (corporation.divisions[i].name === name) {
throw new Error("This division name is already in use!");
return;
}
}
const cost = IndustryStartingCosts[industry];
if(cost === undefined) {
throw new Error("Invalid industry: ${industry}");
}
if (corporation.funds.lt(cost)) {
throw new Error("Not enough money to create a new division in this industry");
} else if (name === "") {
throw new Error("New division must have a name!");
} else {
corporation.funds = corporation.funds.minus(cost);
corporation.divisions.push(new Industry({
corp: corporation,
name: name,
type: industry,
}));
}
}
export function NewCity(corporation: ICorporation, division: IIndustry, city: string): void {
if (corporation.funds.lt(CorporationConstants.OfficeInitialCost)) {
throw new Error("You don't have enough company funds to open a new office!");
} else {
corporation.funds = corporation.funds.minus(CorporationConstants.OfficeInitialCost);
division.offices[city] = new OfficeSpace({
loc: city,
size: CorporationConstants.OfficeInitialSize,
});
}
}
export function UnlockUpgrade(corporation: ICorporation, upgrade: CorporationUnlockUpgrade): void {
if (corporation.funds.lt(upgrade[1])) {
throw new Error("Insufficient funds");
}
corporation.unlock(upgrade);
}
export function LevelUpgrade(corporation: ICorporation, upgrade: CorporationUpgrade): void {
const baseCost = upgrade[1];
const priceMult = upgrade[2];
const level = corporation.upgrades[upgrade[0]];
const cost = baseCost * Math.pow(priceMult, level);
if (corporation.funds.lt(cost)) {
throw new Error("Insufficient funds");
} else {
corporation.upgrade(upgrade);
}
}
export function IssueDividends(corporation: ICorporation, percent: number): void {
if (isNaN(percent) || percent < 0 || percent > CorporationConstants.DividendMaxPercentage) {
throw new Error(`Invalid value. Must be an integer between 0 and ${CorporationConstants.DividendMaxPercentage}`);
}
corporation.dividendPercentage = percent*100;
}

@ -132,7 +132,7 @@ export class Corporation {
// Process dividends
if (this.dividendPercentage > 0 && cycleProfit > 0) {
// Validate input again, just to be safe
if (isNaN(this.dividendPercentage) || this.dividendPercentage < 0 || this.dividendPercentage > CorporationConstants.DividendMaxPercentage) {
if (isNaN(this.dividendPercentage) || this.dividendPercentage < 0 || this.dividendPercentage > CorporationConstants.DividendMaxPercentage*100) {
console.error(`Invalid Corporation dividend percentage: ${this.dividendPercentage}`);
} else {
const totalDividends = (this.dividendPercentage / 100) * cycleProfit;

@ -49,7 +49,7 @@ export const CorporationConstants: {
ProductProductionCostRatio: 5, //Ratio of material cost of a product to its production cost
DividendMaxPercentage: 50,
DividendMaxPercentage: .5,
EmployeeSalaryMultiplier: 3, // Employee stats multiplied by this to determine initial salary
CyclesPerEmployeeRaise: 400, // All employees get a raise every X market cycles

@ -31,7 +31,8 @@ export function CityTabs(props: IProps): React.ReactElement {
return <>
{
Object.keys(props.onClicks).map((cityName: string) => <CityTab current={props.city === cityName} key={cityName} name={cityName} onClick={props.onClicks[cityName]} />,
Object.keys(props.onClicks).map((cityName: string) =>
<CityTab current={props.city === cityName} key={cityName} name={cityName} onClick={props.onClicks[cityName]} />,
)
}
<CityTab

@ -6,6 +6,7 @@ import { removePopup } from "../../ui/React/createPopup";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { OfficeSpace } from "../OfficeSpace";
import { ICorporation } from "../ICorporation";
import { NewCity } from "../Actions";
interface IProps {
popupId: string;
@ -19,19 +20,16 @@ export function ExpandNewCityPopup(props: IProps): React.ReactElement {
function expand(): void {
if(dropdown.current === null) return;
const city = dropdown.current.value;
if (props.corp.funds.lt(CorporationConstants.OfficeInitialCost)) {
dialogBoxCreate("You don't have enough company funds to open a new office!");
} else {
props.corp.funds = props.corp.funds.minus(CorporationConstants.OfficeInitialCost);
dialogBoxCreate(`Opened a new office in ${city}!`);
props.division.offices[city] = new OfficeSpace({
loc: city,
size: CorporationConstants.OfficeInitialSize,
});
try {
NewCity(props.corp, props.division, dropdown.current.value);
} catch(err) {
dialogBoxCreate(err);
return;
}
props.cityStateSetter(city);
dialogBoxCreate(`Opened a new office in ${dropdown.current.value}!`);
props.cityStateSetter(dropdown.current.value);
removePopup(props.popupId);
}
return (<>

@ -11,6 +11,7 @@ import { createProgressBarText } from "../../../utils/helpers/createProgressB
import { MakeProductPopup } from "./MakeProductPopup";
import { ResearchPopup } from "./ResearchPopup";
import { createPopup } from "../../ui/React/createPopup";
import { Money } from "../../ui/React/Money";
import { ICorporation } from "../ICorporation";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { CorporationRouting } from "./Routing";
@ -114,10 +115,6 @@ export function IndustryOverview(props: IProps): React.ReactElement {
const vechain = (corp.unlockUpgrades[4] === 1);
const profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber();
const genInfo = `Industry: ${division.type} (Corp Funds: ${numeralWrapper.formatMoney(corp.funds.toNumber())})`;
const awareness = `Awareness: ${numeralWrapper.format(division.awareness, "0.000")}`;
const popularity = `Popularity: ${numeralWrapper.format(division.popularity, "0.000")}`;
let advertisingInfo = false;
const advertisingFactors = division.getAdvertisingFactors();
const awarenessFac = advertisingFactors[1];
@ -126,10 +123,6 @@ export function IndustryOverview(props: IProps): React.ReactElement {
const totalAdvertisingFac = advertisingFactors[0];
if (vechain) { advertisingInfo = true; }
const revenue = `Revenue: ${numeralWrapper.formatMoney(division.lastCycleRevenue.toNumber())} / s`;
const expenses = `Expenses: ${numeralWrapper.formatMoney(division.lastCycleExpenses.toNumber())} /s`;
const profitStr = `Profit: ${numeralWrapper.formatMoney(profit)} / s`;
function productionMultHelpTipOnClick(): void {
if(division === null) return;
// Wrapper for createProgressBarText()
@ -171,10 +164,10 @@ export function IndustryOverview(props: IProps): React.ReactElement {
return (
<div>
{genInfo}
Industry: {division.type} (Corp Funds: {Money(corp.funds.toNumber())})
<br /> <br />
{awareness} <br />
{popularity} <br />
Awareness: {numeralWrapper.format(division.awareness, "0.000")} <br />
Popularity: {numeralWrapper.format(division.popularity, "0.000")} <br />
{
(advertisingInfo !== false) &&
<p className={"tooltip"}>Advertising Multiplier: x{numeralWrapper.format(totalAdvertisingFac, "0.000")}
@ -191,9 +184,9 @@ export function IndustryOverview(props: IProps): React.ReactElement {
}
{advertisingInfo}
<br /><br />
{revenue} <br />
{expenses} <br />
{profitStr}
Revenue: {Money(division.lastCycleRevenue.toNumber())} / s <br />
Expenses: {Money(division.lastCycleExpenses.toNumber())} /s <br />
Profit: {Money(profit)} / s
<br /> <br />
<p className={"tooltip"}>
Production Multiplier: {numeralWrapper.format(division.prodMult, "0.00")}
@ -264,8 +257,9 @@ export function IndustryOverview(props: IProps): React.ReactElement {
}
upgrades.push(renderUpgrade({
key: index,
onClick: onClick,
text: `${upgrade[4]} - ${numeralWrapper.formatMoney(cost)}`,
text: <>{upgrade[4]} - {Money(cost)}</>,
tooltip: upgrade[5],
}));
}
@ -274,14 +268,15 @@ export function IndustryOverview(props: IProps): React.ReactElement {
}
interface IRenderUpgradeProps {
key: string;
onClick: () => void;
text: string;
text: JSX.Element;
tooltip: string;
}
function renderUpgrade(props: IRenderUpgradeProps): React.ReactElement {
return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} onClick={props.onClick} key={props.text}>
<div className={"cmpy-mgmt-upgrade-div tooltip"} onClick={props.onClick} key={props.key}>
{props.text}
{
props.tooltip != null &&

@ -3,6 +3,7 @@ import { removePopup } from "../../ui/React/createPopup";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { CorporationConstants } from "../data/Constants";
import { ICorporation } from "../ICorporation";
import { IssueDividends } from "../Actions";
interface IProps {
popupId: string;
@ -16,13 +17,12 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement {
function issueDividends(): void {
if(percent === null) return;
if (isNaN(percent) || percent < 0 || percent > CorporationConstants.DividendMaxPercentage) {
dialogBoxCreate(`Invalid value. Must be an integer between 0 and ${CorporationConstants.DividendMaxPercentage}`);
return;
try {
IssueDividends(props.corp, percent/100);
} catch(err) {
dialogBoxCreate(err);
}
props.corp.dividendPercentage = percent;
removePopup(props.popupId);
}
@ -37,7 +37,7 @@ export function IssueDividendsPopup(props: IProps): React.ReactElement {
return (<>
<p>
"Dividends are a distribution of a portion of the corporation's
Dividends are a distribution of a portion of the corporation's
profits to the shareholders. This includes yourself, as well.<br /><br />
In order to issue dividends, simply allocate some percentage
of your corporation's profits to dividends. This percentage must be an

@ -6,32 +6,32 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
import { ICorporation } from "../ICorporation";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { CorporationUpgrade } from "../data/CorporationUpgrades";
import { LevelUpgrade } from "../Actions";
import { Money } from "../../ui/React/Money";
interface IProps {
upgradeData: CorporationUpgrade;
upgradeLevel: number;
upgrade: CorporationUpgrade;
corp: ICorporation;
player: IPlayer;
}
export function LevelableUpgrade(props: IProps): React.ReactElement {
const data = props.upgradeData;
const level = props.upgradeLevel;
const data = props.upgrade;
const level = props.corp.upgrades[data[0]];
const baseCost = data[1];
const priceMult = data[2];
const cost = baseCost * Math.pow(priceMult, level);
const text = `${data[4]} - ${numeralWrapper.formatMoney(cost)}`
const text = <>{data[4]} - {Money(cost)}</>
const tooltip = data[5];
function onClick(): void {
const corp = props.corp;
if (corp.funds.lt(cost)) {
dialogBoxCreate("Insufficient funds");
} else {
corp.upgrade(data);
corp.rerender(props.player);
try {
LevelUpgrade(props.corp, props.upgrade);
} catch(err) {
dialogBoxCreate(err);
}
props.corp.rerender(props.player);
}
return (

@ -9,6 +9,7 @@ import { Industry } from "../Industry";
import { ICorporation } from "../ICorporation";
import { IIndustry } from "../IIndustry";
import { CorporationRouting } from "./Routing";
import { NewIndustry } from "../Actions";
interface IProps {
corp: ICorporation;
@ -24,33 +25,17 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
const [name, setName] = useState('');
function newIndustry(): void {
const ind = industry;
const newDivisionName = name;
for (let i = 0; i < props.corp.divisions.length; ++i) {
if (props.corp.divisions[i].name === newDivisionName) {
dialogBoxCreate("This name is already in use!");
return;
}
try {
NewIndustry(props.corp, industry, name);
} catch(err) {
dialogBoxCreate(err);
return;
}
if (props.corp.funds.lt(IndustryStartingCosts[ind])) {
dialogBoxCreate("Not enough money to create a new division in this industry");
} else if (newDivisionName === "") {
dialogBoxCreate("New division must have a name!");
} else {
props.corp.funds = props.corp.funds.minus(IndustryStartingCosts[ind]);
const newInd = new Industry({
corp: props.corp,
name: newDivisionName,
type: ind,
});
props.corp.divisions.push(newInd);
// Set routing to the new division so that the UI automatically switches to it
props.routing.routeTo(newDivisionName);
// Set routing to the new division so that the UI automatically switches to it
props.routing.routeTo(name);
removePopup(props.popupId);
}
removePopup(props.popupId);
}
function onNameChange(event: React.ChangeEvent<HTMLInputElement>): void {

@ -11,7 +11,9 @@ import { FindInvestorsPopup } from "./FindInvestorsPopup";
import { GoPublicPopup } from "./GoPublicPopup";
import { CorporationConstants } from "../data/Constants";
import { CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
import {
CorporationUnlockUpgrade,
CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
import {
CorporationUpgrade,
CorporationUpgrades } from "../data/CorporationUpgrades";
@ -20,6 +22,7 @@ import { CONSTANTS } from "../../Constants";
import { numeralWrapper } from "../../ui/numeralFormat";
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { createPopup } from "../../ui/React/createPopup";
import { Money } from "../../ui/React/Money";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { ICorporation } from "../ICorporation";
@ -30,7 +33,6 @@ interface IProps {
interface GeneralBtns {
bribeFactions: React.ReactElement;
getStarterGuide: React.ReactElement;
}
export function Overview(props: IProps): React.ReactElement {
@ -38,10 +40,32 @@ export function Overview(props: IProps): React.ReactElement {
interface ICreateButtonProps {
text: string;
class?: string;
className?: string;
display?: string;
tooltip?: string;
onClick?: (event: React.MouseEvent) => void;
}
function Button(props: ICreateButtonProps): React.ReactElement {
let className = props.className ? props.className : "std-button";
const hasTooltip = props.tooltip != null;
if(hasTooltip) className += " tooltip";
return (
<a
className={className}
onClick={props.onClick}
style={{display: props.display ? props.display : "block"}}>
{props.text}
{
hasTooltip &&
<span className={"tooltiptext"}>
{props.tooltip}
</span>
}
</a>
);
}
function createButton(props: ICreateButtonProps): React.ReactElement {
let className = props.class ? props.class : "std-button";
const displayStyle = props.display ? props.display : "block";
@ -63,176 +87,143 @@ export function Overview(props: IProps): React.ReactElement {
)
}
// Returns a string with general information about Corporation
function getOverviewText(): string {
// Formatted text for profit
const profit = props.corp.revenue.minus(props.corp.expenses).toNumber(),
profitStr = profit >= 0 ? numeralWrapper.formatMoney(profit) : "-" + numeralWrapper.format(-1 * profit, "$0.000a");
// Formatted text for dividend information, if applicable
let dividendStr = "";
if (props.corp.dividendPercentage > 0 && profit > 0) {
const totalDividends = (props.corp.dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / props.corp.totalShares;
const playerEarnings = props.corp.numShares * dividendsPerShare;
dividendStr = `Retained Profits (after dividends): ${numeralWrapper.format(retainedEarnings, "$0.000a")} / s<br><br>` +
`Dividend Percentage: ${numeralWrapper.format(props.corp.dividendPercentage / 100, "0%")}<br>` +
`Dividends per share: ${numeralWrapper.format(dividendsPerShare, "$0.000a")} / s<br>` +
`Your earnings as a shareholder (Pre-Tax): ${numeralWrapper.format(playerEarnings, "$0.000a")} / s<br>` +
`Dividend Tax Rate: ${props.corp.dividendTaxPercentage}%<br>` +
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (props.corp.dividendTaxPercentage / 100)), "$0.000a")} / s<br><br>`;
}
let txt = "Total Funds: " + numeralWrapper.format(props.corp.funds.toNumber(), '$0.000a') + "<br>" +
"Total Revenue: " + numeralWrapper.format(props.corp.revenue.toNumber(), "$0.000a") + " / s<br>" +
"Total Expenses: " + numeralWrapper.format(props.corp.expenses.toNumber(), "$0.000a") + " / s<br>" +
"Total Profits: " + profitStr + " / s<br>" +
dividendStr +
"Publicly Traded: " + (props.corp.public ? "Yes" : "No") + "<br>" +
"Owned Stock Shares: " + numeralWrapper.format(props.corp.numShares, '0.000a') + "<br>" +
"Stock Price: " + (props.corp.public ? numeralWrapper.formatMoney(props.corp.sharePrice) : "N/A") + "<br>" +
"<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(props.corp.totalShares, "0.000a") +
"<span class='tooltiptext'>" +
`Outstanding Shares: ${numeralWrapper.format(props.corp.issuedShares, "0.000a")}<br>` +
`Private Shares: ${numeralWrapper.format(props.corp.totalShares - props.corp.issuedShares - props.corp.numShares, "0.000a")}` +
"</span></p><br><br>";
const storedTime = props.corp.storedCycles * CONSTANTS.MilliPerCycle;
if (storedTime > 15000) {
txt += `Bonus time: ${convertTimeMsToTimeElapsedString(storedTime)}<br><br>`;
}
const prodMult = props.corp.getProductionMultiplier(),
storageMult = props.corp.getStorageMultiplier(),
advMult = props.corp.getAdvertisingMultiplier(),
empCreMult = props.corp.getEmployeeCreMultiplier(),
empChaMult = props.corp.getEmployeeChaMultiplier(),
empIntMult = props.corp.getEmployeeIntMultiplier(),
empEffMult = props.corp.getEmployeeEffMultiplier(),
salesMult = props.corp.getSalesMultiplier(),
sciResMult = props.corp.getScientificResearchMultiplier();
if (prodMult > 1) {txt += "Production Multiplier: " + numeralWrapper.format(prodMult, "0.000") + "<br>";}
if (storageMult > 1) {txt += "Storage Multiplier: " + numeralWrapper.format(storageMult, "0.000") + "<br>";}
if (advMult > 1) {txt += "Advertising Multiplier: " + numeralWrapper.format(advMult, "0.000") + "<br>";}
if (empCreMult > 1) {txt += "Empl. Creativity Multiplier: " + numeralWrapper.format(empCreMult, "0.000") + "<br>";}
if (empChaMult > 1) {txt += "Empl. Charisma Multiplier: " + numeralWrapper.format(empChaMult, "0.000") + "<br>";}
if (empIntMult > 1) {txt += "Empl. Intelligence Multiplier: " + numeralWrapper.format(empIntMult, "0.000") + "<br>";}
if (empEffMult > 1) {txt += "Empl. Efficiency Multiplier: " + numeralWrapper.format(empEffMult, "0.000") + "<br>";}
if (salesMult > 1) {txt += "Sales Multiplier: " + numeralWrapper.format(salesMult, "0.000") + "<br>";}
if (sciResMult > 1) {txt += "Scientific Research Multiplier: " + numeralWrapper.format(sciResMult, "0.000") + "<br>";}
return txt;
function openBribeFactionPopup(): void {
const popupId = "corp-bribe-popup";
createPopup(popupId, BribeFactionPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
// Render the buttons that lie below the overview text.
// These are mainly for things such as managing finances/stock
function renderButtons(): React.ReactElement {
// Create a "Getting Started Guide" button that lets player view the
// handbook and adds it to the players home computer
const getStarterGuideBtn = createButton({
class: "a-link-button",
display: "inline-block",
onClick: () => props.corp.getStarterGuide(props.player),
text: "Getting Started Guide",
tooltip: "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.",
});
const profit: number = props.corp.revenue.minus(props.corp.expenses).toNumber();
function openBribeFactionPopup(): void {
const popupId = "corp-bribe-popup";
createPopup(popupId, BribeFactionPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function DividendsStats() {
if(props.corp.dividendPercentage <= 0 || profit <= 0) return (<></>);
const totalDividends = (props.corp.dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / props.corp.totalShares;
const playerEarnings = props.corp.numShares * dividendsPerShare;
return (<>
Retained Profits (after dividends): {Money(retainedEarnings)} / s<br /><br />
Dividend Percentage: {numeralWrapper.format(props.corp.dividendPercentage / 100, "0%")}<br />
Dividends per share: {Money(dividendsPerShare)} / s<br />
Your earnings as a shareholder (Pre-Tax): {Money(playerEarnings)} / s<br />
Dividend Tax Rate: {props.corp.dividendTaxPercentage}%<br />
Your earnings as a shareholder (Post-Tax): {Money(playerEarnings * (1 - (props.corp.dividendTaxPercentage / 100)))} / s<br /><br />
</>);
}
// Create a "Bribe Factions" button if your Corporation is powerful enough.
// This occurs regardless of whether you're public or private
function Mult(props: {name: string, mult: number}): React.ReactElement {
if(props.mult <= 1) return (<></>);
return (<p>{props.name}{numeralWrapper.format(props.mult, "0.000")}<br /></p>);
}
// Returns a string with general information about Corporation
function BonusTime(): React.ReactElement {
const storedTime = props.corp.storedCycles * CONSTANTS.MilliPerCycle;
if (storedTime <= 15000) return (<></>);
return (<p>Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}<br /><br /></p>);
}
function BribeButton(): React.ReactElement {
const canBribe = (props.corp.determineValuation() >= CorporationConstants.BribeThreshold) || true;
const bribeFactionsClass = (canBribe ? "a-link-button" : "a-link-button-inactive");
const bribeFactionsBtn = createButton({
class: bribeFactionsClass,
display: "inline-block",
onClick: openBribeFactionPopup,
text: "Bribe Factions",
tooltip: (canBribe
return <Button
className={bribeFactionsClass}
display="inline-block"
onClick={openBribeFactionPopup}
text="Bribe Factions"
tooltip={(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"),
});
const generalBtns = {
bribeFactions: bribeFactionsBtn,
getStarterGuide: getStarterGuideBtn,
};
if (props.corp.public) {
return renderPublicButtons(generalBtns);
} else {
return renderPrivateButtons(generalBtns);
}
: "Your Corporation is not powerful enough to bribe Faction leaders")}
/>
}
function openFindInvestorsPopup(): void {
const popupId = "cmpy-mgmt-find-investors-popup";
createPopup(popupId, FindInvestorsPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function openGoPublicPopup(): void {
const popupId = "cmpy-mgmt-go-public-popup";
createPopup(popupId, GoPublicPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
// Render the buttons for when your Corporation is still private
function renderPrivateButtons(generalBtns: GeneralBtns): React.ReactElement {
function PrivateButtons(): React.ReactElement {
const fundingAvailable = (props.corp.fundingRound < 4);
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
const findInvestorsTooltip = fundingAvailable ? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company" : undefined;
function openFindInvestorsPopup(): void {
const popupId = "cmpy-mgmt-find-investors-popup";
createPopup(popupId, FindInvestorsPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function openGoPublicPopup(): void {
const popupId = "cmpy-mgmt-go-public-popup";
createPopup(popupId, GoPublicPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
const findInvestorsBtn = createButton({
class: findInvestorsClassName,
onClick: openFindInvestorsPopup,
text: "Find Investors",
tooltip: findInvestorsTooltip,
display: "inline-block",
});
const goPublicBtn = createButton({
class: "std-button",
onClick: openGoPublicPopup,
display: "inline-block",
text: "Go Public",
tooltip: "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.",
});
return (
<div>
{generalBtns.getStarterGuide}
{findInvestorsBtn}
{goPublicBtn}
<>
<Button
className={findInvestorsClassName}
onClick={openFindInvestorsPopup}
text="Find Investors"
tooltip={findInvestorsTooltip}
display="inline-block"
/>
<Button
className="std-button"
onClick={openGoPublicPopup}
display="inline-block"
text="Go Public"
tooltip={"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."}
/>
<br />
{generalBtns.bribeFactions}
</div>
</>
)
}
function openSellSharesPopup(): void {
const popupId = "cmpy-mgmt-sell-shares-popup";
createPopup(popupId, SellSharesPopup, {
corp: props.corp,
player: props.player,
popupId: popupId,
});
}
function openBuybackSharesPopup(): void {
const popupId = "corp-buyback-shares-popup";
createPopup(popupId, BuybackSharesPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function openIssueNewSharesPopup(): void {
const popupId = "cmpy-mgmt-issue-new-shares-popup";
createPopup(popupId, IssueNewSharesPopup, {
popupId: popupId,
corp: props.corp,
});
}
function openIssueDividendsPopup(): void {
const popupId = "cmpy-mgmt-issue-dividends-popup";
createPopup(popupId, IssueDividendsPopup, {
popupId: popupId,
corp: props.corp,
});
}
// Render the buttons for when your Corporation has gone public
function renderPublicButtons(generalBtns: GeneralBtns): React.ReactElement {
function PublicButtons(): React.ReactElement {
const corp = props.corp;
const sellSharesOnCd = (corp.shareSaleCooldown > 0);
@ -242,153 +233,135 @@ export function Overview(props: IProps): React.ReactElement {
: "Sell your shares in the company. The money earned from selling your " +
"shares goes into your personal account, not the Corporation's. " +
"This is one of the only ways to profit from your business venture."
const sellSharesBtn = createButton({
class: sellSharesClass,
display: "inline-block",
onClick: function(event: React.MouseEvent) {
if(!event.isTrusted) return;
const popupId = "cmpy-mgmt-sell-shares-popup";
createPopup(popupId, SellSharesPopup, {
corp: props.corp,
player: props.player,
popupId: popupId,
});
},
text: "Sell Shares",
tooltip: sellSharesTooltip,
});
function openBuybackSharesPopup(): void {
const popupId = "corp-buyback-shares-popup";
createPopup(popupId, BuybackSharesPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
const buybackSharesBtn = createButton({
class: "std-button",
display: "inline-block",
onClick: openBuybackSharesPopup,
text: "Buyback shares",
tooltip: "Buy back shares you that previously issued or sold at market price.",
});
function openIssueNewSharesPopup(): void {
const popupId = "cmpy-mgmt-issue-new-shares-popup";
createPopup(popupId, IssueNewSharesPopup, {
popupId: popupId,
corp: props.corp,
});
}
const issueNewSharesOnCd = (corp.issueNewSharesCooldown > 0);
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
const issueNewSharesTooltip = issueNewSharesOnCd
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
: "Issue new equity shares to raise capital.";
const issueNewSharesBtn = createButton({
class: issueNewSharesClass,
display: "inline-block",
onClick: openIssueNewSharesPopup,
text: "Issue New Shares",
tooltip: issueNewSharesTooltip,
});
function openIssueDividendsPopup(): void {
const popupId = "cmpy-mgmt-issue-dividends-popup";
createPopup(popupId, IssueDividendsPopup, {
popupId: popupId,
corp: props.corp,
});
}
const issueDividendsBtn = createButton({
class: "std-button",
display: "inline-block",
onClick: openIssueDividendsPopup,
text: "Issue Dividends",
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
});
return (
<div>
{generalBtns.getStarterGuide}
{sellSharesBtn}
{buybackSharesBtn}
<>
<Button
className={sellSharesClass}
display="inline-block"
onClick={openSellSharesPopup}
text="Sell Shares"
tooltip={sellSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openBuybackSharesPopup}
text="Buyback shares"
tooltip="Buy back shares you that previously issued or sold at market price."
/>
<br />
{issueNewSharesBtn}
{issueDividendsBtn}
<Button
className={issueNewSharesClass}
display="inline-block"
onClick={openIssueNewSharesPopup}
text="Issue New Shares"
tooltip={issueNewSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openIssueDividendsPopup}
text="Issue Dividends"
tooltip="Manage the dividends that are paid out to shareholders (including yourself)"
/>
<br />
{generalBtns.bribeFactions}
</div>
</>
)
}
// Render the UI for Corporation upgrades
function renderUpgrades(): React.ReactElement {
function Upgrades(): React.ReactElement {
// Don't show upgrades
if (props.corp.divisions.length <= 0) { return (<></>); }
// Create an array of all Unlocks
const unlockUpgrades: React.ReactElement[] = [];
Object.values(CorporationUnlockUpgrades).forEach((unlockData) => {
if (props.corp.unlockUpgrades[unlockData[0]] === 0) {
unlockUpgrades.push(<UnlockUpgrade
player={props.player}
corp={props.corp}
upgradeData={unlockData}
key={unlockData[0]}
/>);
}
});
interface UpgradeData {
upgradeData: CorporationUpgrade;
upgradeLevel: number;
}
// Create an array of properties of all unlocks
const levelableUpgradeProps: UpgradeData[] = [];
for (let i = 0; i < props.corp.upgrades.length; ++i) {
const upgradeData = CorporationUpgrades[i];
const level = props.corp.upgrades[i];
levelableUpgradeProps.push({
upgradeData: upgradeData,
upgradeLevel: level,
});
}
return (
<div className={"cmpy-mgmt-upgrade-container"}>
<h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1>
{unlockUpgrades}
{
Object.values(CorporationUnlockUpgrades)
.filter((upgrade: CorporationUnlockUpgrade) => props.corp.unlockUpgrades[upgrade[0]] === 0)
.map((upgrade: CorporationUnlockUpgrade) =>
<UnlockUpgrade
player={props.player}
corp={props.corp}
upgradeData={upgrade}
key={upgrade[0]}
/>)
}
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
{
levelableUpgradeProps.map((data: UpgradeData) => <LevelableUpgrade
props.corp.upgrades
.map((level: number, i: number) => CorporationUpgrades[i])
.map((upgrade: CorporationUpgrade) => <LevelableUpgrade
player={props.player}
corp={props.corp}
upgradeData={data.upgradeData}
upgradeLevel={data.upgradeLevel}
key={data.upgradeData[0]}
upgrade={upgrade}
key={upgrade[0]}
/>,
)
}
</div>
)
);
}
return (
<div>
<p dangerouslySetInnerHTML={{__html: getOverviewText()}}></p>
{renderButtons()}
<p>
Total Funds: {Money(props.corp.funds.toNumber())}<br />
Total Revenue: {Money(props.corp.revenue.toNumber())} / s<br />
Total Expenses: {Money(props.corp.expenses.toNumber())} / s<br />
Total Profits: {Money(profit)} / s<br />
<DividendsStats />
Publicly Traded: {(props.corp.public ? "Yes" : "No")}<br />
Owned Stock Shares: {numeralWrapper.format(props.corp.numShares, '0.000a')}<br />
Stock Price: {(props.corp.public ? Money(props.corp.sharePrice) : "N/A")}<br />
</p>
<p className='tooltip'>
Total Stock Shares: {numeralWrapper.format(props.corp.totalShares, "0.000a")}
<span className='tooltiptext'>
Outstanding Shares: {numeralWrapper.format(props.corp.issuedShares, "0.000a")}<br />
Private Shares: {numeralWrapper.format(props.corp.totalShares - props.corp.issuedShares - props.corp.numShares, "0.000a")}
</span>
</p>
<br /><br />
<Mult name="Production Multiplier: " mult={props.corp.getProductionMultiplier()} />
<Mult name="Storage Multiplier: " mult={props.corp.getStorageMultiplier()} />
<Mult name="Advertising Multiplier: " mult={props.corp.getAdvertisingMultiplier()} />
<Mult name="Empl. Creativity Multiplier: " mult={props.corp.getEmployeeCreMultiplier()} />
<Mult name="Empl. Charisma Multiplier: " mult={props.corp.getEmployeeChaMultiplier()} />
<Mult name="Empl. Intelligence Multiplier: " mult={props.corp.getEmployeeIntMultiplier()} />
<Mult name="Empl. Efficiency Multiplier: " mult={props.corp.getEmployeeEffMultiplier()} />
<Mult name="Sales Multiplier: " mult={props.corp.getSalesMultiplier()} />
<Mult name="Scientific Research Multiplier: " mult={props.corp.getScientificResearchMultiplier()} />
<br />
{renderUpgrades()}
<BonusTime />
<div>
<Button
className="a-link-button"
display="inline-block"
onClick={() => props.corp.getStarterGuide(props.player)}
text="Getting Started Guide"
tooltip={"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."}
/>
{ props.corp.public ?
<PublicButtons /> :
<PrivateButtons />
}
<BribeButton />
</div>
<br />
<Upgrades />
</div>
)
}

@ -6,6 +6,8 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
import { CorporationUnlockUpgrade } from "../data/CorporationUnlockUpgrades";
import { ICorporation } from "../ICorporation";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { UnlockUpgrade as UU } from "../Actions";
import { Money } from "../../ui/React/Money";
interface IProps {
upgradeData: CorporationUnlockUpgrade;
@ -15,16 +17,15 @@ interface IProps {
export function UnlockUpgrade(props: IProps): React.ReactElement {
const data = props.upgradeData;
const text = `${data[2]} - ${numeralWrapper.formatMoney(data[1])}`;
const text = <>{data[2]} - {Money(data[1])}</>;
const tooltip = data[3];
function onClick(): void {
const corp = props.corp;
if (corp.funds.lt(data[1])) {
dialogBoxCreate("Insufficient funds");
} else {
corp.unlock(data);
corp.rerender(props.player);
try {
UU(props.corp, props.upgradeData);
} catch(err) {
dialogBoxCreate(err);
}
props.corp.rerender(props.player);
}
return (

@ -20,6 +20,14 @@ import { CompanyPosition } from "./Company/CompanyPosition";
import { CompanyPositions } from "./Company/CompanyPositions";
import { CONSTANTS } from "./Constants";
import { DarkWebItems } from "./DarkWeb/DarkWebItems";
import {
NewIndustry,
NewCity,
UnlockUpgrade,
LevelUpgrade,
IssueDividends } from "./Corporation/Actions";
import { CorporationUnlockUpgrades } from "./Corporation/data/CorporationUnlockUpgrades";
import { CorporationUpgrades } from "./Corporation/data/CorporationUpgrades";
import {
calculateHackingChance,
calculateHackingExpGain,
@ -4097,6 +4105,32 @@ function NetscriptFunctions(workerScript) {
},
}, // End Bladeburner
corporation: {
expandIndustry: function(industryName, divisionName) {
NewIndustry(Player.corporation, industryName, divisionName);
},
expandCity: function(divisionName, cityName) {
const division = Player.corporation.divisions.find(div => div.name === divisionName);
if(division === undefined) throw new Error("No division named '${divisionName}'");
NewCity(Player.corporation, division, cityName);
},
unlockUpgrade: function(upgradeName) {
const upgrade = Object.values(CorporationUnlockUpgrades).
find(upgrade => upgrade[2] === upgradeName);
if(upgrade === undefined) throw new Error("No upgrade named '${upgradeName}'")
UnlockUpgrade(Player.corporation, upgrade);
},
levelUpgrade: function(upgradeName) {
const upgrade = Object.values(CorporationUpgrades).
find(upgrade => upgrade[4] === upgradeName);
if(upgrade === undefined) throw new Error("No upgrade named '${upgradeName}'")
LevelUpgrade(Player.corporation, upgrade);
},
issueDividends: function(percent) {
IssueDividends(Player.corporation, percent);
},
}, // End Corporation API
// Coding Contract API
codingcontract: {
attempt: function(answer, fn, ip=workerScript.serverIp, { returnReward } = {}) {

@ -19,7 +19,8 @@ import { LocationName } from "../Locations/data/LocationNames";
import { Server } from "../Server/Server";
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { Exploit } from "../Exploits/Exploit";
import { Exploit } from "../Exploits/Exploit";
import { ICorporation } from "../Corporation/ICorporation";
export interface IPlayer {
// Class members
@ -28,7 +29,7 @@ export interface IPlayer {
bitNodeN: number;
city: CityName;
companyName: string;
corporation: any;
corporation: ICorporation;
currentServer: string;
factions: string[];
factionInvitations: string[];