mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 17:43:48 +01:00
more conversion
This commit is contained in:
parent
21008ba65a
commit
a72d1aa99f
3
src/Corporation/Corporation.d.ts
vendored
Normal file
3
src/Corporation/Corporation.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export class Industry {
|
||||||
|
constructor(props: any)
|
||||||
|
}
|
@ -1,140 +0,0 @@
|
|||||||
import { ResearchTree } from "./ResearchTree";
|
|
||||||
import { getBaseResearchTreeCopy,
|
|
||||||
getProductIndustryResearchTreeCopy } from "./data/BaseResearchTree";
|
|
||||||
|
|
||||||
import { numeralWrapper } from "../ui/numeralFormat";
|
|
||||||
|
|
||||||
interface IIndustryMap<T> {
|
|
||||||
Energy: T;
|
|
||||||
Utilities: T;
|
|
||||||
Agriculture: T;
|
|
||||||
Fishing: T;
|
|
||||||
Mining: T;
|
|
||||||
Food: T;
|
|
||||||
Tobacco: T;
|
|
||||||
Chemical: T;
|
|
||||||
Pharmaceutical: T;
|
|
||||||
Computer: T;
|
|
||||||
Robotics: T;
|
|
||||||
Software: T;
|
|
||||||
Healthcare: T;
|
|
||||||
RealEstate: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of official names for each Industry
|
|
||||||
export const Industries: IIndustryMap<string> = {
|
|
||||||
Energy: "Energy",
|
|
||||||
Utilities: "Water Utilities",
|
|
||||||
Agriculture: "Agriculture",
|
|
||||||
Fishing: "Fishing",
|
|
||||||
Mining: "Mining",
|
|
||||||
Food: "Food",
|
|
||||||
Tobacco: "Tobacco",
|
|
||||||
Chemical: "Chemical",
|
|
||||||
Pharmaceutical: "Pharmaceutical",
|
|
||||||
Computer: "Computer Hardware",
|
|
||||||
Robotics: "Robotics",
|
|
||||||
Software: "Software",
|
|
||||||
Healthcare: "Healthcare",
|
|
||||||
RealEstate: "RealEstate",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of how much money it takes to start each industry
|
|
||||||
export const IndustryStartingCosts: IIndustryMap<number> = {
|
|
||||||
Energy: 225e9,
|
|
||||||
Utilities: 150e9,
|
|
||||||
Agriculture: 40e9,
|
|
||||||
Fishing: 80e9,
|
|
||||||
Mining: 300e9,
|
|
||||||
Food: 10e9,
|
|
||||||
Tobacco: 20e9,
|
|
||||||
Chemical: 70e9,
|
|
||||||
Pharmaceutical: 200e9,
|
|
||||||
Computer: 500e9,
|
|
||||||
Robotics: 1e12,
|
|
||||||
Software: 25e9,
|
|
||||||
Healthcare: 750e9,
|
|
||||||
RealEstate: 600e9,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of description for each industry
|
|
||||||
export const IndustryDescriptions: IIndustryMap<string> = {
|
|
||||||
Energy: "Engage in the production and distribution of energy.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Energy, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Utilities: "Distribute water and provide wastewater services.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Utilities, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Agriculture: "Cultivate crops and breed livestock to produce food.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Agriculture, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: YES",
|
|
||||||
Fishing: "Produce food through the breeding and processing of fish and fish products.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Fishing, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Mining: "Extract and process metals from the earth.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Mining, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Food: "Create your own restaurants all around the world.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Food, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: YES",
|
|
||||||
Tobacco: "Create and distribute tobacco and tobacco-related products.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Tobacco, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: YES",
|
|
||||||
Chemical: "Produce industrial chemicals.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Chemical, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Pharmaceutical: "Discover, develop, and create new pharmaceutical drugs.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Pharmaceutical, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Computer: "Develop and manufacture new computer hardware and networking infrastructures.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Computer, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Robotics: "Develop and create robots.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Robotics, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
Software: "Develop computer software and create AI Cores.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Software, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: YES",
|
|
||||||
Healthcare: "Create and manage hospitals.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.Healthcare, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
RealEstate: "Develop and manage real estate properties.<br><br>" +
|
|
||||||
"Starting cost: " + numeralWrapper.format(IndustryStartingCosts.RealEstate, "$0.000a") + "<br>" +
|
|
||||||
"Recommended starting Industry: NO",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map of available Research for each Industry. This data is held in a
|
|
||||||
// ResearchTree object
|
|
||||||
export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
|
|
||||||
Energy: getBaseResearchTreeCopy(),
|
|
||||||
Utilities: getBaseResearchTreeCopy(),
|
|
||||||
Agriculture: getBaseResearchTreeCopy(),
|
|
||||||
Fishing: getBaseResearchTreeCopy(),
|
|
||||||
Mining: getBaseResearchTreeCopy(),
|
|
||||||
Food: getProductIndustryResearchTreeCopy(),
|
|
||||||
Tobacco: getProductIndustryResearchTreeCopy(),
|
|
||||||
Chemical: getBaseResearchTreeCopy(),
|
|
||||||
Pharmaceutical: getProductIndustryResearchTreeCopy(),
|
|
||||||
Computer: getProductIndustryResearchTreeCopy(),
|
|
||||||
Robotics: getProductIndustryResearchTreeCopy(),
|
|
||||||
Software: getProductIndustryResearchTreeCopy(),
|
|
||||||
Healthcare: getProductIndustryResearchTreeCopy(),
|
|
||||||
RealEstate: getProductIndustryResearchTreeCopy(),
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetIndustryResearchTrees(): void {
|
|
||||||
IndustryResearchTrees.Energy = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Utilities = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Agriculture = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Fishing = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Mining = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Food = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Tobacco = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Chemical = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Pharmaceutical = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Computer = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Robotics = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Software = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.Healthcare = getBaseResearchTreeCopy();
|
|
||||||
IndustryResearchTrees.RealEstate = getBaseResearchTreeCopy();
|
|
||||||
}
|
|
143
src/Corporation/IndustryData.tsx
Normal file
143
src/Corporation/IndustryData.tsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ResearchTree } from "./ResearchTree";
|
||||||
|
import { getBaseResearchTreeCopy,
|
||||||
|
getProductIndustryResearchTreeCopy } from "./data/BaseResearchTree";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../ui/numeralFormat";
|
||||||
|
import { Money } from "../ui/React/Money";
|
||||||
|
|
||||||
|
interface IIndustryMap<T> {
|
||||||
|
[key: string]: T | undefined;
|
||||||
|
Energy: T;
|
||||||
|
Utilities: T;
|
||||||
|
Agriculture: T;
|
||||||
|
Fishing: T;
|
||||||
|
Mining: T;
|
||||||
|
Food: T;
|
||||||
|
Tobacco: T;
|
||||||
|
Chemical: T;
|
||||||
|
Pharmaceutical: T;
|
||||||
|
Computer: T;
|
||||||
|
Robotics: T;
|
||||||
|
Software: T;
|
||||||
|
Healthcare: T;
|
||||||
|
RealEstate: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of official names for each Industry
|
||||||
|
export const Industries: IIndustryMap<string> = {
|
||||||
|
Energy: "Energy",
|
||||||
|
Utilities: "Water Utilities",
|
||||||
|
Agriculture: "Agriculture",
|
||||||
|
Fishing: "Fishing",
|
||||||
|
Mining: "Mining",
|
||||||
|
Food: "Food",
|
||||||
|
Tobacco: "Tobacco",
|
||||||
|
Chemical: "Chemical",
|
||||||
|
Pharmaceutical: "Pharmaceutical",
|
||||||
|
Computer: "Computer Hardware",
|
||||||
|
Robotics: "Robotics",
|
||||||
|
Software: "Software",
|
||||||
|
Healthcare: "Healthcare",
|
||||||
|
RealEstate: "RealEstate",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of how much money it takes to start each industry
|
||||||
|
export const IndustryStartingCosts: IIndustryMap<number> = {
|
||||||
|
Energy: 225e9,
|
||||||
|
Utilities: 150e9,
|
||||||
|
Agriculture: 40e9,
|
||||||
|
Fishing: 80e9,
|
||||||
|
Mining: 300e9,
|
||||||
|
Food: 10e9,
|
||||||
|
Tobacco: 20e9,
|
||||||
|
Chemical: 70e9,
|
||||||
|
Pharmaceutical: 200e9,
|
||||||
|
Computer: 500e9,
|
||||||
|
Robotics: 1e12,
|
||||||
|
Software: 25e9,
|
||||||
|
Healthcare: 750e9,
|
||||||
|
RealEstate: 600e9,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of description for each industry
|
||||||
|
export const IndustryDescriptions: IIndustryMap<JSX.Element> = {
|
||||||
|
Energy: (<>Engage in the production and distribution of energy.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Energy)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Utilities: (<>Distribute water and provide wastewater services.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Utilities)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Agriculture: (<>Cultivate crops and breed livestock to produce food.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Agriculture)}<br />
|
||||||
|
Recommended starting Industry: YES</>),
|
||||||
|
Fishing: (<>Produce food through the breeding and processing of fish and fish products.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Fishing)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Mining: (<>Extract and process metals from the earth.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Mining)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Food: (<>Create your own restaurants all around the world.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Food)}<br />
|
||||||
|
Recommended starting Industry: YES</>),
|
||||||
|
Tobacco: (<>Create and distribute tobacco and tobacco-related products.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Tobacco)}<br />
|
||||||
|
Recommended starting Industry: YES</>),
|
||||||
|
Chemical: (<>Produce industrial chemicals.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Chemical)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Pharmaceutical: (<>Discover, develop, and create new pharmaceutical drugs.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Pharmaceutical)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Computer: (<>Develop and manufacture new computer hardware and networking infrastructures.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Computer)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Robotics: (<>Develop and create robots.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Robotics)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
Software: (<>Develop computer software and create AI Cores.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Software)}<br />
|
||||||
|
Recommended starting Industry: YES</>),
|
||||||
|
Healthcare: (<>Create and manage hospitals.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.Healthcare)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
RealEstate: (<>Develop and manage real estate properties.<br /><br />
|
||||||
|
Starting cost: {Money(IndustryStartingCosts.RealEstate)}<br />
|
||||||
|
Recommended starting Industry: NO</>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of available Research for each Industry. This data is held in a
|
||||||
|
// ResearchTree object
|
||||||
|
export const IndustryResearchTrees: IIndustryMap<ResearchTree> = {
|
||||||
|
Energy: getBaseResearchTreeCopy(),
|
||||||
|
Utilities: getBaseResearchTreeCopy(),
|
||||||
|
Agriculture: getBaseResearchTreeCopy(),
|
||||||
|
Fishing: getBaseResearchTreeCopy(),
|
||||||
|
Mining: getBaseResearchTreeCopy(),
|
||||||
|
Food: getProductIndustryResearchTreeCopy(),
|
||||||
|
Tobacco: getProductIndustryResearchTreeCopy(),
|
||||||
|
Chemical: getBaseResearchTreeCopy(),
|
||||||
|
Pharmaceutical: getProductIndustryResearchTreeCopy(),
|
||||||
|
Computer: getProductIndustryResearchTreeCopy(),
|
||||||
|
Robotics: getProductIndustryResearchTreeCopy(),
|
||||||
|
Software: getProductIndustryResearchTreeCopy(),
|
||||||
|
Healthcare: getProductIndustryResearchTreeCopy(),
|
||||||
|
RealEstate: getProductIndustryResearchTreeCopy(),
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetIndustryResearchTrees(): void {
|
||||||
|
IndustryResearchTrees.Energy = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Utilities = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Agriculture = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Fishing = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Mining = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Food = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Tobacco = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Chemical = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Pharmaceutical = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Computer = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Robotics = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Software = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.Healthcare = getBaseResearchTreeCopy();
|
||||||
|
IndustryResearchTrees.RealEstate = getBaseResearchTreeCopy();
|
||||||
|
}
|
@ -47,666 +47,6 @@ export class CorporationEventHandler {
|
|||||||
this.routing = routing;
|
this.routing = routing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a popup that lets the player manage exports
|
|
||||||
createExportMaterialPopup(mat) {
|
|
||||||
const corp = this.corp;
|
|
||||||
|
|
||||||
const popupId = "cmpy-mgmt-export-popup";
|
|
||||||
const exportTxt = createElement("p", {
|
|
||||||
innerText:"Select the industry and city to export this material to, as well as " +
|
|
||||||
"how much of this material to export per second. You can set the export " +
|
|
||||||
"amount to 'MAX' to export all of the materials in this warehouse.",
|
|
||||||
});
|
|
||||||
|
|
||||||
//Select industry and city to export to
|
|
||||||
const citySelector = createElement("select", {class: "dropdown"});
|
|
||||||
const industrySelector = createElement("select", {
|
|
||||||
class: "dropdown",
|
|
||||||
changeListener: () => {
|
|
||||||
const industryName = getSelectValue(industrySelector);
|
|
||||||
for (let i = 0; i < corp.divisions.length; ++i) {
|
|
||||||
if (corp.divisions[i].name == industryName) {
|
|
||||||
clearSelector(citySelector);
|
|
||||||
for (const cityName in corp.divisions[i].warehouses) {
|
|
||||||
if (corp.divisions[i].warehouses[cityName] instanceof Warehouse) {
|
|
||||||
citySelector.add(createElement("option", {
|
|
||||||
value:cityName, text:cityName,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < corp.divisions.length; ++i) {
|
|
||||||
industrySelector.add(createOptionElement(corp.divisions[i].name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force change listener to initialize citySelector
|
|
||||||
industrySelector.dispatchEvent(new Event("change"));
|
|
||||||
|
|
||||||
//Select amount to export
|
|
||||||
const exportAmount = createElement("input", {
|
|
||||||
class: "text-input",
|
|
||||||
placeholder:"Export amount / s",
|
|
||||||
});
|
|
||||||
|
|
||||||
const exportBtn = createElement("button", {
|
|
||||||
class: "std-button", display:"inline-block", innerText:"Export",
|
|
||||||
clickListener: () => {
|
|
||||||
const industryName = getSelectText(industrySelector);
|
|
||||||
const cityName = citySelector.options[citySelector.selectedIndex].text;
|
|
||||||
const amt = exportAmount.value;
|
|
||||||
|
|
||||||
// Sanitize amt
|
|
||||||
let sanitizedAmt = amt.replace(/\s+/g, '');
|
|
||||||
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, '');
|
|
||||||
let temp = sanitizedAmt.replace(/MAX/g, 1);
|
|
||||||
try {
|
|
||||||
temp = eval(temp);
|
|
||||||
} catch(e) {
|
|
||||||
dialogBoxCreate("Invalid expression entered for export amount: " + e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temp == null || isNaN(temp) || temp < 0) {
|
|
||||||
dialogBoxCreate("Invalid amount entered for export");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var exportObj = {ind:industryName, city:cityName, amt:sanitizedAmt};
|
|
||||||
mat.exp.push(exportObj);
|
|
||||||
removeElementById(popupId);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const cancelBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
|
||||||
|
|
||||||
const currExportsText = createElement("p", {
|
|
||||||
innerText:"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.",
|
|
||||||
});
|
|
||||||
const currExports = [];
|
|
||||||
for (var i = 0; i < mat.exp.length; ++i) {
|
|
||||||
(function(i, mat, currExports){
|
|
||||||
currExports.push(createElement("div", {
|
|
||||||
class:"cmpy-mgmt-existing-export",
|
|
||||||
innerHTML: "Industry: " + mat.exp[i].ind + "<br>" +
|
|
||||||
"City: " + mat.exp[i].city + "<br>" +
|
|
||||||
"Amount/s: " + mat.exp[i].amt,
|
|
||||||
clickListener:()=>{
|
|
||||||
mat.exp.splice(i, 1); //Remove export object
|
|
||||||
removeElementById(popupId);
|
|
||||||
createExportMaterialPopup(mat);
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
})(i, mat, currExports);
|
|
||||||
}
|
|
||||||
createPopup(popupId, [exportTxt, industrySelector, citySelector, exportAmount,
|
|
||||||
exportBtn, cancelBtn, currExportsText].concat(currExports));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player issue & manage dividends
|
|
||||||
// This is created when the player clicks the "Issue Dividends" button in the overview panel
|
|
||||||
createIssueDividendsPopup() {
|
|
||||||
const popupId = "cmpy-mgmt-issue-dividends-popup";
|
|
||||||
const descText = "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 " +
|
|
||||||
`integer between 0 and ${DividendMaxPercentage}. (A percentage of 0 means no dividends will be ` +
|
|
||||||
"issued<br><br>" +
|
|
||||||
"Two important things to note:<br>" +
|
|
||||||
" * Issuing dividends will negatively affect your corporation's stock price<br>" +
|
|
||||||
" * Dividends are taxed. Taxes start at 50%, but can be decreased<br><br>" +
|
|
||||||
"Example: Assume your corporation makes $100m / sec in profit and you allocate " +
|
|
||||||
"40% of that towards dividends. That means your corporation will gain $60m / sec " +
|
|
||||||
"in funds and the remaining $40m / sec will be paid as dividends. Since your " +
|
|
||||||
"corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share " +
|
|
||||||
"per second before taxes.";
|
|
||||||
const txt = createElement("p", { innerHTML: descText });
|
|
||||||
|
|
||||||
let allocateBtn;
|
|
||||||
const dividendPercentInput = createElement("input", {
|
|
||||||
margin: "5px",
|
|
||||||
placeholder: "Dividend %",
|
|
||||||
type: "number",
|
|
||||||
onkeyup: (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.keyCode === KEY.ENTER) {allocateBtn.click();}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
allocateBtn = createElement("button", {
|
|
||||||
class: "std-button",
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Allocate Dividend Percentage",
|
|
||||||
clickListener: () => {
|
|
||||||
const percentage = Math.round(parseInt(dividendPercentInput.value));
|
|
||||||
if (isNaN(percentage) || percentage < 0 || percentage > DividendMaxPercentage) {
|
|
||||||
return dialogBoxCreate(`Invalid value. Must be an integer between 0 and ${DividendMaxPercentage}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.corp.dividendPercentage = percentage;
|
|
||||||
|
|
||||||
removeElementById(popupId);
|
|
||||||
|
|
||||||
this.rerender();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const cancelBtn = createPopupCloseButton(popupId, {
|
|
||||||
class: "std-button",
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Cancel",
|
|
||||||
});
|
|
||||||
|
|
||||||
createPopup(popupId, [txt, dividendPercentInput, allocateBtn, cancelBtn]);
|
|
||||||
dividendPercentInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player issue new shares
|
|
||||||
// This is created when the player clicks the "Issue New Shares" buttons in the overview panel
|
|
||||||
createIssueNewSharesPopup() {
|
|
||||||
const popupId = "cmpy-mgmt-issue-new-shares-popup";
|
|
||||||
const maxNewSharesUnrounded = Math.round(this.corp.totalShares * 0.2);
|
|
||||||
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
|
||||||
|
|
||||||
const descText = createElement("p", {
|
|
||||||
innerHTML: "You can issue new equity shares (i.e. stocks) in order to raise " +
|
|
||||||
"capital for your corporation.<br><br>" +
|
|
||||||
` * You can issue at most ${numeralWrapper.format(maxNewShares, "0.000a")} new shares<br>` +
|
|
||||||
` * New shares are sold at a 10% discount<br>` +
|
|
||||||
` * You can only issue new shares once every 12 hours<br>` +
|
|
||||||
` * Issuing new shares causes dilution, resulting in a decrease in stock price and lower dividends per share<br>` +
|
|
||||||
` * Number of new shares issued must be a multiple of 10 million<br><br>` +
|
|
||||||
`When you choose to issue new equity, private shareholders have first priority for up to 50% of the new shares. ` +
|
|
||||||
`If they choose to exercise this option, these newly issued shares become private, restricted shares, which means ` +
|
|
||||||
`you cannot buy them back.`,
|
|
||||||
});
|
|
||||||
|
|
||||||
let issueBtn, newSharesInput;
|
|
||||||
const dynamicText = createElement("p", {
|
|
||||||
display: "block",
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateDynamicText(corp) {
|
|
||||||
const newSharePrice = Math.round(corp.sharePrice * 0.9);
|
|
||||||
let newShares = parseInt(newSharesInput.value);
|
|
||||||
if (isNaN(newShares)) {
|
|
||||||
dynamicText.innerText = "Invalid input";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round to nearest ten-millionth
|
|
||||||
newShares /= 10e6;
|
|
||||||
newShares = Math.round(newShares) * 10e6;
|
|
||||||
|
|
||||||
if (newShares < 10e6) {
|
|
||||||
dynamicText.innerText = "Must issue at least 10 million new shares";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newShares > maxNewShares) {
|
|
||||||
dynamicText.innerText = "You cannot issue that many shares";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicText.innerText = `Issue ${numeralWrapper.format(newShares, "0.000a")} new shares ` +
|
|
||||||
`for ${numeralWrapper.formatMoney(newShares * newSharePrice)}?`
|
|
||||||
}
|
|
||||||
newSharesInput = createElement("input", {
|
|
||||||
margin: "5px",
|
|
||||||
placeholder: "# New Shares",
|
|
||||||
type: "number",
|
|
||||||
onkeyup: (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.keyCode === KEY.ENTER) {
|
|
||||||
issueBtn.click();
|
|
||||||
} else {
|
|
||||||
updateDynamicText(this.corp);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
issueBtn = createElement("button", {
|
|
||||||
class: "std-button",
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Issue New Shares",
|
|
||||||
clickListener: () => {
|
|
||||||
const newSharePrice = Math.round(this.corp.sharePrice * 0.9);
|
|
||||||
let newShares = parseInt(newSharesInput.value);
|
|
||||||
if (isNaN(newShares)) {
|
|
||||||
dialogBoxCreate("Invalid input for number of new shares");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round to nearest ten-millionth
|
|
||||||
newShares = Math.round(newShares / 10e6) * 10e6;
|
|
||||||
|
|
||||||
if (newShares < 10e6 || newShares > maxNewShares) {
|
|
||||||
dialogBoxCreate("Invalid input for number of new shares");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const profit = newShares * newSharePrice;
|
|
||||||
this.corp.issueNewSharesCooldown = IssueNewSharesCooldown;
|
|
||||||
this.corp.totalShares += newShares;
|
|
||||||
|
|
||||||
// Determine how many are bought by private investors
|
|
||||||
// Private investors get up to 50% at most
|
|
||||||
// Round # of private shares to the nearest millionth
|
|
||||||
let privateShares = getRandomInt(0, Math.round(newShares / 2));
|
|
||||||
privateShares = Math.round(privateShares / 1e6) * 1e6;
|
|
||||||
|
|
||||||
this.corp.issuedShares += (newShares - privateShares);
|
|
||||||
this.corp.funds = this.corp.funds.plus(profit);
|
|
||||||
this.corp.immediatelyUpdateSharePrice();
|
|
||||||
|
|
||||||
removeElementById(popupId);
|
|
||||||
dialogBoxCreate(`Issued ${numeralWrapper.format(newShares, "0.000a")} and raised ` +
|
|
||||||
`${numeralWrapper.formatMoney(profit)}. ${numeralWrapper.format(privateShares, "0.000a")} ` +
|
|
||||||
`of these shares were bought by private investors.<br><br>` +
|
|
||||||
`Stock price decreased to ${numeralWrapper.formatMoney(this.corp.sharePrice)}`);
|
|
||||||
|
|
||||||
this.rerender();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const cancelBtn = createPopupCloseButton(popupId, {
|
|
||||||
class: "std-button",
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Cancel",
|
|
||||||
});
|
|
||||||
|
|
||||||
createPopup(popupId, [descText, dynamicText, newSharesInput, issueBtn, cancelBtn]);
|
|
||||||
newSharesInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player limit the production of a product
|
|
||||||
createLimitProductProdutionPopup(product, city) {
|
|
||||||
const popupId = "cmpy-mgmt-limit-product-production-popup";
|
|
||||||
const txt = createElement("p", {
|
|
||||||
innerText:"Enter a limit to the amount of this product you would " +
|
|
||||||
"like to product per second. Leave the box empty to set no limit.",
|
|
||||||
});
|
|
||||||
let confirmBtn;
|
|
||||||
const input = createElement("input", {
|
|
||||||
margin: "5px",
|
|
||||||
placeholder:"Limit",
|
|
||||||
type:"number",
|
|
||||||
onkeyup: (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.keyCode === KEY.ENTER) { confirmBtn.click(); }
|
|
||||||
},
|
|
||||||
});
|
|
||||||
confirmBtn = createElement("button", {
|
|
||||||
class: "std-button",
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Limit production",
|
|
||||||
margin: "5px",
|
|
||||||
clickListener: () => {
|
|
||||||
if (input.value === "") {
|
|
||||||
product.prdman[city][0] = false;
|
|
||||||
removeElementById(popupId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var qty = parseFloat(input.value);
|
|
||||||
if (isNaN(qty)) {
|
|
||||||
dialogBoxCreate("Invalid value entered");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (qty < 0) {
|
|
||||||
product.prdman[city][0] = false;
|
|
||||||
} else {
|
|
||||||
product.prdman[city][0] = true;
|
|
||||||
product.prdman[city][1] = qty;
|
|
||||||
}
|
|
||||||
removeElementById(popupId);
|
|
||||||
this.rerender();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const cancelBtn = createPopupCloseButton(popupId, { innerText: "Cancel" });
|
|
||||||
cancelBtn.style.margin = "6px";
|
|
||||||
|
|
||||||
createPopup(popupId, [txt, input, confirmBtn, cancelBtn]);
|
|
||||||
input.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player create a product for their current industry
|
|
||||||
createMakeProductPopup(popupText, division) {
|
|
||||||
if (division.hasMaximumNumberProducts()) { return; }
|
|
||||||
|
|
||||||
const popupId = "cmpy-mgmt-create-product-popup";
|
|
||||||
const txt = createElement("p", {
|
|
||||||
innerHTML: popupText,
|
|
||||||
});
|
|
||||||
const designCity = createElement("select", {
|
|
||||||
class: "dropdown",
|
|
||||||
margin: "5px",
|
|
||||||
});
|
|
||||||
for (const cityName in division.offices) {
|
|
||||||
if (division.offices[cityName] instanceof OfficeSpace) {
|
|
||||||
designCity.add(createElement("option", {
|
|
||||||
value: cityName,
|
|
||||||
text: cityName,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let productNamePlaceholder = "Product Name";
|
|
||||||
if (division.type === Industries.Food) {
|
|
||||||
productNamePlaceholder = "Restaurant Name";
|
|
||||||
} else if (division.type === Industries.Healthcare) {
|
|
||||||
productNamePlaceholder = "Hospital Name";
|
|
||||||
} else if (division.type === Industries.RealEstate) {
|
|
||||||
productNamePlaceholder = "Property Name";
|
|
||||||
}
|
|
||||||
var productNameInput = createElement("input", {
|
|
||||||
class: "text-input",
|
|
||||||
margin: "5px",
|
|
||||||
placeholder: productNamePlaceholder,
|
|
||||||
});
|
|
||||||
var lineBreak1 = createElement("br");
|
|
||||||
var designInvestInput = createElement("input", {
|
|
||||||
class: "text-input",
|
|
||||||
margin: "5px",
|
|
||||||
placeholder: "Design investment",
|
|
||||||
type: "number",
|
|
||||||
});
|
|
||||||
let confirmBtn;
|
|
||||||
var marketingInvestInput = createElement("input", {
|
|
||||||
class: "text-input",
|
|
||||||
margin: "5px",
|
|
||||||
placeholder: "Marketing investment",
|
|
||||||
type: "number",
|
|
||||||
onkeyup: (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.keyCode === KEY.ENTER) { confirmBtn.click(); }
|
|
||||||
},
|
|
||||||
});
|
|
||||||
confirmBtn = createElement("button", {
|
|
||||||
class: "std-button",
|
|
||||||
innerText: "Develop Product",
|
|
||||||
clickListener: () => {
|
|
||||||
if (designInvestInput.value == null || designInvestInput.value < 0) { designInvestInput.value = 0; }
|
|
||||||
if (marketingInvestInput.value == null || marketingInvestInput.value < 0) { marketingInvestInput.value = 0; }
|
|
||||||
var designInvest = parseFloat(designInvestInput.value),
|
|
||||||
marketingInvest = parseFloat(marketingInvestInput.value);
|
|
||||||
if (productNameInput.value == null || productNameInput.value === "") {
|
|
||||||
dialogBoxCreate("You must specify a name for your product!");
|
|
||||||
} else if (isNaN(designInvest)) {
|
|
||||||
dialogBoxCreate("Invalid value for design investment");
|
|
||||||
} else if (isNaN(marketingInvest)) {
|
|
||||||
dialogBoxCreate("Invalid value for marketing investment");
|
|
||||||
} else if (this.corp.funds.lt(designInvest + marketingInvest)) {
|
|
||||||
dialogBoxCreate("You don't have enough company funds to make this large of an investment");
|
|
||||||
} else {
|
|
||||||
const product = new Product({
|
|
||||||
name:productNameInput.value.replace(/[<>]/g, ''), //Sanitize for HTMl elements
|
|
||||||
createCity:designCity.options[designCity.selectedIndex].value,
|
|
||||||
designCost: designInvest,
|
|
||||||
advCost: marketingInvest,
|
|
||||||
});
|
|
||||||
if (division.products[product.name] instanceof Product) {
|
|
||||||
dialogBoxCreate(`You already have a product with this name!`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.corp.funds = this.corp.funds.minus(designInvest + marketingInvest);
|
|
||||||
division.products[product.name] = product;
|
|
||||||
removeElementById(popupId);
|
|
||||||
}
|
|
||||||
this.rerender();
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const cancelBtn = createPopupCloseButton(popupId, {
|
|
||||||
class: "std-button",
|
|
||||||
innerText: "Cancel",
|
|
||||||
});
|
|
||||||
|
|
||||||
createPopup(popupId, [txt, designCity, productNameInput, lineBreak1,
|
|
||||||
designInvestInput, marketingInvestInput, confirmBtn, cancelBtn]);
|
|
||||||
productNameInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player use the Market TA research for Materials
|
|
||||||
createMaterialMarketTaPopup(mat, industry) {
|
|
||||||
const popupId = "cmpy-mgmt-marketta-popup";
|
|
||||||
const markupLimit = mat.getMarkupLimit();
|
|
||||||
const ta1 = createElement("p", {
|
|
||||||
innerHTML: "<u><strong>Market-TA.I</strong></u><br>" +
|
|
||||||
"The maximum sale price you can mark this up to is " +
|
|
||||||
numeralWrapper.formatMoney(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",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enable using Market-TA1 for automatically setting sale price
|
|
||||||
const useTa1AutoSaleId = "cmpy-mgmt-marketa1-checkbox";
|
|
||||||
const useTa1AutoSaleDiv = createElement("div", { display: "block" });
|
|
||||||
const useTa1AutoSaleLabel = createElement("label", {
|
|
||||||
color: "white",
|
|
||||||
for: useTa1AutoSaleId,
|
|
||||||
innerText: "Use Market-TA.I for Auto-Sale Price",
|
|
||||||
tooltip: "If this is enabled, then this Material will automatically " +
|
|
||||||
"be sold at the price identified by Market-TA.I (i.e. the price shown above)",
|
|
||||||
})
|
|
||||||
const useTa1AutoSaleCheckbox = createElement("input", {
|
|
||||||
checked: mat.marketTa1,
|
|
||||||
id: useTa1AutoSaleId,
|
|
||||||
margin: "3px",
|
|
||||||
type: "checkbox",
|
|
||||||
changeListener: (e) => {
|
|
||||||
mat.marketTa1 = e.target.checked;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleLabel);
|
|
||||||
useTa1AutoSaleDiv.appendChild(useTa1AutoSaleCheckbox);
|
|
||||||
|
|
||||||
const closeBtn = createPopupCloseButton(popupId, {
|
|
||||||
class: "std-button",
|
|
||||||
display: "block",
|
|
||||||
innerText: "Close",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (industry.hasResearch("Market-TA.II")) {
|
|
||||||
let updateTa2Text;
|
|
||||||
const ta2Text = createElement("p");
|
|
||||||
const ta2Input = createElement("input", {
|
|
||||||
marginTop: "4px",
|
|
||||||
onkeyup: (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
updateTa2Text();
|
|
||||||
},
|
|
||||||
type: "number",
|
|
||||||
value: mat.bCost,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Function that updates the text in ta2Text element
|
|
||||||
updateTa2Text = function() {
|
|
||||||
const sCost = parseFloat(ta2Input.value);
|
|
||||||
let markup = 1;
|
|
||||||
if (sCost > mat.bCost) {
|
|
||||||
//Penalty if difference between sCost and bCost is greater than markup limit
|
|
||||||
if ((sCost - mat.bCost) > markupLimit) {
|
|
||||||
markup = Math.pow(markupLimit / (sCost - mat.bCost), 2);
|
|
||||||
}
|
|
||||||
} else if (sCost < mat.bCost) {
|
|
||||||
if (sCost <= 0) {
|
|
||||||
markup = 1e12; //Sell everything, essentially discard
|
|
||||||
} else {
|
|
||||||
//Lower prices than market increases sales
|
|
||||||
markup = mat.bCost / sCost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ta2Text.innerHTML = `<br><u><strong>Market-TA.II</strong></u><br>` +
|
|
||||||
`If you sell at ${numeralWrapper.formatMoney(sCost)}, ` +
|
|
||||||
`then you will sell ${numeralWrapper.format(markup, "0.00000")}x as much compared ` +
|
|
||||||
`to if you sold at market price.`;
|
|
||||||
}
|
|
||||||
updateTa2Text();
|
|
||||||
|
|
||||||
// Enable using Market-TA2 for automatically setting sale price
|
|
||||||
const useTa2AutoSaleId = "cmpy-mgmt-marketa2-checkbox";
|
|
||||||
const useTa2AutoSaleDiv = createElement("div", { display: "block" });
|
|
||||||
const useTa2AutoSaleLabel = createElement("label", {
|
|
||||||
color: "white",
|
|
||||||
for: useTa2AutoSaleId,
|
|
||||||
innerText: "Use Market-TA.II for Auto-Sale Price",
|
|
||||||
tooltip: "If this is enabled, then this Material will automatically " +
|
|
||||||
"be sold at the optimal price such that the amount sold matches the " +
|
|
||||||
"amount produced. (i.e. the highest possible price, while still ensuring " +
|
|
||||||
" that all produced materials will be sold)",
|
|
||||||
})
|
|
||||||
const useTa2AutoSaleCheckbox = createElement("input", {
|
|
||||||
checked: mat.marketTa2,
|
|
||||||
id: useTa2AutoSaleId,
|
|
||||||
margin: "3px",
|
|
||||||
type: "checkbox",
|
|
||||||
changeListener: (e) => {
|
|
||||||
mat.marketTa2 = e.target.checked;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleLabel);
|
|
||||||
useTa2AutoSaleDiv.appendChild(useTa2AutoSaleCheckbox);
|
|
||||||
|
|
||||||
const ta2OverridesTa1 = createElement("p", {
|
|
||||||
innerText: "Note that Market-TA.II overrides Market-TA.I. This means that if " +
|
|
||||||
"both are enabled, then Market-TA.II will take effect, not Market-TA.I",
|
|
||||||
});
|
|
||||||
|
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, ta2Text, ta2Input, useTa2AutoSaleDiv, ta2OverridesTa1, closeBtn]);
|
|
||||||
} else {
|
|
||||||
// Market-TA.I only
|
|
||||||
createPopup(popupId, [ta1, useTa1AutoSaleDiv, closeBtn]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player create a new industry.
|
|
||||||
// This is created when the player clicks the "Expand into new Industry" header tab
|
|
||||||
createNewIndustryPopup() {
|
|
||||||
const popupId = "cmpy-mgmt-expand-industry-popup";
|
|
||||||
if (document.getElementById(popupId) != null) { return; }
|
|
||||||
|
|
||||||
var txt = createElement("p", {
|
|
||||||
innerHTML: "Create a new division to expand into a new industry:",
|
|
||||||
});
|
|
||||||
var selector = createElement("select", {
|
|
||||||
class:"dropdown",
|
|
||||||
});
|
|
||||||
var industryDescription = createElement("p", {});
|
|
||||||
var yesBtn;
|
|
||||||
var nameInput = createElement("input", {
|
|
||||||
type:"text",
|
|
||||||
id:"cmpy-mgmt-expand-industry-name-input",
|
|
||||||
class: "text-input",
|
|
||||||
display:"block",
|
|
||||||
maxLength: 30,
|
|
||||||
pattern:"[a-zA-Z0-9-_]",
|
|
||||||
onkeyup:(e)=>{
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.keyCode === KEY.ENTER) {yesBtn.click();}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
var nameLabel = createElement("label", {
|
|
||||||
for:"cmpy-mgmt-expand-industry-name-input",
|
|
||||||
innerText:"Division name: ",
|
|
||||||
});
|
|
||||||
yesBtn = createElement("span", {
|
|
||||||
class:"popup-box-button",
|
|
||||||
innerText:"Create Division",
|
|
||||||
clickListener: ()=>{
|
|
||||||
const ind = selector.options[selector.selectedIndex].value;
|
|
||||||
const newDivisionName = nameInput.value;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.corp.divisions.length; ++i) {
|
|
||||||
if (this.corp.divisions[i].name === newDivisionName) {
|
|
||||||
dialogBoxCreate("This name is already in use!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.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 {
|
|
||||||
this.corp.funds = this.corp.funds.minus(IndustryStartingCosts[ind]);
|
|
||||||
var newInd = new Industry({
|
|
||||||
corp: this.corp,
|
|
||||||
name: newDivisionName,
|
|
||||||
type: ind,
|
|
||||||
});
|
|
||||||
this.corp.divisions.push(newInd);
|
|
||||||
|
|
||||||
// Set routing to the new division so that the UI automatically switches to it
|
|
||||||
this.routing.routeTo(newDivisionName);
|
|
||||||
|
|
||||||
removeElementById("cmpy-mgmt-expand-industry-popup");
|
|
||||||
this.rerender();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const noBtn = createPopupCloseButton(popupId, {
|
|
||||||
display: "inline-block",
|
|
||||||
innerText: "Cancel",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make an object to keep track of what industries you're already in
|
|
||||||
const ownedIndustries = {};
|
|
||||||
for (let i = 0; i < this.corp.divisions.length; ++i) {
|
|
||||||
ownedIndustries[this.corp.divisions[i].type] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add industry types to selector
|
|
||||||
// Have Agriculture be first as recommended option
|
|
||||||
if (!ownedIndustries["Agriculture"]) {
|
|
||||||
selector.add(createElement("option", {
|
|
||||||
text:Industries["Agriculture"], value:"Agriculture",
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var key in Industries) {
|
|
||||||
if (key !== "Agriculture" && Industries.hasOwnProperty(key) && !ownedIndustries[key]) {
|
|
||||||
var ind = Industries[key];
|
|
||||||
selector.add(createElement("option", {
|
|
||||||
text: ind,value:key,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Initial Industry Description
|
|
||||||
var ind = selector.options[selector.selectedIndex].value;
|
|
||||||
industryDescription.innerHTML = (IndustryDescriptions[ind] + "<br><br>");
|
|
||||||
|
|
||||||
//Change the industry description text based on selected option
|
|
||||||
selector.addEventListener("change", function() {
|
|
||||||
var ind = selector.options[selector.selectedIndex].value;
|
|
||||||
industryDescription.innerHTML = IndustryDescriptions[ind] + "<br><br>";
|
|
||||||
});
|
|
||||||
|
|
||||||
//Add to DOM
|
|
||||||
const elems = [];
|
|
||||||
elems.push(txt);
|
|
||||||
elems.push(selector);
|
|
||||||
elems.push(industryDescription);
|
|
||||||
elems.push(nameLabel);
|
|
||||||
elems.push(nameInput);
|
|
||||||
elems.push(noBtn);
|
|
||||||
elems.push(yesBtn);
|
|
||||||
|
|
||||||
createPopup(popupId, elems);
|
|
||||||
nameInput.focus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a popup that lets the player use the Market TA research for Products
|
// Create a popup that lets the player use the Market TA research for Products
|
||||||
createProductMarketTaPopup(product, industry) {
|
createProductMarketTaPopup(product, industry) {
|
||||||
const popupId = "cmpy-mgmt-marketta-popup";
|
const popupId = "cmpy-mgmt-marketta-popup";
|
||||||
|
120
src/Corporation/ui/ExportPopup.tsx
Normal file
120
src/Corporation/ui/ExportPopup.tsx
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Warehouse } from "../Warehouse";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
mat: any;
|
||||||
|
corp: any;
|
||||||
|
popupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player manage exports
|
||||||
|
export function ExportPopup(props: IProps): React.ReactElement {
|
||||||
|
if(props.corp.divisions.length === 0)
|
||||||
|
throw new Error('Export popup created with no divisions.');
|
||||||
|
if(Object.keys(props.corp.divisions[0].warehouses).length === 0)
|
||||||
|
throw new Error('Export popup created in a division with no warehouses.');
|
||||||
|
const [industry, setIndustry] = useState<string>(props.corp.divisions[0].name);
|
||||||
|
const [city, setCity] = useState<string>(Object.keys(props.corp.divisions[0].warehouses)[0]);
|
||||||
|
const [amt, setAmt] = useState('');
|
||||||
|
const setRerender = useState(false)[1];
|
||||||
|
|
||||||
|
function rerender(): void {
|
||||||
|
setRerender(old => !old);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCityChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
setCity(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onIndustryChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
setIndustry(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAmtChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
setAmt(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportMaterial(): void {
|
||||||
|
const industryName = industry;
|
||||||
|
const cityName = city;
|
||||||
|
console.log(`${industryName}, ${cityName}, ${amt}`)
|
||||||
|
|
||||||
|
// Sanitize amt
|
||||||
|
let sanitizedAmt = amt.replace(/\s+/g, '');
|
||||||
|
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, '');
|
||||||
|
let temp = sanitizedAmt.replace(/MAX/g, '1');
|
||||||
|
try {
|
||||||
|
temp = eval(temp);
|
||||||
|
} catch(e) {
|
||||||
|
dialogBoxCreate("Invalid expression entered for export amount: " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const n = parseFloat(temp);
|
||||||
|
|
||||||
|
if (n == null || isNaN(n) || n < 0) {
|
||||||
|
dialogBoxCreate("Invalid amount entered for export");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const exportObj = {ind:industryName, city:cityName, amt:sanitizedAmt};
|
||||||
|
console.log(exportObj);
|
||||||
|
props.mat.exp.push(exportObj);
|
||||||
|
removePopup(props.popupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeExport(exp: any): 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) continue;
|
||||||
|
props.mat.exp.splice(i, 1);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDivision = props.corp.divisions.find((division: any) => division.name === industry);
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
Select the industry and city to export this material to, as well as
|
||||||
|
how much of this material to export per second. You can set the export
|
||||||
|
amount to 'MAX' to export all of the materials in this warehouse.
|
||||||
|
</p>
|
||||||
|
<select className="dropdown" onChange={onIndustryChange} defaultValue={industry}>
|
||||||
|
{
|
||||||
|
props.corp.divisions.map((division: any) =>
|
||||||
|
<option key={division.name} value={division.name}>{division.name}</option>)
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<select className="dropdown" onChange={onCityChange} defaultValue={city}>
|
||||||
|
{
|
||||||
|
currentDivision && Object.keys(currentDivision.warehouses).map((cityName: any) => {
|
||||||
|
if(currentDivision.warehouses[cityName] === 0) return;
|
||||||
|
return (<option key={cityName} value={cityName}>{cityName}</option>);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<input className="text-input" placeholder="Export amount / s" onChange={onAmtChange} />
|
||||||
|
<button className="std-button" style={{display:"inline-block"}} onClick={exportMaterial}>Export</button>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
{
|
||||||
|
props.mat.exp.map((exp: any, index: number) =>
|
||||||
|
<div key={index} className="cmpy-mgmt-existing-export" onClick={() => removeExport(exp)}>
|
||||||
|
Industry: {exp.ind}<br />
|
||||||
|
City: {exp.city}<br />
|
||||||
|
Amount/s: {exp.amt}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
</>);
|
||||||
|
}
|
@ -4,6 +4,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { HeaderTab } from "./HeaderTab";
|
import { HeaderTab } from "./HeaderTab";
|
||||||
import { IDivision } from "../IDivision";
|
import { IDivision } from "../IDivision";
|
||||||
|
import { NewIndustryPopup } from "./NewIndustryPopup";
|
||||||
|
import { createPopup } from "../../ui/React/createPopup";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
corp: any;
|
corp: any;
|
||||||
@ -17,6 +19,15 @@ export function HeaderTabs(props: IProps): React.ReactElement {
|
|||||||
props.corp.rerender();
|
props.corp.rerender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openNewIndustryPopup(): void {
|
||||||
|
const popupId = "cmpy-mgmt-expand-industry-popup";
|
||||||
|
createPopup(popupId, NewIndustryPopup, {
|
||||||
|
corp: props.corp,
|
||||||
|
routing: props.routing,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<HeaderTab
|
<HeaderTab
|
||||||
@ -38,7 +49,7 @@ export function HeaderTabs(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
<HeaderTab
|
<HeaderTab
|
||||||
current={false}
|
current={false}
|
||||||
onClick={() => props.eventHandler.createNewIndustryPopup()}
|
onClick={openNewIndustryPopup}
|
||||||
text={"Expand into new Industry"}
|
text={"Expand into new Industry"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,8 @@ import { IndustryUpgrades } from "../IndustryUpgrades";
|
|||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
||||||
|
import { MakeProductPopup } from "./MakeProductPopup";
|
||||||
|
import { createPopup } from "../../ui/React/createPopup";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
routing: any;
|
routing: any;
|
||||||
@ -77,8 +79,18 @@ export function IndustryOverview(props: IProps): React.ReactElement {
|
|||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openMakeProductPopup() {
|
||||||
|
const popupId = "cmpy-mgmt-create-product-popup";
|
||||||
|
createPopup(popupId, MakeProductPopup, {
|
||||||
|
popupText: createProductPopupText,
|
||||||
|
division: division,
|
||||||
|
corp: props.corp,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className={className} onClick={() => props.eventHandler.createMakeProductPopup(createProductPopupText, division)} style={buttonStyle}>
|
<button className={className} onClick={openMakeProductPopup} style={buttonStyle}>
|
||||||
{createProductButtonText}
|
{createProductButtonText}
|
||||||
{
|
{
|
||||||
hasMaxProducts &&
|
hasMaxProducts &&
|
||||||
|
@ -8,6 +8,9 @@ import { Material } from "../Material";
|
|||||||
import { Product } from "../Product";
|
import { Product } from "../Product";
|
||||||
import { Warehouse } from "../Warehouse";
|
import { Warehouse } from "../Warehouse";
|
||||||
import { DiscontinueProductPopup } from "./DiscontinueProductPopup";
|
import { DiscontinueProductPopup } from "./DiscontinueProductPopup";
|
||||||
|
import { ExportPopup } from "./ExportPopup";
|
||||||
|
import { LimitProductProductionPopup } from "./LimitProductProductionPopup";
|
||||||
|
import { MaterialMarketTaPopup } from "./MaterialMarketTaPopup";
|
||||||
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
@ -71,7 +74,15 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
if (product.prdman[city][0]) {
|
if (product.prdman[city][0]) {
|
||||||
limitProductionButtonText += " (" + numeralWrapper.format(product.prdman[city][1], nf) + ")";
|
limitProductionButtonText += " (" + numeralWrapper.format(product.prdman[city][1], nf) + ")";
|
||||||
}
|
}
|
||||||
const limitProductionButtonOnClick = eventHandler.createLimitProductProdutionPopup.bind(eventHandler, product, city);
|
|
||||||
|
function openLimitProductProdutionPopup(): void {
|
||||||
|
const popupId = "cmpy-mgmt-limit-product-production-popup";
|
||||||
|
createPopup(popupId, LimitProductProductionPopup, {
|
||||||
|
product: product,
|
||||||
|
city: city,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function openDiscontinueProductPopup(): void {
|
function openDiscontinueProductPopup(): void {
|
||||||
const popupId = "cmpy-mgmt-discontinue-product-popup";
|
const popupId = "cmpy-mgmt-discontinue-product-popup";
|
||||||
@ -83,8 +94,15 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Market TA button
|
function openMaterialMarketTaPopup(): void {
|
||||||
const marketTaButtonOnClick = eventHandler.createProductMarketTaPopup.bind(eventHandler, product, division);
|
const popupId = "cmpy-mgmt-export-popup";
|
||||||
|
createPopup(popupId, MaterialMarketTaPopup, {
|
||||||
|
mat: product,
|
||||||
|
industry: division,
|
||||||
|
corp: props.corp,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Unfinished Product
|
// Unfinished Product
|
||||||
if (!product.fin) {
|
if (!product.fin) {
|
||||||
@ -99,7 +117,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
<button className={"std-button"} onClick={sellButtonOnClick}>
|
<button className={"std-button"} onClick={sellButtonOnClick}>
|
||||||
{sellButtonText}
|
{sellButtonText}
|
||||||
</button><br />
|
</button><br />
|
||||||
<button className={"std-button"} onClick={limitProductionButtonOnClick}>
|
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
|
||||||
{limitProductionButtonText}
|
{limitProductionButtonText}
|
||||||
</button>
|
</button>
|
||||||
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
|
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
|
||||||
@ -107,7 +125,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
</button>
|
</button>
|
||||||
{
|
{
|
||||||
division.hasResearch("Market-TA.I") &&
|
division.hasResearch("Market-TA.I") &&
|
||||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
<button className={"std-button"} onClick={openMaterialMarketTaPopup}>
|
||||||
Market-TA
|
Market-TA
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@ -179,7 +197,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
<button className={"std-button"} onClick={sellButtonOnClick}>
|
<button className={"std-button"} onClick={sellButtonOnClick}>
|
||||||
{sellButtonText}
|
{sellButtonText}
|
||||||
</button><br />
|
</button><br />
|
||||||
<button className={"std-button"} onClick={limitProductionButtonOnClick}>
|
<button className={"std-button"} onClick={openLimitProductProdutionPopup}>
|
||||||
{limitProductionButtonText}
|
{limitProductionButtonText}
|
||||||
</button>
|
</button>
|
||||||
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
|
<button className={"std-button"} onClick={openDiscontinueProductPopup}>
|
||||||
@ -187,7 +205,7 @@ function ProductComponent(props: IProductProps): React.ReactElement {
|
|||||||
</button>
|
</button>
|
||||||
{
|
{
|
||||||
division.hasResearch("Market-TA.I") &&
|
division.hasResearch("Market-TA.I") &&
|
||||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
<button className={"std-button"} onClick={openMaterialMarketTaPopup}>
|
||||||
Market-TA
|
Market-TA
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@ -236,8 +254,14 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
|||||||
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
const purchaseButtonClass = tutorial ? "std-button flashing-button tooltip" : "std-button";
|
||||||
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
const purchaseButtonOnClick = eventHandler.createPurchaseMaterialPopup.bind(eventHandler, mat, division, warehouse);
|
||||||
|
|
||||||
// Export material button
|
function openExportPopup() {
|
||||||
const exportButtonOnClick = eventHandler.createExportMaterialPopup.bind(eventHandler, mat);
|
const popupId = "cmpy-mgmt-export-popup";
|
||||||
|
createPopup(popupId, ExportPopup, {
|
||||||
|
mat: mat,
|
||||||
|
corp: props.corp,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Sell material button
|
// Sell material button
|
||||||
let sellButtonText;
|
let sellButtonText;
|
||||||
@ -265,8 +289,15 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
const sellButtonOnClick = eventHandler.createSellMaterialPopup.bind(eventHandler, mat);
|
const sellButtonOnClick = eventHandler.createSellMaterialPopup.bind(eventHandler, mat);
|
||||||
|
|
||||||
// Market TA button
|
function openMaterialMarketTaPopup(): void {
|
||||||
const marketTaButtonOnClick = eventHandler.createMaterialMarketTaPopup.bind(eventHandler, mat, division);
|
const popupId = "cmpy-mgmt-export-popup";
|
||||||
|
createPopup(popupId, MaterialMarketTaPopup, {
|
||||||
|
mat: mat,
|
||||||
|
industry: division,
|
||||||
|
corp: props.corp,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"cmpy-mgmt-warehouse-material-div"}>
|
<div className={"cmpy-mgmt-warehouse-material-div"}>
|
||||||
@ -322,7 +353,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
|||||||
|
|
||||||
{
|
{
|
||||||
corp.unlockUpgrades[0] === 1 &&
|
corp.unlockUpgrades[0] === 1 &&
|
||||||
<button className={"std-button"} onClick={exportButtonOnClick}>
|
<button className={"std-button"} onClick={openExportPopup}>
|
||||||
Export
|
Export
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@ -334,7 +365,7 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
|||||||
|
|
||||||
{
|
{
|
||||||
division.hasResearch("Market-TA.I") &&
|
division.hasResearch("Market-TA.I") &&
|
||||||
<button className={"std-button"} onClick={marketTaButtonOnClick}>
|
<button className={"std-button"} onClick={openMaterialMarketTaPopup}>
|
||||||
Market-TA
|
Market-TA
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
57
src/Corporation/ui/IssueDividendsPopup.tsx
Normal file
57
src/Corporation/ui/IssueDividendsPopup.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { CorporationConstants } from "../data/Constants";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
popupId: string;
|
||||||
|
corp: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player issue & manage dividends
|
||||||
|
// This is created when the player clicks the "Issue Dividends" button in the overview panel
|
||||||
|
export function IssueDividendsPopup(props: IProps): React.ReactElement {
|
||||||
|
const [percent, setPercent] = useState<number | null>(null);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.corp.dividendPercentage = percent;
|
||||||
|
|
||||||
|
removePopup(props.popupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
|
if (event.keyCode === 13) issueDividends();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setPercent(null);
|
||||||
|
else setPercent(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
"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
|
||||||
|
integer between 0 and {CorporationConstants.DividendMaxPercentage}. (A percentage of 0 means no dividends will be
|
||||||
|
issued<br /><br />
|
||||||
|
Two important things to note:<br />
|
||||||
|
* Issuing dividends will negatively affect your corporation's stock price<br />
|
||||||
|
* Dividends are taxed. Taxes start at 50%, but can be decreased<br /><br />
|
||||||
|
Example: Assume your corporation makes $100m / sec in profit and you allocate
|
||||||
|
40% of that towards dividends. That means your corporation will gain $60m / sec
|
||||||
|
in funds and the remaining $40m / sec will be paid as dividends. Since your
|
||||||
|
corporation starts with 1 billion shares, every shareholder will be paid $0.04 per share
|
||||||
|
per second before taxes.
|
||||||
|
</p>
|
||||||
|
<input autoFocus={true} onChange={onChange} onKeyDown={onKeyDown} className="text-input" placeholder="Dividend %" type="number" style={{margin: "5px"}} />
|
||||||
|
<button onClick={issueDividends} className="std-button" style={{display: "inline-block"}}>Allocate Dividend Percentage</button>
|
||||||
|
</>);
|
||||||
|
}
|
134
src/Corporation/ui/IssueNewSharesPopup.tsx
Normal file
134
src/Corporation/ui/IssueNewSharesPopup.tsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
|
||||||
|
import { CorporationConstants } from "../data/Constants";
|
||||||
|
|
||||||
|
interface IEffectTextProps {
|
||||||
|
corp: any;
|
||||||
|
shares: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EffectText(props: IEffectTextProps): React.ReactElement {
|
||||||
|
if(props.shares === null) return (<></>);
|
||||||
|
const newSharePrice = Math.round(props.corp.sharePrice * 0.9);
|
||||||
|
const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2);
|
||||||
|
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
||||||
|
let newShares = props.shares;
|
||||||
|
if (isNaN(newShares)) {
|
||||||
|
return (<p>Invalid input</p>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round to nearest ten-millionth
|
||||||
|
newShares /= 10e6;
|
||||||
|
newShares = Math.round(newShares) * 10e6;
|
||||||
|
|
||||||
|
if (newShares < 10e6) {
|
||||||
|
return (<p>Must issue at least 10 million new shares</p>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newShares > maxNewShares) {
|
||||||
|
return (<p>You cannot issue that many shares</p>);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<p>
|
||||||
|
Issue ${numeralWrapper.format(newShares, "0.000a")} new
|
||||||
|
shares for {numeralWrapper.formatMoney(newShares * newSharePrice)}?
|
||||||
|
</p>);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
corp: any;
|
||||||
|
popupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player issue new shares
|
||||||
|
// This is created when the player clicks the "Issue New Shares" buttons in the overview panel
|
||||||
|
export function IssueNewSharesPopup(props: IProps): React.ReactElement {
|
||||||
|
const [shares, setShares] = useState<number | null>(null);
|
||||||
|
const maxNewSharesUnrounded = Math.round(props.corp.totalShares * 0.2);
|
||||||
|
const maxNewShares = maxNewSharesUnrounded - (maxNewSharesUnrounded % 1e6);
|
||||||
|
|
||||||
|
function issueNewShares(): void {
|
||||||
|
if(shares === null) return;
|
||||||
|
const newSharePrice = Math.round(props.corp.sharePrice * 0.9);
|
||||||
|
let newShares = shares;
|
||||||
|
if (isNaN(newShares)) {
|
||||||
|
dialogBoxCreate("Invalid input for number of new shares");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round to nearest ten-millionth
|
||||||
|
newShares = Math.round(newShares / 10e6) * 10e6;
|
||||||
|
|
||||||
|
if (newShares < 10e6 || newShares > maxNewShares) {
|
||||||
|
dialogBoxCreate("Invalid input for number of new shares");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const profit = newShares * newSharePrice;
|
||||||
|
props.corp.issueNewSharesCooldown = CorporationConstants.IssueNewSharesCooldown;
|
||||||
|
props.corp.totalShares += newShares;
|
||||||
|
|
||||||
|
// Determine how many are bought by private investors
|
||||||
|
// Private investors get up to 50% at most
|
||||||
|
// Round # of private shares to the nearest millionth
|
||||||
|
let privateShares = getRandomInt(0, Math.round(newShares / 2));
|
||||||
|
privateShares = Math.round(privateShares / 1e6) * 1e6;
|
||||||
|
|
||||||
|
props.corp.issuedShares += (newShares - privateShares);
|
||||||
|
props.corp.funds = props.corp.funds.plus(profit);
|
||||||
|
props.corp.immediatelyUpdateSharePrice();
|
||||||
|
|
||||||
|
removePopup(props.popupId);
|
||||||
|
dialogBoxCreate(`Issued ${numeralWrapper.format(newShares, "0.000a")} and raised ` +
|
||||||
|
`${numeralWrapper.formatMoney(profit)}. ${numeralWrapper.format(privateShares, "0.000a")} ` +
|
||||||
|
`of these shares were bought by private investors.<br><br>` +
|
||||||
|
`Stock price decreased to ${numeralWrapper.formatMoney(props.corp.sharePrice)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
|
if (event.keyCode === 13) issueNewShares();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setShares(null);
|
||||||
|
else setShares(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
You can issue new equity shares (i.e. stocks) in order to raise
|
||||||
|
capital for your corporation.<br /><br />
|
||||||
|
* You can issue at most {numeralWrapper.formatMoney(maxNewShares)} new shares<br />
|
||||||
|
* New shares are sold at a 10% discount<br />
|
||||||
|
* You can only issue new shares once every 12 hours<br />
|
||||||
|
* Issuing new shares causes dilution, resulting in a decrease in stock price and lower dividends per share<br />
|
||||||
|
* Number of new shares issued must be a multiple of 10 million<br /><br />
|
||||||
|
When you choose to issue new equity, private shareholders have first priority for up to 50% of the new shares.
|
||||||
|
If they choose to exercise this option, these newly issued shares become private, restricted shares, which means
|
||||||
|
you cannot buy them back.
|
||||||
|
</p>
|
||||||
|
<EffectText corp={props.corp} shares={shares} />
|
||||||
|
<input className="text-input" autoFocus={true} placeholder="# New Shares" style={{margin: "5px"}} onChange={onChange} onKeyDown={onKeyDown} />
|
||||||
|
<button onClick={issueNewShares} className="std-button" style={{display: "inline-block"}}>Issue New Shares</button>
|
||||||
|
</>);
|
||||||
|
|
||||||
|
|
||||||
|
// let issueBtn, newSharesInput;
|
||||||
|
// const dynamicText = createElement("p", {
|
||||||
|
// display: "block",
|
||||||
|
// });
|
||||||
|
|
||||||
|
// function updateDynamicText(corp) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// createPopup(popupId, [descText, dynamicText, newSharesInput, issueBtn, cancelBtn]);
|
||||||
|
// newSharesInput.focus();
|
||||||
|
}
|
59
src/Corporation/ui/LimitProductProductionPopup.tsx
Normal file
59
src/Corporation/ui/LimitProductProductionPopup.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Warehouse } from "../Warehouse";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
product: any;
|
||||||
|
city: any;
|
||||||
|
popupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player limit the production of a product
|
||||||
|
export function LimitProductProductionPopup(props: IProps): React.ReactElement {
|
||||||
|
const [limit, setLimit] = useState<number | null>(null);
|
||||||
|
|
||||||
|
function limitProductProduction(): void {
|
||||||
|
if (limit === null) {
|
||||||
|
props.product.prdman[props.city][0] = false;
|
||||||
|
removePopup(props.popupId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var qty = limit;
|
||||||
|
if (isNaN(qty)) {
|
||||||
|
dialogBoxCreate("Invalid value entered");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (qty < 0) {
|
||||||
|
props.product.prdman[props.city][0] = false;
|
||||||
|
} else {
|
||||||
|
props.product.prdman[props.city][0] = true;
|
||||||
|
props.product.prdman[props.city][1] = qty;
|
||||||
|
}
|
||||||
|
removePopup(props.popupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
|
if (event.keyCode === 13) limitProductProduction();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setLimit(null);
|
||||||
|
else setLimit(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
Enter a limit to the amount of this product you would
|
||||||
|
like to product per second. Leave the box empty to set no limit.
|
||||||
|
</p>
|
||||||
|
<input autoFocus={true} className="text-input" style={{margin: "5px"}} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} />
|
||||||
|
<button className="std-button" style={{margin:"5px", display:"inline-block"}} onClick={limitProductProduction}>Limit production</button>
|
||||||
|
</>);
|
||||||
|
}
|
107
src/Corporation/ui/MakeProductPopup.tsx
Normal file
107
src/Corporation/ui/MakeProductPopup.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Warehouse } from "../Warehouse";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
import { Industries } from "../IndustryData";
|
||||||
|
import { Product } from "../Product";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
popupText: string;
|
||||||
|
division: any;
|
||||||
|
corp: any;
|
||||||
|
popupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function productPlaceholder(tpe: string): string {
|
||||||
|
if (tpe === Industries.Food) {
|
||||||
|
return "Restaurant Name";
|
||||||
|
} else if (tpe === Industries.Healthcare) {
|
||||||
|
return "Hospital Name";
|
||||||
|
} else if (tpe === Industries.RealEstate) {
|
||||||
|
return "Property Name";
|
||||||
|
}
|
||||||
|
return "Product Name";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player create a product for their current industry
|
||||||
|
export function MakeProductPopup(props: IProps) {
|
||||||
|
const allCities = Object.keys(props.division.offices).
|
||||||
|
filter((cityName: string) => props.division.offices[cityName] !== 0);
|
||||||
|
const [city, setCity] = useState(allCities.length > 0 ? allCities[0] : '');
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [design, setDesign] = useState<number | null>(null);
|
||||||
|
const [marketing, setMarketing] = useState<number | null>(null);
|
||||||
|
if (props.division.hasMaximumNumberProducts()) return (<></>);
|
||||||
|
|
||||||
|
function makeProduct(): void {
|
||||||
|
let designInvest = design;
|
||||||
|
let marketingInvest = marketing;
|
||||||
|
if (designInvest == null || designInvest < 0) { designInvest = 0; }
|
||||||
|
if (marketingInvest == null || marketingInvest < 0) { marketingInvest = 0; }
|
||||||
|
if (name == null || name === "") {
|
||||||
|
dialogBoxCreate("You must specify a name for your product!");
|
||||||
|
} else if (isNaN(designInvest)) {
|
||||||
|
dialogBoxCreate("Invalid value for design investment");
|
||||||
|
} else if (isNaN(marketingInvest)) {
|
||||||
|
dialogBoxCreate("Invalid value for marketing investment");
|
||||||
|
} else if (props.corp.funds.lt(designInvest + marketingInvest)) {
|
||||||
|
dialogBoxCreate("You don't have enough company funds to make this large of an investment");
|
||||||
|
} else {
|
||||||
|
const product = new Product({
|
||||||
|
name: name.replace(/[<>]/g, ''), //Sanitize for HTMl elements
|
||||||
|
createCity: city,
|
||||||
|
designCost: designInvest,
|
||||||
|
advCost: marketingInvest,
|
||||||
|
});
|
||||||
|
if (props.division.products[product.name] instanceof Product) {
|
||||||
|
dialogBoxCreate(`You already have a product with this name!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.corp.funds = props.corp.funds.minus(designInvest + marketingInvest);
|
||||||
|
props.division.products[product.name] = product;
|
||||||
|
removePopup(props.popupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCityChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
setCity(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onProductNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
setName(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDesignChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setDesign(null);
|
||||||
|
else setDesign(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMarketingChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setMarketing(null);
|
||||||
|
else setMarketing(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
|
if (event.keyCode === 13) makeProduct();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p dangerouslySetInnerHTML={{__html: props.popupText}} />
|
||||||
|
<select className="dropdown" style={{margin: "5px"}} onChange={onCityChange} defaultValue={city}>
|
||||||
|
{
|
||||||
|
allCities.map((cityName: string) =>
|
||||||
|
<option key={cityName} value={cityName}>{cityName}</option>)
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<input onChange={onProductNameChange} className="text-input" style={{margin:"5px"}} placeholder={productPlaceholder(props.division.type)} />
|
||||||
|
<br />
|
||||||
|
<input onChange={onDesignChange} autoFocus={true} type="number" className="text-input" style={{margin:"5px"}} placeholder={"Design investment"}/>
|
||||||
|
<input onChange={onMarketingChange} onKeyDown={onKeyDown} type="number" className="text-input" style={{margin:"5px"}} placeholder={"Marketing investment"}/>
|
||||||
|
<button className="std-button" onClick={makeProduct}>Develop Product</button>
|
||||||
|
</>);
|
||||||
|
}
|
121
src/Corporation/ui/MaterialMarketTaPopup.tsx
Normal file
121
src/Corporation/ui/MaterialMarketTaPopup.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Warehouse } from "../Warehouse";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
|
||||||
|
interface IMarketTA2Props {
|
||||||
|
industry: any;
|
||||||
|
mat: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MarketTA2(props: IMarketTA2Props): React.ReactElement {
|
||||||
|
if(!props.industry.hasResearch("Market-TA.II")) return (<></>);
|
||||||
|
|
||||||
|
const [newCost, setNewCost] = useState<number>(props.mat.bCost);
|
||||||
|
const setRerender = useState(false)[1];
|
||||||
|
function rerender(): void {
|
||||||
|
setRerender(old => !old);
|
||||||
|
}
|
||||||
|
const markupLimit = props.mat.getMarkupLimit();
|
||||||
|
|
||||||
|
function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
if(event.target.value === "") setNewCost(0);
|
||||||
|
else setNewCost(parseFloat(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
const sCost = newCost;
|
||||||
|
let markup = 1;
|
||||||
|
if (sCost > props.mat.bCost) {
|
||||||
|
//Penalty if difference between sCost and bCost is greater than markup limit
|
||||||
|
if ((sCost - props.mat.bCost) > markupLimit) {
|
||||||
|
markup = Math.pow(markupLimit / (sCost - props.mat.bCost), 2);
|
||||||
|
}
|
||||||
|
} else if (sCost < props.mat.bCost) {
|
||||||
|
if (sCost <= 0) {
|
||||||
|
markup = 1e12; //Sell everything, essentially discard
|
||||||
|
} else {
|
||||||
|
//Lower prices than market increases sales
|
||||||
|
markup = props.mat.bCost / sCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMarketTA2(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
props.mat.marketTa2 = event.target.checked;
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
<br /><u><strong>Market-TA.II</strong></u><br />
|
||||||
|
If you sell at {numeralWrapper.formatMoney(sCost)},
|
||||||
|
then you will sell {numeralWrapper.format(markup, "0.00000")}x as much compared
|
||||||
|
to if you sold at market price.
|
||||||
|
</p>
|
||||||
|
<input className="text-input" type="number" style={{marginTop: "4px"}} onChange={onChange} value={newCost} />
|
||||||
|
<div style={{display: "block"}}>
|
||||||
|
<label className="tooltip" htmlFor="cmpy-mgmt-marketa2-checkbox" style={{color: "white"}}>
|
||||||
|
Use Market-TA.II for Auto-Sale Price
|
||||||
|
<span className="tooltiptext">
|
||||||
|
If this is enabled, then this Material will automatically
|
||||||
|
be sold at the optimal price such that the amount sold matches the
|
||||||
|
amount produced. (i.e. the highest possible price, while still ensuring
|
||||||
|
that all produced materials will be sold)
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input id="cmpy-mgmt-marketa2-checkbox" type="checkbox" onChange={onMarketTA2} checked={props.mat.marketTa2} style={{margin: "3px"}} />
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Note that Market-TA.II overrides Market-TA.I. This means that if
|
||||||
|
both are enabled, then Market-TA.II will take effect, not Market-TA.I
|
||||||
|
</p>
|
||||||
|
</>);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
mat: any;
|
||||||
|
industry: any;
|
||||||
|
corp: any;
|
||||||
|
popupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a popup that lets the player use the Market TA research for Materials
|
||||||
|
export function MaterialMarketTaPopup(props: IProps): React.ReactElement {
|
||||||
|
const setRerender = useState(false)[1];
|
||||||
|
function rerender(): void {
|
||||||
|
setRerender(old => !old);
|
||||||
|
}
|
||||||
|
const markupLimit = props.mat.getMarkupLimit();
|
||||||
|
|
||||||
|
function onMarketTA1(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
props.mat.marketTa1 = event.target.checked;
|
||||||
|
rerender();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>
|
||||||
|
<u><strong>Market-TA.I</strong></u><br />
|
||||||
|
The maximum sale price you can mark this up to
|
||||||
|
is {numeralWrapper.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
|
||||||
|
</p>
|
||||||
|
<div style={{display: 'block'}}>
|
||||||
|
<label className="tooltip" htmlFor="cmpy-mgmt-marketa1-checkbox" style={{color: "white"}}>
|
||||||
|
Use Market-TA.I for Auto-Sale Price
|
||||||
|
<span className="tooltiptext">
|
||||||
|
If this is enabled, then this Material will automatically
|
||||||
|
be sold at the price identified by Market-TA.I (i.e. the price shown above)
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input id="cmpy-mgmt-marketa1-checkbox" type="checkbox" onChange={onMarketTA1} checked={props.mat.marketTa1} style={{margin: "3px"}} />
|
||||||
|
</div>
|
||||||
|
<MarketTA2 mat={props.mat} industry={props.industry} />
|
||||||
|
</>);
|
||||||
|
|
||||||
|
}
|
89
src/Corporation/ui/NewIndustryPopup.tsx
Normal file
89
src/Corporation/ui/NewIndustryPopup.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Warehouse } from "../Warehouse";
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { createElement } from "../../../utils/uiHelpers/createElement";
|
||||||
|
import { removePopup } from "../../ui/React/createPopup";
|
||||||
|
import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement";
|
||||||
|
import { clearSelector } from "../../../utils/uiHelpers/clearSelector";
|
||||||
|
import { getSelectText,
|
||||||
|
getSelectValue } from "../../../utils/uiHelpers/getSelectData";
|
||||||
|
import {
|
||||||
|
Industries,
|
||||||
|
IndustryStartingCosts,
|
||||||
|
IndustryDescriptions } from "../IndustryData";
|
||||||
|
import { Industry } from "../Corporation";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
corp: any;
|
||||||
|
popupId: string;
|
||||||
|
routing: any;
|
||||||
|
}
|
||||||
|
// Create a popup that lets the player create a new industry.
|
||||||
|
// This is created when the player clicks the "Expand into new Industry" header tab
|
||||||
|
export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||||
|
const allIndustries = Object.keys(Industries).sort();
|
||||||
|
const possibleIndustries = allIndustries.filter((industryType: string) =>
|
||||||
|
props.corp.divisions.find((division: any) =>
|
||||||
|
division.type === industryType) === undefined).sort();
|
||||||
|
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : '');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
removePopup(props.popupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNameChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
|
setName(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
|
if (event.keyCode === 13) newIndustry();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onIndustryChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||||
|
setIndustry(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<p>Create a new division to expand into a new industry:</p>
|
||||||
|
<select className="dropdown" defaultValue={industry} onChange={onIndustryChange}>
|
||||||
|
{
|
||||||
|
possibleIndustries.map((industry: string) =>
|
||||||
|
<option key={industry} value={industry}>{industry}</option>)
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<p>{IndustryDescriptions[industry]}</p>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<p>Division name:</p>
|
||||||
|
<input autoFocus={true} value={name} onChange={onNameChange} onKeyDown={onKeyDown} type="text" className="text-input" style={{display:"block"}} maxLength={30} pattern="[a-zA-Z0-9-_]" />
|
||||||
|
<span onClick={newIndustry} className="popup-box-button">Create Division</span>
|
||||||
|
</>);
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,8 @@ import { UnlockUpgrade } from "./UnlockUpgrade";
|
|||||||
import { BribeFactionPopup } from "./BribeFactionPopup";
|
import { BribeFactionPopup } from "./BribeFactionPopup";
|
||||||
import { SellSharesPopup } from "./SellSharesPopup";
|
import { SellSharesPopup } from "./SellSharesPopup";
|
||||||
import { BuybackSharesPopup } from "./BuybackSharesPopup";
|
import { BuybackSharesPopup } from "./BuybackSharesPopup";
|
||||||
|
import { IssueDividendsPopup } from "./IssueDividendsPopup";
|
||||||
|
import { IssueNewSharesPopup } from "./IssueNewSharesPopup";
|
||||||
|
|
||||||
import { CorporationConstants } from "../data/Constants";
|
import { CorporationConstants } from "../data/Constants";
|
||||||
import { CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
|
import { CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
|
||||||
@ -245,6 +247,14 @@ export function Overview(props: IProps): React.ReactElement {
|
|||||||
tooltip: "Buy back shares you that previously issued or sold at market price.",
|
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 issueNewSharesOnCd = (corp.issueNewSharesCooldown > 0);
|
||||||
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
|
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
|
||||||
const issueNewSharesTooltip = issueNewSharesOnCd
|
const issueNewSharesTooltip = issueNewSharesOnCd
|
||||||
@ -253,15 +263,23 @@ export function Overview(props: IProps): React.ReactElement {
|
|||||||
const issueNewSharesBtn = createButton({
|
const issueNewSharesBtn = createButton({
|
||||||
class: issueNewSharesClass,
|
class: issueNewSharesClass,
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
onClick: props.eventHandler.createIssueNewSharesPopup,
|
onClick: openIssueNewSharesPopup,
|
||||||
text: "Issue New Shares",
|
text: "Issue New Shares",
|
||||||
tooltip: issueNewSharesTooltip,
|
tooltip: issueNewSharesTooltip,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function openIssueDividendsPopup(): void {
|
||||||
|
const popupId = "cmpy-mgmt-issue-dividends-popup";
|
||||||
|
createPopup(popupId, IssueDividendsPopup, {
|
||||||
|
popupId: popupId,
|
||||||
|
corp: props.corp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const issueDividendsBtn = createButton({
|
const issueDividendsBtn = createButton({
|
||||||
class: "std-button",
|
class: "std-button",
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
onClick: props.eventHandler.createIssueDividendsPopup,
|
onClick: openIssueDividendsPopup,
|
||||||
text: "Issue Dividends",
|
text: "Issue Dividends",
|
||||||
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
|
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
|
||||||
});
|
});
|
||||||
|
@ -591,6 +591,13 @@ class DevMenuComponent extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addCorporationResearch() {
|
||||||
|
if(!Player.corporation) return;
|
||||||
|
Player.corporation.divisions.forEach(div => {
|
||||||
|
div.sciResearch.qty += 1e10;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
specificContract() {
|
specificContract() {
|
||||||
generateContract({
|
generateContract({
|
||||||
problemType: this.state.codingcontract,
|
problemType: this.state.codingcontract,
|
||||||
@ -1181,6 +1188,11 @@ class DevMenuComponent extends Component {
|
|||||||
<button className="std-button" onClick={this.finishCorporationProducts}>Finish products</button>
|
<button className="std-button" onClick={this.finishCorporationProducts}>Finish products</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button className="std-button" onClick={this.addCorporationResearch}>Tons of research</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user