Fixed numerous bugs with the recent Corporation UI rewrite. Rebalanced Corporation mechanic to give employees better and more interesting effects

This commit is contained in:
danielyxie 2019-03-15 02:37:06 -07:00
parent 8470f307ac
commit c3ecc189fd
19 changed files with 394 additions and 214 deletions

@ -5,7 +5,7 @@ played at https://danielyxie.github.io/bitburner.
# Documentation # Documentation
The game's official documentation can be found on [Read The The game's official documentation can be found on [Read The
Docs](http://bitburner.readthedocs.io/). Please note that this is still a Docs](http://bitburner.readthedocs.io/). Please note that this is still a
work-in-progress and is in its early stages. work-in-progress.
The documentation is created using [Sphinx](http://www.sphinx-doc.org). The documentation is created using [Sphinx](http://www.sphinx-doc.org).
@ -14,11 +14,6 @@ files](/doc/source) and then making a pull request with your contributions.
For further guidance, please refer to the "As A Documentor" section of For further guidance, please refer to the "As A Documentor" section of
[CONTRIBUTING](CONTRIBUTING.md). [CONTRIBUTING](CONTRIBUTING.md).
# Wiki
The game's wiki can be found on [Wikia](http://bitburner.wikia.com/). Please
note that the wiki is in the process of being deprecated. Eventually all of
the wiki content will be moved into the Read The Docs documentation.
# Contribution # Contribution
There are many ways to contribute to the game. It can be as simple as fixing There are many ways to contribute to the game. It can be as simple as fixing
a typo, correcting a bug, or improving the UI. For guidance on doing so, a typo, correcting a bug, or improving the UI. For guidance on doing so,
@ -32,4 +27,4 @@ publish, and distribute your contributions to the project. A formal
Contributor's License Agreement will be drawn up in the future. Contributor's License Agreement will be drawn up in the future.
If you would like to make significant contributions to the project as a If you would like to make significant contributions to the project as a
collaborator, please reach out to @danielyxie to help coordinate the effort. collaborator, please reach out to @danielyxie to help coordinate the effort.

@ -159,5 +159,6 @@
/* Research */ /* Research */
#corporation-research-popup-box-content { #corporation-research-popup-box-content {
overflow-x: visible !important; overflow-x: auto !important;
overflow-y: auto !important;
} }

@ -258,6 +258,7 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.FactionPassiveRepGain = 0; BitNodeMultipliers.FactionPassiveRepGain = 0;
break; break;
case 3: //Corporatocracy case 3: //Corporatocracy
BitNodeMultipliers.HackingLevelMultiplier = 0.8;
BitNodeMultipliers.RepToDonateToFaction = 0.5; BitNodeMultipliers.RepToDonateToFaction = 0.5;
BitNodeMultipliers.AugmentationRepCost = 3; BitNodeMultipliers.AugmentationRepCost = 3;
BitNodeMultipliers.AugmentationMoneyCost = 3; BitNodeMultipliers.AugmentationMoneyCost = 3;
@ -268,6 +269,8 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.CompanyWorkMoney = 0.25; BitNodeMultipliers.CompanyWorkMoney = 0.25;
BitNodeMultipliers.CrimeMoney = 0.25; BitNodeMultipliers.CrimeMoney = 0.25;
BitNodeMultipliers.HacknetNodeMoney = 0.25; BitNodeMultipliers.HacknetNodeMoney = 0.25;
BitNodeMultipliers.HomeComputerRamCost = 1.5;
BitNodeMultipliers.PurchasedServerCost = 2;
break; break;
case 4: //The Singularity case 4: //The Singularity
BitNodeMultipliers.ServerMaxMoney = 0.15; BitNodeMultipliers.ServerMaxMoney = 0.15;

@ -1417,7 +1417,7 @@ Bladeburner.prototype.completeAction = function() {
break; break;
case ActionTypes["Hyperbolic Regeneration Chamber"]: case ActionTypes["Hyperbolic Regeneration Chamber"]:
Player.regenerateHp(HrcHpGain); Player.regenerateHp(HrcHpGain);
this.stamina = Math.max(this.maxStamina, this.stamina + HrcStaminaGain); // TODO Turn this into a const and adjust value this.stamina = Math.min(this.maxStamina, this.stamina + HrcStaminaGain);
this.startAction(this.action); this.startAction(this.action);
if (this.logging.general) { if (this.logging.general) {
this.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${HrcHpGain} HP and gained ${HrcStaminaGain} stamina`); this.log(`Rested in Hyperbolic Regeneration Chamber. Restored ${HrcHpGain} HP and gained ${HrcStaminaGain} stamina`);

@ -291,7 +291,15 @@ export let CONSTANTS: IMap<any> = {
** Added several new Research upgrades ** Added several new Research upgrades
** Reduced the amount of Scientific Research needed to unlock the Hi-Tech R&D Laboratory from 10k to 5k ** Reduced the amount of Scientific Research needed to unlock the Hi-Tech R&D Laboratory from 10k to 5k
** Energy Material requirement of the Software industry reduced from 1 to 0.5 ** Energy Material requirement of the Software industry reduced from 1 to 0.5
** It is now slightly easier to increase the Software industry's production multiplier
** Industries now have a maximum number of allowed products, starting at 3. This can be increased through research. ** Industries now have a maximum number of allowed products, starting at 3. This can be increased through research.
** You can now see an approximation of how each material affects an industry's production multiplier by clicking the "?" help tip next to it
** Significantly changed the effects of the different employee positions. See updated descriptions
** Reduced the amount of money you gain from private investors
** Training employees is now 3x more effective
* Rebalanced BitNode-3 to make it slightly harder
* Bug Fix: Bladeburner's Hyperbolic Regeneration Chamber should no longer instantly refill all stamina
` `
} }

@ -24,6 +24,8 @@ import { Player } from "../Player";
import { numeralWrapper } from "../ui/numeralFormat"; import { numeralWrapper } from "../ui/numeralFormat";
import { Page, routing } from "../ui/navigationTracking"; import { Page, routing } from "../ui/navigationTracking";
import { calculateEffectWithFactors } from "../utils/calculateEffectWithFactors";
import { dialogBoxCreate } from "../../utils/DialogBox"; import { dialogBoxCreate } from "../../utils/DialogBox";
import { clearSelector } from "../../utils/uiHelpers/clearSelector"; import { clearSelector } from "../../utils/uiHelpers/clearSelector";
import { Reviver, import { Reviver,
@ -37,7 +39,6 @@ import { formatNumber, generateRandomString } from "../../utils/String
import { getRandomInt } from "../../utils/helpers/getRandomInt"; import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { isString } from "../../utils/helpers/isString"; import { isString } from "../../utils/helpers/isString";
import { KEY } from "../../utils/helpers/keyCodes"; import { KEY } from "../../utils/helpers/keyCodes";
import { removeChildrenFromElement } from "../../utils/uiHelpers/removeChildrenFromElement";
import { removeElement } from "../../utils/uiHelpers/removeElement"; import { removeElement } from "../../utils/uiHelpers/removeElement";
import { removeElementById } from "../../utils/uiHelpers/removeElementById"; import { removeElementById } from "../../utils/uiHelpers/removeElementById";
import { yesNoBoxCreate, import { yesNoBoxCreate,
@ -48,8 +49,7 @@ import { yesNoBoxCreate,
yesNoTxtInpBoxGetNoButton, yesNoTxtInpBoxGetNoButton,
yesNoTxtInpBoxGetInput, yesNoTxtInpBoxGetInput,
yesNoBoxClose, yesNoBoxClose,
yesNoTxtInpBoxClose, yesNoTxtInpBoxClose } from "../../utils/YesNoBox";
yesNoBoxOpen } from "../../utils/YesNoBox";
// UI Related Imports // UI Related Imports
import React from "react"; import React from "react";
@ -124,18 +124,6 @@ function Industry(params={}) {
[Locations.Volhaven]: 0 [Locations.Volhaven]: 0
}; };
this.warehouses = { //Maps locations to warehouses. 0 if no warehouse at that location
[Locations.Aevum]: 0,
[Locations.Chonqing]: 0,
[Locations.Sector12]: new Warehouse({
loc:Locations.Sector12,
size: WarehouseInitialSize,
}),
[Locations.NewTokyo]: 0,
[Locations.Ishima]: 0,
[Locations.Volhaven]: 0
};
this.name = params.name ? params.name : 0; this.name = params.name ? params.name : 0;
this.type = params.type ? params.type : 0; this.type = params.type ? params.type : 0;
@ -183,6 +171,20 @@ function Industry(params={}) {
this.state = "START"; this.state = "START";
this.newInd = true; this.newInd = true;
this.warehouses = { //Maps locations to warehouses. 0 if no warehouse at that location
[Locations.Aevum]: 0,
[Locations.Chonqing]: 0,
[Locations.Sector12]: new Warehouse({
corp: params.corp,
industry: this,
loc: Locations.Sector12,
size: WarehouseInitialSize,
}),
[Locations.NewTokyo]: 0,
[Locations.Ishima]: 0,
[Locations.Volhaven]: 0
};
this.init(); this.init();
} }
@ -340,8 +342,8 @@ Industry.prototype.init = function() {
this.sciFac = 0.62; this.sciFac = 0.62;
this.advFac = 0.16; this.advFac = 0.16;
this.hwFac = 0.25; this.hwFac = 0.25;
this.reFac = 0.1; this.reFac = 0.15;
this.aiFac = 0.15; this.aiFac = 0.18;
this.robFac = 0.05; this.robFac = 0.05;
this.reqMats = { this.reqMats = {
"Hardware": 0.5, "Hardware": 0.5,
@ -711,7 +713,7 @@ Industry.prototype.processMaterials = function(marketCycles=1, company) {
for (var j = 0; j < this.prodMats.length; ++j) { for (var j = 0; j < this.prodMats.length; ++j) {
warehouse.materials[this.prodMats[j]].qty += (prod * producableFrac); warehouse.materials[this.prodMats[j]].qty += (prod * producableFrac);
warehouse.materials[this.prodMats[j]].qlt = warehouse.materials[this.prodMats[j]].qlt =
(office.employeeProd[EmployeePositions.Engineer] / 100 + (office.employeeProd[EmployeePositions.Engineer] / 90 +
Math.pow(this.sciResearch.qty, this.sciFac) + Math.pow(this.sciResearch.qty, this.sciFac) +
Math.pow(warehouse.materials["AICores"].qty, this.aiFac) / 10e3); Math.pow(warehouse.materials["AICores"].qty, this.aiFac) / 10e3);
} }
@ -918,27 +920,30 @@ Industry.prototype.processProducts = function(marketCycles=1, corporation) {
//Create products //Create products
if (this.state === "PRODUCTION") { if (this.state === "PRODUCTION") {
for (var prodName in this.products) { for (const prodName in this.products) {
if (this.products.hasOwnProperty(prodName)) { const prod = this.products[prodName];
var prod = this.products[prodName]; if (!prod.fin) {
if (!prod.fin) { const city = prod.createCity;
var city = prod.createCity, office = this.offices[city]; const office = this.offices[city];
var total = office.employeeProd[EmployeePositions.Operations] +
office.employeeProd[EmployeePositions.Engineer] + // Designing/Creating a Product is based mostly off Engineers
office.employeeProd[EmployeePositions.Management], ratio; const engrProd = office.employeeProd[EmployeePositions.Engineer];
if (total === 0) { const mgmtProd = office.employeeProd[EmployeePositions.Management];
ratio = 0; const opProd = office.employeeProd[EmployeePositions.Operations];
} else { const total = engrProd + mgmtProd + opProd;
ratio = office.employeeProd[EmployeePositions.Engineer] / total +
office.employeeProd[EmployeePositions.Operations] / total + if (total <= 0) { break; }
office.employeeProd[EmployeePositions.Management] / total;
} // Management is a multiplier for the production from Engineers
prod.createProduct(marketCycles, ratio * Math.pow(total, 0.35)); const mgmtFactor = 1 + (mgmtProd / (1.2 * total));
if (prod.prog >= 100) {
prod.finishProduct(office.employeeProd, this); const progress = (Math.pow(engrProd, 0.34) + Math.pow(opProd, 0.2)) * mgmtFactor;
}
break; prod.createProduct(marketCycles, progress);
if (prod.prog >= 100) {
prod.finishProduct(office.employeeProd, this);
} }
break;
} }
} }
} }
@ -1147,33 +1152,38 @@ Industry.prototype.upgrade = function(upgrade, refs) {
} }
} }
//Returns how much of a material can be produced based of office productivity (employee stats) // Returns how much of a material can be produced based of office productivity (employee stats)
Industry.prototype.getOfficeProductivity = function(office, params) { Industry.prototype.getOfficeProductivity = function(office, params) {
var total = office.employeeProd[EmployeePositions.Operations] + const opProd = office.employeeProd[EmployeePositions.Operations];
office.employeeProd[EmployeePositions.Engineer] + const engrProd = office.employeeProd[EmployeePositions.Engineer];
office.employeeProd[EmployeePositions.Management], ratio; const mgmtProd = office.employeeProd[EmployeePositions.Management]
if (total === 0) { const total = opProd + engrProd + mgmtProd;
ratio = 0;
} else { if (total <= 0) { return 0; }
ratio = (office.employeeProd[EmployeePositions.Operations] / total) *
(office.employeeProd[EmployeePositions.Engineer] / total) * // Management is a multiplier for the production from Operations and Engineers
(office.employeeProd[EmployeePositions.Management] / total); const mgmtFactor = 1 + (mgmtProd / (1.2 * total));
ratio = Math.max(0.01, ratio); //Minimum ratio value if you have employees
} // For production, Operations is slightly more important than engineering
// Both Engineering and Operations have diminishing returns
const prod = (Math.pow(opProd, 0.4) + Math.pow(engrProd, 0.3)) * mgmtFactor;
// Generic multiplier for the production. Used for game-balancing purposes
const balancingMult = 0.05;
if (params && params.forProduct) { if (params && params.forProduct) {
return ratio * Math.pow(total, 0.25); // Products are harder to create and therefore have less production
return 0.5 * balancingMult * prod;
} else { } else {
return 2 * ratio * Math.pow(total, 0.35); return balancingMult * prod;
} }
} }
//Returns a multiplier based on the office' 'Business' employees that affects sales // Returns a multiplier based on the office' 'Business' employees that affects sales
Industry.prototype.getBusinessFactor = function(office) { Industry.prototype.getBusinessFactor = function(office) {
var ratioMult = 1; const businessProd = 1 + office.employeeProd[EmployeePositions.Business];
if (office.employeeProd["total"] > 0) {
ratioMult = 1 + (office.employeeProd[EmployeePositions.Business] / office.employeeProd["total"]); return calculateEffectWithFactors(businessProd, 0.26, 10e3);
}
return ratioMult * Math.pow(1 + office.employeeProd[EmployeePositions.Business], 0.25);
} }
//Returns a set of multipliers based on the Industry's awareness, popularity, and advFac. This //Returns a set of multipliers based on the Industry's awareness, popularity, and advFac. This
@ -1399,7 +1409,7 @@ function Employee(params={}) {
//Returns the amount the employee needs to be paid //Returns the amount the employee needs to be paid
Employee.prototype.process = function(marketCycles=1, office) { Employee.prototype.process = function(marketCycles=1, office) {
var gain = 0.001 * marketCycles, var gain = 0.003 * marketCycles,
det = gain * Math.random(); det = gain * Math.random();
this.age += gain; this.age += gain;
this.exp += gain; this.exp += gain;
@ -1425,16 +1435,9 @@ Employee.prototype.process = function(marketCycles=1, office) {
this.eff += trainingEff; this.eff += trainingEff;
} }
//Weight based on how full office is this.ene -= det;
//Too many employees = more likely to decrease energy and happiness this.hap -= det;
var officeCapacityWeight = 0.5 * (office.employees.length / office.size - 0.5);
if (Math.random() < 0.5 - officeCapacityWeight) {
this.ene += det;
this.hap += det;
} else {
this.ene -= det;
this.hap -= det;
}
if (this.ene < office.minEne) {this.ene = office.minEne;} if (this.ene < office.minEne) {this.ene = office.minEne;}
if (this.hap < office.minHap) {this.hap = office.minHap;} if (this.hap < office.minHap) {this.hap = office.minHap;}
var salary = this.sal * marketCycles * SecsPerMarketCycle; var salary = this.sal * marketCycles * SecsPerMarketCycle;
@ -1640,18 +1643,16 @@ OfficeSpace.prototype.process = function(marketCycles=1, parentRefs) {
salaryPaid += salary; salaryPaid += salary;
} }
this.calculateEmployeeProductivity(marketCycles, parentRefs); this.calculateEmployeeProductivity(parentRefs);
return salaryPaid; return salaryPaid;
} }
OfficeSpace.prototype.calculateEmployeeProductivity = function(marketCycles=1, parentRefs) { OfficeSpace.prototype.calculateEmployeeProductivity = function(parentRefs) {
var company = parentRefs.corporation, industry = parentRefs.industry; var company = parentRefs.corporation, industry = parentRefs.industry;
//Reset //Reset
for (const name in this.employeeProd) { for (const name in this.employeeProd) {
if (this.employeeProd.hasOwnProperty(name)) { this.employeeProd[name] = 0;
this.employeeProd[name] = 0;
}
} }
var total = 0; var total = 0;
@ -1977,19 +1978,19 @@ Corporation.prototype.getInvestment = function() {
switch (this.fundingRound) { switch (this.fundingRound) {
case 0: //Seed case 0: //Seed
percShares = 0.10; percShares = 0.10;
roundMultiplier = 5; roundMultiplier = 4;
break; break;
case 1: //Series A case 1: //Series A
percShares = 0.35; percShares = 0.35;
roundMultiplier = 4; roundMultiplier = 3;
break; break;
case 2: //Series B case 2: //Series B
percShares = 0.25; percShares = 0.25;
roundMultiplier = 4; roundMultiplier = 3;
break; break;
case 3: //Series C case 3: //Series C
percShares = 0.20; percShares = 0.20;
roundMultiplier = 3.5; roundMultiplier = 2.5;
break; break;
case 4: case 4:
return; return;

@ -164,11 +164,11 @@ export class Product {
//Calculate properties //Calculate properties
var progrMult = this.prog / 100; var progrMult = this.prog / 100;
var engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"], const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"];
mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"], const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"];
rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"], const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"];
opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"], const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"];
busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"]; const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
var designMult = 1 + (Math.pow(this.designCost, 0.1) / 100); var designMult = 1 + (Math.pow(this.designCost, 0.1) / 100);
console.log("designMult: " + designMult); console.log("designMult: " + designMult);
var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) + var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) +

@ -8,6 +8,8 @@ import { ResearchMap } from "./ResearchMap";
import { IMap } from "../types"; import { IMap } from "../types";
import { numeralWrapper } from "../ui/numeralFormat";
interface IConstructorParams { interface IConstructorParams {
children?: Node[]; children?: Node[];
cost: number; cost: number;
@ -83,7 +85,7 @@ export class Node {
children: childrenArray, children: childrenArray,
HTMLclass: htmlClass, HTMLclass: htmlClass,
innerHTML: `<div id="${sanitizedName}-corp-research-click-listener" class="tooltip">` + innerHTML: `<div id="${sanitizedName}-corp-research-click-listener" class="tooltip">` +
`${this.text}<br>${this.cost} Scientific Research` + `${this.text}<br>${numeralWrapper.format(this.cost, "0,0")} Scientific Research` +
`<span class="tooltiptext">` + `<span class="tooltiptext">` +
`${research.desc}` + `${research.desc}` +
`</span>` + `</span>` +

@ -5,16 +5,19 @@ import { numeralWrapper } from "../ui/numeralFormat";
import { Generic_fromJSON, import { Generic_fromJSON,
Generic_toJSON, Generic_toJSON,
Reviver } from "../../utils/JSONReviver"; Reviver } from "../../utils/JSONReviver";
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
interface IConstructorParams {
loc?: string;
size?: number;
}
interface IParent { interface IParent {
getStorageMultiplier(): number; getStorageMultiplier(): number;
} }
interface IConstructorParams {
corp?: IParent;
industry?: IParent;
loc?: string;
size?: number;
}
export class Warehouse { export class Warehouse {
// Initiatizes a Warehouse object from a JSON save state. // Initiatizes a Warehouse object from a JSON save state.
static fromJSON(value: any): Warehouse { static fromJSON(value: any): Warehouse {
@ -65,6 +68,10 @@ export class Warehouse {
AICores: new Material({name: "AI Cores"}), AICores: new Material({name: "AI Cores"}),
RealEstate: new Material({name: "Real Estate"}) RealEstate: new Material({name: "Real Estate"})
} }
if (params.corp && params.industry) {
this.updateSize(params.corp, params.industry);
}
} }
// Re-calculate how much space is being used by this Warehouse // Re-calculate how much space is being used by this Warehouse
@ -76,7 +83,7 @@ export class Warehouse {
if (MaterialSizes.hasOwnProperty(matName)) { if (MaterialSizes.hasOwnProperty(matName)) {
this.sizeUsed += (mat.qty * MaterialSizes[matName]); this.sizeUsed += (mat.qty * MaterialSizes[matName]);
if (mat.qty > 0) { if (mat.qty > 0) {
this.breakdown += (matName + ": " + numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0") + "<br>"); this.breakdown += (matName + ": " + numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0") + "<br>");
} }
} }
} }
@ -86,9 +93,13 @@ export class Warehouse {
} }
updateSize(corporation: IParent, industry: IParent) { updateSize(corporation: IParent, industry: IParent) {
this.size = (this.level * 100) try {
* corporation.getStorageMultiplier() this.size = (this.level * 100)
* industry.getStorageMultiplier(); * corporation.getStorageMultiplier()
* industry.getStorageMultiplier();
} catch(e) {
exceptionAlert(e);
}
} }
// Serialize the current object to a JSON save state. // Serialize the current object to a JSON save state.

@ -14,6 +14,9 @@ export class CityTabs extends BaseReactComponent {
if (props.city == null) { if (props.city == null) {
throw new Error(`CityTabs component constructed without 'city' property`) throw new Error(`CityTabs component constructed without 'city' property`)
} }
if (props.cityStateSetter == null) {
throw new Error(`CityTabs component constructed without 'cityStateSetter' property`)
}
super(props); super(props);
} }
@ -46,7 +49,8 @@ export class CityTabs extends BaseReactComponent {
} }
// Tab to "Expand into new City" // Tab to "Expand into new City"
const newCityOnClick = this.eventHandler().createNewCityPopup.bind(this.eventHandler(), division); const newCityOnClick = this.eventHandler().createNewCityPopup.bind(this.eventHandler(), division, this.props.cityStateSetter);
tabs.push(this.renderTab({ tabs.push(this.renderTab({
current: false, current: false,
key: "Expand into new City", key: "Expand into new City",

@ -17,6 +17,8 @@ import { Industries,
IndustryDescriptions, IndustryDescriptions,
IndustryResearchTrees } from "../IndustryData"; IndustryResearchTrees } from "../IndustryData";
import { Product } from "../Product";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
@ -109,7 +111,7 @@ export class CorporationEventHandler {
} }
} }
}); });
var confirmButton = createElement("a", { var confirmButton = createElement("button", {
class:"a-link-button", innerText:"Bribe", display:"inline-block", class:"a-link-button", innerText:"Bribe", display:"inline-block",
clickListener:()=>{ clickListener:()=>{
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value); var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
@ -181,7 +183,7 @@ export class CorporationEventHandler {
} }
} }
}); });
var confirmBtn = createElement("a", { var confirmBtn = createElement("button", {
class:"a-link-button", innerText:"Buy shares", display:"inline-block", class:"a-link-button", innerText:"Buy shares", display:"inline-block",
clickListener: () => { clickListener: () => {
var shares = Math.round(input.value); var shares = Math.round(input.value);
@ -234,12 +236,12 @@ export class CorporationEventHandler {
"produce this product and all of its existing stock will be " + "produce this product and all of its existing stock will be " +
"removed and left unsold", "removed and left unsold",
}); });
const confirmBtn = createElement("a", { const confirmBtn = createElement("button", {
class:"a-link-button",innerText:"Discontinue", class:"a-link-button",innerText:"Discontinue",
clickListener:()=>{ clickListener: () => {
industry.discontinueProduct(product, parentRefs); industry.discontinueProduct(product, parentRefs);
removeElementById(popupId); removeElementById(popupId);
this.corp.rerender(); this.rerender();
return false; return false;
} }
}); });
@ -294,7 +296,7 @@ export class CorporationEventHandler {
placeholder:"Export amount / s" placeholder:"Export amount / s"
}); });
const exportBtn = createElement("a", { const exportBtn = createElement("button", {
class: "std-button", display:"inline-block", innerText:"Export", class: "std-button", display:"inline-block", innerText:"Export",
clickListener: () => { clickListener: () => {
const industryName = getSelectText(industrySelector); const industryName = getSelectText(industrySelector);
@ -473,7 +475,7 @@ export class CorporationEventHandler {
} }
}); });
issueBtn = createElement("a", { issueBtn = createElement("button", {
class: "std-button", class: "std-button",
display: "inline-block", display: "inline-block",
innerText: "Issue New Shares", innerText: "Issue New Shares",
@ -529,7 +531,7 @@ export class CorporationEventHandler {
} }
// Create a popup that lets the player limit the production of a product // Create a popup that lets the player limit the production of a product
createLimitProductProdutionPopup(product) { createLimitProductProdutionPopup(product, city) {
const popupId = "cmpy-mgmt-limit-product-production-popup"; const popupId = "cmpy-mgmt-limit-product-production-popup";
const txt = createElement("p", { const txt = createElement("p", {
innerText:"Enter a limit to the amount of this product you would " + innerText:"Enter a limit to the amount of this product you would " +
@ -543,7 +545,7 @@ export class CorporationEventHandler {
if (e.keyCode === KEY.ENTER) { confirmBtn.click(); } if (e.keyCode === KEY.ENTER) { confirmBtn.click(); }
} }
}); });
confirmBtn = createElement("a", { confirmBtn = createElement("button", {
class: "std-button", class: "std-button",
display:"inline-block", display:"inline-block",
innerText:"Limit production", innerText:"Limit production",
@ -585,7 +587,7 @@ export class CorporationEventHandler {
const txt = createElement("p", { const txt = createElement("p", {
innerHTML: popupText, innerHTML: popupText,
}); });
const designCity = createElement("select"); const designCity = createElement("select", { margin: "5px" });
for (const cityName in division.offices) { for (const cityName in division.offices) {
if (division.offices[cityName] instanceof OfficeSpace) { if (division.offices[cityName] instanceof OfficeSpace) {
designCity.add(createElement("option", { designCity.add(createElement("option", {
@ -603,18 +605,26 @@ export class CorporationEventHandler {
productNamePlaceholder = "Property Name"; productNamePlaceholder = "Property Name";
} }
var productNameInput = createElement("input", { var productNameInput = createElement("input", {
margin: "5px",
placeholder: productNamePlaceholder, placeholder: productNamePlaceholder,
}); });
var lineBreak1 = createElement("br"); var lineBreak1 = createElement("br");
var designInvestInput = createElement("input", { var designInvestInput = createElement("input", {
margin: "5px",
placeholder: "Design investment",
type: "number", type: "number",
placeholder: "Design investment"
}); });
let confirmBtn;
var marketingInvestInput = createElement("input", { var marketingInvestInput = createElement("input", {
margin: "5px",
placeholder: "Marketing investment",
type: "number", type: "number",
placeholder: "Marketing investment" onkeyup: (e) => {
e.preventDefault();
if (e.keyCode === KEY.ENTER) { confirmBtn.click(); }
}
}); });
const confirmBtn = createElement("a", { confirmBtn = createElement("button", {
class: "std-button", class: "std-button",
innerText: "Develop Product", innerText: "Develop Product",
clickListener: () => { clickListener: () => {
@ -637,17 +647,19 @@ export class CorporationEventHandler {
designCost: designInvest, designCost: designInvest,
advCost: marketingInvest, 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); this.corp.funds = this.corp.funds.minus(designInvest + marketingInvest);
division.products[product.name] = product; division.products[product.name] = product;
removeElementById(popupId); removeElementById(popupId);
} }
this.rerender(); this.rerender();
//this.updateUIContent();
//this.displayDivisionContent(division, city);
return false; return false;
} }
}) })
const cancelBtn = createPopupCloseButton(popupid, { const cancelBtn = createPopupCloseButton(popupId, {
class: "std-button", class: "std-button",
innerText: "Cancel", innerText: "Cancel",
}); });
@ -741,7 +753,8 @@ export class CorporationEventHandler {
} }
// Create a popup that lets the player expand into a new city (for the current industry) // Create a popup that lets the player expand into a new city (for the current industry)
createNewCityPopup(division) { // The 'cityStateSetter' arg is a function that sets the UI's 'city' state property
createNewCityPopup(division, cityStateSetter) {
const popupId = "cmpy-mgmt-expand-city-popup"; const popupId = "cmpy-mgmt-expand-city-popup";
const text = createElement("p", { const text = createElement("p", {
innerText: "Would you like to expand into a new city by opening an office? " + innerText: "Would you like to expand into a new city by opening an office? " +
@ -757,7 +770,7 @@ export class CorporationEventHandler {
} }
} }
const confirmBtn = createElement("a", { const confirmBtn = createElement("button", {
class:"std-button", class:"std-button",
display:"inline-block", display:"inline-block",
innerText: "Confirm", innerText: "Confirm",
@ -772,9 +785,11 @@ export class CorporationEventHandler {
loc: city, loc: city,
size: OfficeInitialSize, size: OfficeInitialSize,
}); });
this.corp.displayDivisionContent(division, city);
} }
cityStateSetter(city);
removeElementById(popupId); removeElementById(popupId);
this.rerender();
return false; return false;
} }
}); });
@ -836,15 +851,17 @@ export class CorporationEventHandler {
} else { } else {
this.corp.funds = this.corp.funds.minus(IndustryStartingCosts[ind]); this.corp.funds = this.corp.funds.minus(IndustryStartingCosts[ind]);
var newInd = new Industry({ var newInd = new Industry({
name:newDivisionName, corp: this.corp,
type:ind, name: newDivisionName,
type: ind,
}); });
this.corp.divisions.push(newInd); this.corp.divisions.push(newInd);
// this.corp.updateUIHeaderTabs();
// this.corp.selectHeaderTab(headerTabs[headerTabs.length-2]); // Set routing to the new division so that the UI automatically switches to it
this.routing.routeTo(newDivisionName);
removeElementById("cmpy-mgmt-expand-industry-popup"); removeElementById("cmpy-mgmt-expand-industry-popup");
this.rerender(); this.rerender();
// this.corp.displayDivisionContent(newInd, Locations.Sector12);
} }
return false; return false;
} }
@ -855,14 +872,14 @@ export class CorporationEventHandler {
innerText: "Cancel", innerText: "Cancel",
}); });
//Make an object to keep track of what industries you're already in // Make an object to keep track of what industries you're already in
const ownedIndustries = {}; const ownedIndustries = {};
for (let i = 0; i < this.corp.divisions.length; ++i) { for (let i = 0; i < this.corp.divisions.length; ++i) {
ownedIndustries[this.corp.divisions[i].type] = true; ownedIndustries[this.corp.divisions[i].type] = true;
} }
//Add industry types to selector // Add industry types to selector
//Have Agriculture be first as recommended option // Have Agriculture be first as recommended option
if (!ownedIndustries["Agriculture"]) { if (!ownedIndustries["Agriculture"]) {
selector.add(createElement("option", { selector.add(createElement("option", {
text:Industries["Agriculture"], value:"Agriculture" text:Industries["Agriculture"], value:"Agriculture"
@ -933,6 +950,7 @@ export class CorporationEventHandler {
mat.buy = parseFloat(input.value); mat.buy = parseFloat(input.value);
if (isNaN(mat.buy)) {mat.buy = 0;} if (isNaN(mat.buy)) {mat.buy = 0;}
removeElementById(purchasePopupId); removeElementById(purchasePopupId);
this.rerender();
return false; return false;
} }
} }
@ -942,6 +960,7 @@ export class CorporationEventHandler {
clickListener: () => { clickListener: () => {
mat.buy = 0; mat.buy = 0;
removeElementById(purchasePopupId); removeElementById(purchasePopupId);
this.rerender();
return false; return false;
} }
}); });
@ -979,7 +998,7 @@ export class CorporationEventHandler {
type: "number", type: "number",
onkeyup: (e) => { onkeyup: (e) => {
e.preventDefault(); e.preventDefault();
bulkPurchaseUpdateCostTxt(); updateBulkPurchaseText();
if (e.keyCode === KEY.ENTER) {bulkPurchaseConfirmBtn.click();} if (e.keyCode === KEY.ENTER) {bulkPurchaseConfirmBtn.click();}
} }
}); });
@ -1010,6 +1029,7 @@ export class CorporationEventHandler {
elems.push(bulkPurchaseInfo); elems.push(bulkPurchaseInfo);
elems.push(bulkPurchaseCostTxt); elems.push(bulkPurchaseCostTxt);
elems.push(bulkPurchaseInput); elems.push(bulkPurchaseInput);
elems.push(bulkPurchaseConfirmBtn);
} }
createPopup(purchasePopupId, elems); createPopup(purchasePopupId, elems);
@ -1129,7 +1149,7 @@ export class CorporationEventHandler {
} }
// Create a popup that lets the player manage sales of the product // Create a popup that lets the player manage sales of the product
createSellProductPopup(product) { createSellProductPopup(product, city) {
const popupId = "cmpy-mgmt-sell-product-popup"; const popupId = "cmpy-mgmt-sell-product-popup";
const txt = createElement("p", { const txt = createElement("p", {
innerHTML:"Enter the maximum amount of " + product.name + " you would like " + innerHTML:"Enter the maximum amount of " + product.name + " you would like " +
@ -1150,15 +1170,17 @@ export class CorporationEventHandler {
}); });
let confirmBtn; let confirmBtn;
const inputQty = createElement("input", { const inputQty = createElement("input", {
margin: "5px 0px 5px 0px",
placeholder: "Sell amount", placeholder: "Sell amount",
type: "text", type: "text",
value:product.sllman[city][1] ? product.sllman[city][1] : null, value: product.sllman[city][1] ? product.sllman[city][1] : null,
onkeyup: (e) => { onkeyup: (e) => {
e.preventDefault(); e.preventDefault();
if (e.keyCode === KEY.ENTER) {confirmBtn.click();} if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
} }
}); });
const inputPx = createElement("input", { const inputPx = createElement("input", {
margin: "5px 0px 5px 0px",
placeholder: "Sell price", placeholder: "Sell price",
type: "text", type: "text",
value: product.sCost ? product.sCost : null, value: product.sCost ? product.sCost : null,
@ -1167,7 +1189,7 @@ export class CorporationEventHandler {
if (e.keyCode === KEY.ENTER) {confirmBtn.click();} if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
} }
}); });
confirmBtn = createElement("a", { confirmBtn = createElement("button", {
class: "std-button", class: "std-button",
innerText: "Confirm", innerText: "Confirm",
clickListener: () => { clickListener: () => {
@ -1276,7 +1298,7 @@ export class CorporationEventHandler {
} }
} }
}); });
const confirmBtn = createElement("a", { const confirmBtn = createElement("button", {
class:"a-link-button", innerText:"Sell shares", display:"inline-block", class:"a-link-button", innerText:"Sell shares", display:"inline-block",
clickListener:()=>{ clickListener:()=>{
var shares = Math.round(input.value); var shares = Math.round(input.value);
@ -1355,7 +1377,7 @@ export class CorporationEventHandler {
if (e.keyCode === KEY.ENTER) {confirmBtn.click();} if (e.keyCode === KEY.ENTER) {confirmBtn.click();}
} }
}); });
confirmBtn = createElement("a", { confirmBtn = createElement("button", {
class: "std-button", class: "std-button",
innerText: "Throw Party", innerText: "Throw Party",
clickListener:()=>{ clickListener:()=>{
@ -1366,20 +1388,20 @@ export class CorporationEventHandler {
if (this.corp.funds.lt(totalCost)) { if (this.corp.funds.lt(totalCost)) {
dialogBoxCreate("You don't have enough company funds to throw this.corp party!"); dialogBoxCreate("You don't have enough company funds to throw this.corp party!");
} else { } else {
this.corp.funds = this.funds.minus(totalCost); this.corp.funds = this.corp.funds.minus(totalCost);
var mult; var mult;
for (let fooit = 0; fooit < office.employees.length; ++fooit) { for (let fooit = 0; fooit < office.employees.length; ++fooit) {
mult = office.employees[fooit].throwParty(input.value); mult = office.employees[fooit].throwParty(input.value);
} }
dialogBoxCreate("You threw a party for the office! The morale and happiness " + dialogBoxCreate("You threw a party for the office! The morale and happiness " +
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%."); "of each employee increased by " + numeralWrapper.formatPercentage((mult-1)));
removeElementById(popupId); removeElementById(popupId);
} }
} }
return false; return false;
} }
}); });
const cancelBtn = createPopupCloseButton(popupId, { innerText: "Cancel" }); const cancelBtn = createPopupCloseButton(popupId, { class: "std-button", innerText: "Cancel" });
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]); createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]);
input.focus(); input.focus();
@ -1420,7 +1442,7 @@ export class CorporationEventHandler {
}); });
const text2 = createElement("p", { innerText: "Upgrade size: " }); const text2 = createElement("p", { innerText: "Upgrade size: " });
const confirmBtn = createElement("a", { const confirmBtn = createElement("button", {
class: this.corp.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button", class: this.corp.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by 3", display:"inline-block", margin:"4px", innerText:"by 3",
tooltip:numeralWrapper.format(upgradeCost, "$0.000a"), tooltip:numeralWrapper.format(upgradeCost, "$0.000a"),
@ -1437,7 +1459,7 @@ export class CorporationEventHandler {
return false; return false;
} }
}); });
const confirmBtn15 = createElement("a", { const confirmBtn15 = createElement("button", {
class: this.corp.funds.lt(upgradeCost15) ? "a-link-button-inactive" : "a-link-button", class: this.corp.funds.lt(upgradeCost15) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by 15", display:"inline-block", margin:"4px", innerText:"by 15",
tooltip:numeralWrapper.format(upgradeCost15, "$0.000a"), tooltip:numeralWrapper.format(upgradeCost15, "$0.000a"),
@ -1454,7 +1476,7 @@ export class CorporationEventHandler {
return false; return false;
} }
}); });
const confirmBtnMax = createElement("a", { const confirmBtnMax = createElement("button", {
class:this.corp.funds.lt(upgradeCostMax) ? "a-link-button-inactive" : "a-link-button", class:this.corp.funds.lt(upgradeCostMax) ? "a-link-button-inactive" : "a-link-button",
display:"inline-block", margin:"4px", innerText:"by MAX (" + maxNum*OfficeInitialSize + ")", display:"inline-block", margin:"4px", innerText:"by MAX (" + maxNum*OfficeInitialSize + ")",
tooltip:numeralWrapper.format(upgradeCostMax, "$0.000a"), tooltip:numeralWrapper.format(upgradeCostMax, "$0.000a"),
@ -1484,6 +1506,8 @@ export class CorporationEventHandler {
dialogBoxCreate("You do not have enough funds to do this!"); dialogBoxCreate("You do not have enough funds to do this!");
} else { } else {
division.warehouses[city] = new Warehouse({ division.warehouses[city] = new Warehouse({
corp: corp,
industry: division,
loc: city, loc: city,
size: WarehouseInitialSize, size: WarehouseInitialSize,
}); });

@ -15,6 +15,8 @@ export class IndustryOffice extends BaseReactComponent {
super(props); super(props);
this.state = { this.state = {
city: "",
division: "",
employeeManualAssignMode: false, employeeManualAssignMode: false,
employee: null, // Reference to employee being referenced if in Manual Mode employee: null, // Reference to employee being referenced if in Manual Mode
numEmployees: 0, numEmployees: 0,
@ -30,6 +32,17 @@ export class IndustryOffice extends BaseReactComponent {
this.updateEmployeeCount(); // This function validates division and office refs this.updateEmployeeCount(); // This function validates division and office refs
} }
resetEmployeeCount() {
this.state.numEmployees = 0;
this.state.numOperations = 0;
this.state.numEngineers = 0;
this.state.numBusiness = 0;
this.state.numManagement = 0;
this.state.numResearch = 0;
this.state.numUnassigned = 0;
this.state.numTraining = 0;
}
updateEmployeeCount() { updateEmployeeCount() {
const division = this.routing().currentDivision; const division = this.routing().currentDivision;
if (division == null) { if (division == null) {
@ -40,6 +53,13 @@ export class IndustryOffice extends BaseReactComponent {
throw new Error(`Current City (${this.props.currentCity}) for UI does not have an OfficeSpace object`); throw new Error(`Current City (${this.props.currentCity}) for UI does not have an OfficeSpace object`);
} }
// If we're in a new city, we have to reset the state
if (division.name !== this.state.division || this.props.currentCity !== this.state.city) {
this.resetEmployeeCount();
this.state.division = division.name;
this.state.city = this.props.currentCity;
}
// Calculate how many NEW emplyoees we need to account for // Calculate how many NEW emplyoees we need to account for
const currentNumEmployees = office.employees.length; const currentNumEmployees = office.employees.length;
const newEmployees = currentNumEmployees - this.state.numEmployees; const newEmployees = currentNumEmployees - this.state.numEmployees;
@ -151,6 +171,7 @@ export class IndustryOffice extends BaseReactComponent {
--this.state.numUnassigned; --this.state.numUnassigned;
office.assignEmployeeToJob(to); office.assignEmployeeToJob(to);
office.calculateEmployeeProductivity({ corporation: this.corp(), industry:division });
this.corp().rerender(); this.corp().rerender();
} }
@ -194,6 +215,7 @@ export class IndustryOffice extends BaseReactComponent {
++this.state.numUnassigned; ++this.state.numUnassigned;
office.unassignEmployeeFromJob(from); office.unassignEmployeeFromJob(from);
office.calculateEmployeeProductivity({ corporation: this.corp(), industry:division });
this.corp().rerender(); this.corp().rerender();
} }
@ -283,36 +305,40 @@ export class IndustryOffice extends BaseReactComponent {
<p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p> <p>Total Employee Salary: {numeralWrapper.formatMoney(totalSalary)}</p>
{ {
vechain && vechain &&
<div> <p className={"tooltip"} style={{display: "block"}}>
<p className={"tooltip"}>
Material Production: {numeralWrapper.format(division.getOfficeProductivity(office), "0.000")} Material Production: {numeralWrapper.format(division.getOfficeProductivity(office), "0.000")}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
The base amount of material this office can produce. Does not include The base amount of material this office can produce. Does not include
production multipliers from upgrades and materials. This value is based off production multipliers from upgrades and materials. This value is based off
the productivity of your Operations, Engineering, and Management employees the productivity of your Operations, Engineering, and Management employees
</span> </span>
</p><br /> </p>
<p className={"tooltip"}> }
{
vechain &&
<p className={"tooltip"} style={{display: "block"}}>
Product Production: {numeralWrapper.format(division.getOfficeProductivity(office, {forProduct:true}), "0.000")} Product Production: {numeralWrapper.format(division.getOfficeProductivity(office, {forProduct:true}), "0.000")}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
The base amount of any given Product this office can produce. Does not include The base amount of any given Product this office can produce. Does not include
production multipliers from upgrades and materials. This value is based off production multipliers from upgrades and materials. This value is based off
the productivity of your Operations, Engineering, and Management employees the productivity of your Operations, Engineering, and Management employees
</span> </span>
</p><br /> </p>
<p className={"tooltip"}> }
Business Multiplier: x" ${numeralWrapper.format(division.getBusinessFactor(office), "0.000")} {
vechain &&
<p className={"tooltip"} style={{display: "block"}}>
Business Multiplier: x{numeralWrapper.format(division.getBusinessFactor(office), "0.000")}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
The effect this office's 'Business' employees has on boosting sales The effect this office's 'Business' employees has on boosting sales
</span> </span>
</p><br /> </p>
</div>
} }
<h2 className={"tooltip"} style={positionHeaderStyle}> <h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Operations} ({this.state.numOperations}) {EmployeePositions.Operations} ({this.state.numOperations})
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Manages supply chain operations. Improves production. Manages supply chain operations. Improves the amount of Materials and Products you produce.
</span> </span>
</h2> </h2>
<button className={assignButtonClass} onClick={operationAssignButtonOnClick}>+</button> <button className={assignButtonClass} onClick={operationAssignButtonOnClick}>+</button>
@ -322,7 +348,9 @@ export class IndustryOffice extends BaseReactComponent {
<h2 className={"tooltip"} style={positionHeaderStyle}> <h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Engineer} ({this.state.numEngineers}) {EmployeePositions.Engineer} ({this.state.numEngineers})
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Develops and maintains products and production systems. Improves production. Develops and maintains products and production systems. Increases the quality of
everything you produce. Also increases the amount you produce (not as much
as Operations, however)
</span> </span>
</h2> </h2>
<button className={assignButtonClass} onClick={engineerAssignButtonOnClick}>+</button> <button className={assignButtonClass} onClick={engineerAssignButtonOnClick}>+</button>
@ -332,7 +360,7 @@ export class IndustryOffice extends BaseReactComponent {
<h2 className={"tooltip"} style={positionHeaderStyle}> <h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Business} ({this.state.numBusiness}) {EmployeePositions.Business} ({this.state.numBusiness})
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Handles sales and finances. Improves sales. Handles sales and finances. Improves the amount of Materials and Products you can sell.
</span> </span>
</h2> </h2>
<button className={assignButtonClass} onClick={businessAssignButtonOnClick}>+</button> <button className={assignButtonClass} onClick={businessAssignButtonOnClick}>+</button>
@ -342,7 +370,8 @@ export class IndustryOffice extends BaseReactComponent {
<h2 className={"tooltip"} style={positionHeaderStyle}> <h2 className={"tooltip"} style={positionHeaderStyle}>
{EmployeePositions.Management} ({this.state.numManagement}) {EmployeePositions.Management} ({this.state.numManagement})
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Leads and oversees employees and office operations. Improves production. Leads and oversees employees and office operations. Improves the effectiveness of
Engineer and Operations employees
</span> </span>
</h2> </h2>
<button className={assignButtonClass} onClick={managementAssignButtonOnClick}>+</button> <button className={assignButtonClass} onClick={managementAssignButtonOnClick}>+</button>
@ -398,27 +427,36 @@ export class IndustryOffice extends BaseReactComponent {
for (let i = 0; i < office.employees.length; ++i) { for (let i = 0; i < office.employees.length; ++i) {
if (name === office.employees[i].name) { if (name === office.employees[i].name) {
this.state.employee = office.employees[i]; this.state.employee = office.employees[i];
break;
} }
} }
corp.rerender();
} }
// Employee Positions Selector // Employee Positions Selector
const emp = this.state.employee;
let employeePositionSelectorInitialValue = null;
const employeePositions = []; const employeePositions = [];
const positionNames = Object.values(EmployeePositions); const positionNames = Object.values(EmployeePositions);
for (let i = 0; i < positionNames.length; ++i) { for (let i = 0; i < positionNames.length; ++i) {
employeePositions.push(<option key={positionNames[i]}>{positionNames[i]}</option>); employeePositions.push(<option key={positionNames[i]} value={positionNames[i]}>{positionNames[i]}</option>);
if (emp != null && emp.pos === positionNames[i]) {
employeePositionSelectorInitialValue = positionNames[i];
}
} }
const employeePositionSelectorOnChange = (e) => { const employeePositionSelectorOnChange = (e) => {
const pos = getSelectText(e.target); const pos = getSelectText(e.target);
this.state.employee.pos = pos; this.state.employee.pos = pos;
this.resetEmployeeCount();
corp.rerender();
} }
// Numeraljs formatter // Numeraljs formatter
const nf = "0.000"; const nf = "0.000";
// Employee stats (after applying multipliers) // Employee stats (after applying multipliers)
const emp = this.state.employee;
const effCre = emp ? emp.cre * corp.getEmployeeCreMultiplier() * division.getEmployeeCreMultiplier() : 0; const effCre = emp ? emp.cre * corp.getEmployeeCreMultiplier() * division.getEmployeeCreMultiplier() : 0;
const effCha = emp ? emp.cha * corp.getEmployeeChaMultiplier() * division.getEmployeeChaMultiplier() : 0; const effCha = emp ? emp.cha * corp.getEmployeeChaMultiplier() * division.getEmployeeChaMultiplier() : 0;
const effInt = emp ? emp.int * corp.getEmployeeIntMultiplier() * division.getEmployeeIntMultiplier() : 0; const effInt = emp ? emp.int * corp.getEmployeeIntMultiplier() * division.getEmployeeIntMultiplier() : 0;
@ -436,6 +474,9 @@ export class IndustryOffice extends BaseReactComponent {
</button> </button>
<div style={employeeInfoDivStyle}> <div style={employeeInfoDivStyle}>
<select onChange={employeeSelectorOnChange}>
{employees}
</select>
{ {
this.state.employee != null && this.state.employee != null &&
<p> <p>
@ -462,15 +503,11 @@ export class IndustryOffice extends BaseReactComponent {
} }
{ {
this.state.employee != null && this.state.employee != null &&
<select onChange={employeePositionSelectorOnChange}> <select onChange={employeePositionSelectorOnChange} value={employeePositionSelectorInitialValue}>
{employeePositions} {employeePositions}
</select> </select>
} }
</div> </div>
<select onChange={employeeSelectorOnChange}>
{employees}
</select>
</div> </div>
) )
} }
@ -495,7 +532,6 @@ export class IndustryOffice extends BaseReactComponent {
} }
} }
const hireEmployeeButtonOnClick = () => { const hireEmployeeButtonOnClick = () => {
office.findEmployees({ corporation: corp, industry: division }); office.findEmployees({ corporation: corp, industry: division });
} }

@ -8,6 +8,7 @@ import { Industries } from "../IndustryData";
import { IndustryUpgrades } from "../IndustryUpgrades"; 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";
export class IndustryOverview extends BaseReactComponent { export class IndustryOverview extends BaseReactComponent {
renderMakeProductButton() { renderMakeProductButton() {
@ -109,6 +110,16 @@ export class IndustryOverview extends BaseReactComponent {
const profitStr = `Profit: ${numeralWrapper.formatMoney(profit)} / s`; const profitStr = `Profit: ${numeralWrapper.formatMoney(profit)} / s`;
const productionMultHelpTipOnClick = () => { const productionMultHelpTipOnClick = () => {
// Wrapper for createProgressBarText()
// Converts the industry's "effectiveness factors"
// into a graphic (string) depicting how high that effectiveness is
function convertEffectFacToGraphic(fac) {
return createProgressBarText({
progress: fac,
totalTicks: 20,
});
}
dialogBoxCreate("Owning Hardware, Robots, AI Cores, and Real Estate " + dialogBoxCreate("Owning Hardware, Robots, AI Cores, and Real Estate " +
"can boost your Industry's production. The effect these " + "can boost your Industry's production. The effect these " +
"materials have on your production varies between Industries. " + "materials have on your production varies between Industries. " +
@ -118,7 +129,13 @@ export class IndustryOverview extends BaseReactComponent {
"the individual production multiplier of each of its office locations. " + "the individual production multiplier of each of its office locations. " +
"This production multiplier is applied to each office. Therefore, it is " + "This production multiplier is applied to each office. Therefore, it is " +
"beneficial to expand into new cities as this can greatly increase the " + "beneficial to expand into new cities as this can greatly increase the " +
"production multiplier of your entire Division."); "production multiplier of your entire Division.<br><br>" +
"Below are approximations for how effective each material is at boosting " +
"this industry's production multiplier (Bigger bars = more effective):<br><br>" +
`Hardware:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.hwFac)}<br>` +
`Robots:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.robFac)}<br>` +
`AI Cores:&nbsp;&nbsp;&nbsp; ${convertEffectFacToGraphic(division.aiFac)}<br>` +
`Real Estate: ${convertEffectFacToGraphic(division.reFac)}`);
} }
return ( return (
@ -129,15 +146,15 @@ export class IndustryOverview extends BaseReactComponent {
{popularity} <br /> {popularity} <br />
{ {
(advertisingInfo !== false) && (advertisingInfo !== false) &&
<p className={"tooltip"}>Advertising Multiplier: {numeralWrapper.format(totalAdvertisingFac, "0.000")} <p className={"tooltip"}>Advertising Multiplier: x{numeralWrapper.format(totalAdvertisingFac, "0.000")}
<span className={"tooltiptext cmpy-mgmt-advertising-info"}> <span className={"tooltiptext cmpy-mgmt-advertising-info"}>
Total multiplier for this industrys sales due to its awareness and popularity Total multiplier for this industrys sales due to its awareness and popularity
<br /> <br />
Awareness Bonus: x{formatNumber(Math.pow(awarenessFac, 0.85), 3)} Awareness Bonus: x{numeralWrapper.format(Math.pow(awarenessFac, 0.85), "0.000")}
<br /> <br />
Popularity Bonus: x{formatNumber(Math.pow(popularityFac, 0.85), 3)} Popularity Bonus: x{numeralWrapper.format(Math.pow(popularityFac, 0.85), "0.000")}
<br /> <br />
Ratio Multiplier: x{formatNumber(Math.pow(ratioFac, 0.85), 3)} Ratio Multiplier: x{numeralWrapper.format(Math.pow(ratioFac, 0.85), "0.000")}
</span> </span>
</p> </p>
} }
@ -157,7 +174,7 @@ export class IndustryOverview extends BaseReactComponent {
<div className={"help-tip"} onClick={productionMultHelpTipOnClick}>?</div> <div className={"help-tip"} onClick={productionMultHelpTipOnClick}>?</div>
<br /> <br /> <br /> <br />
<p className={"tooltip"}> <p className={"tooltip"}>
Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000")} Scientific Research: {numeralWrapper.format(division.sciResearch.qty, "0.000a")}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Scientific Research increases the quality of the materials and Scientific Research increases the quality of the materials and
products that you produce. products that you produce.
@ -252,7 +269,7 @@ export class IndustryOverview extends BaseReactComponent {
{ {
division.makesProducts && division.makesProducts &&
{makeProductButton} makeProductButton
} }
</div> </div>
) )

@ -1,38 +1,50 @@
// React Component for displaying an Industry's warehouse information // React Component for displaying an Industry's warehouse information
// (right-side panel in the Industry UI) // (right-side panel in the Industry UI)
import React from "react"; import React from "react";
import { BaseReactComponent } from "./BaseReactComponent"; import { BaseReactComponent } from "./BaseReactComponent";
import { Material } from "../Material"; import { Material } from "../Material";
import { Product } from "../Product"; import { Product } from "../Product";
import { Warehouse, import { Warehouse,
WarehouseInitialCost, WarehouseInitialCost,
WarehouseUpgradeBaseCost } from "../Corporation"; WarehouseUpgradeBaseCost,
ProductProductionCostRatio } from "../Corporation";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { isString } from "../../../utils/helpers/isString"; import { isString } from "../../../utils/helpers/isString";
// Creates the UI for a single Product type // Creates the UI for a single Product type
function ProductComponent(props) { function ProductComponent(props) {
const corp = props.corp; const corp = props.corp;
const division = props.division; const division = props.division;
const warehouse = props.warehouse; const warehouse = props.warehouse;
const city = props.city;
const product = props.product; const product = props.product;
const eventHandler = props.eventHandler; const eventHandler = props.eventHandler;
const nf = "0.000"; // Numeraljs formatter // Numeraljs formatters
const nf = "0.000";
const nfB = "0.000a"; // For numbers that might be big
const hasUpgradeDashboard = division.hasResearch("uPgrade: Dashboard"); const hasUpgradeDashboard = division.hasResearch("uPgrade: Dashboard");
// Total product gain = production - sale // Total product gain = production - sale
const totalGain = totalGain = product.data[city][1] - product.data[city][2]; const totalGain = product.data[city][1] - product.data[city][2];
// Sell button // Sell button
const sellButtonText = product.sllman[city][1] === -1 let sellButtonText;
? "Sell (" + numeralWrapper.format(product.data[city][2], nf) + "/MAX)" if (product.sllman[city][0]) {
: "Sell (" + numeralWrapper.format(product.data[city][2], nf) + "/" + numeralWrapper.format(product.sllman[city][1], nf) + ")"; if (isString(product.sllman[city][1])) {
sellButtonText = `Sell (${numeralWrapper.format(product.data[city][2], nfB)}/${product.sllman[city][1]})`;
} else {
sellButtonText = `Sell (${numeralWrapper.format(product.data[city][2], nfB)}/${numeralWrapper.format(product.sllman[city][1], nfB)})`;
}
} else {
sellButtonText = "Sell (0.000/0.000)";
}
if (product.sCost) { if (product.sCost) {
if (isString(product.sCost)) { if (isString(product.sCost)) {
sellButtonText += (" @ " + product.sCost); sellButtonText += (" @ " + product.sCost);
@ -40,14 +52,14 @@ function ProductComponent(props) {
sellButtonText += (" @ " + numeralWrapper.format(product.sCost, "$0.000a")); sellButtonText += (" @ " + numeralWrapper.format(product.sCost, "$0.000a"));
} }
} }
const sellButtonOnClick = eventHandler.createSellProductPopup.bind(eventHandler, product); const sellButtonOnClick = eventHandler.createSellProductPopup.bind(eventHandler, product, city);
// Limit Production button // Limit Production button
const limitProductionButtonText = "Limit Production"; const limitProductionButtonText = "Limit Production";
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); const limitProductionButtonOnClick = eventHandler.createLimitProductProdutionPopup.bind(eventHandler, product, city);
// Discontinue Button // Discontinue Button
const discontinueButtonOnClick = eventHandler.createDiscontinueProductPopup.bind(eventHandler, product); const discontinueButtonOnClick = eventHandler.createDiscontinueProductPopup.bind(eventHandler, product);
@ -56,8 +68,8 @@ function ProductComponent(props) {
if (!product.fin) { if (!product.fin) {
if (hasUpgradeDashboard) { if (hasUpgradeDashboard) {
return ( return (
<div className={"cmpy-mgmt-warehouse-product-div"}> <div className={"cmpy-mgmt-warehouse-product-div"} key={product.name}>
<p>Designing {product.name}...</p> <p>Designing {product.name}...</p><br />
<p>{numeralWrapper.format(product.prog, "0.00")}% complete</p> <p>{numeralWrapper.format(product.prog, "0.00")}% complete</p>
<br /> <br />
@ -76,8 +88,8 @@ function ProductComponent(props) {
) )
} else { } else {
return ( return (
<div className={"cmpy-mgmt-warehouse-product-div"}> <div className={"cmpy-mgmt-warehouse-product-div"} key={product.name}>
<p>Designing {product.name}...</p> <p>Designing {product.name}...</p><br />
<p>{numeralWrapper.format(product.prog, "0.00")}% complete</p> <p>{numeralWrapper.format(product.prog, "0.00")}% complete</p>
</div> </div>
); );
@ -87,13 +99,13 @@ function ProductComponent(props) {
return ( return (
<div className={"cmpy-mgmt-warehouse-product-div"} key={props.key}> <div className={"cmpy-mgmt-warehouse-product-div"} key={props.key}>
<p className={"tooltip"}> <p className={"tooltip"}>
{product.name}: {numeralWrapper.format(product.data[city][0], nf)} ({numeralWrapper.format(totalGain, nf)}/s) {product.name}: {numeralWrapper.format(product.data[city][0], nfB)} ({numeralWrapper.format(totalGain, nfB)}/s)
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Prod: {numeralWrapper.format(product.data[city][1], nf)}/s Prod: {numeralWrapper.format(product.data[city][1], nfB)}/s
<br /> <br />
Sell: {numeralWrapper.format(product.data[city][2], nf)} /s Sell: {numeralWrapper.format(product.data[city][2], nfB)} /s
</span> </span>
</p> </p><br />
<p className={"tooltip"}> <p className={"tooltip"}>
Rating: {numeralWrapper.format(product.rat, nf)} Rating: {numeralWrapper.format(product.rat, nf)}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
@ -119,13 +131,13 @@ function ProductComponent(props) {
} }
</span> </span>
</p> </p><br />
<p className={"tooltip"}> <p className={"tooltip"}>
Est. Production Cost: {numeralWrapper.formatMoney(product.pCost / ProductProductionCostRatio)} Est. Production Cost: {numeralWrapper.formatMoney(product.pCost / ProductProductionCostRatio)}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
An estimate of the material cost it takes to create this Product. An estimate of the material cost it takes to create this Product.
</span> </span>
</p> </p><br />
<p className={"tooltip"}> <p className={"tooltip"}>
Est. Market Price: {numeralWrapper.formatMoney(product.pCost + product.rat / product.mku)} Est. Market Price: {numeralWrapper.formatMoney(product.pCost + product.rat / product.mku)}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
@ -161,6 +173,7 @@ function MaterialComponent(props) {
// Numeraljs formatter // Numeraljs formatter
const nf = "0.000"; const nf = "0.000";
const nfB = "0.000a"; // For numbers that might be biger
// Total gain or loss of this material (per second) // Total gain or loss of this material (per second)
const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp; const totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
@ -190,8 +203,12 @@ function MaterialComponent(props) {
// Sell material button // Sell material button
let sellButtonText; let sellButtonText;
if (mat.sllman[0]) { if (mat.sllman[0]) {
sellButtonText = (mat.sllman[1] === -1 ? "Sell (" + numeralWrapper.format(mat.sll, nf) + "/MAX)" : if (isString(mat.sllman[1])) {
"Sell (" + numeralWrapper.format(mat.sll, nf) + "/" + numeralWrapper.format(mat.sllman[1], nf) + ")"); sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nf)}/${mat.sllman[1]})`
} else {
sellButtonText = `Sell (${numeralWrapper.format(mat.sll, nf)}/${numeralWrapper.format(mat.sllman[1], nf)})`;
}
if (mat.sCost) { if (mat.sCost) {
if (mat.marketTa1) { if (mat.marketTa1) {
sellButtonText += " @ " + numeralWrapper.formatMoney(mat.bCost + markupLimit); sellButtonText += " @ " + numeralWrapper.formatMoney(mat.bCost + markupLimit);
@ -214,13 +231,13 @@ function MaterialComponent(props) {
<div className={"cmpy-mgmt-warehouse-material-div"} key={props.key}> <div className={"cmpy-mgmt-warehouse-material-div"} key={props.key}>
<div style={{display: "inline-block"}}> <div style={{display: "inline-block"}}>
<p className={"tooltip"}> <p className={"tooltip"}>
{mat.name}: {numeralWrapper.format(mat.qty, nf)} ({numeralWrapper.format(totalGain, nf)}/s) {mat.name}: {numeralWrapper.format(mat.qty, nfB)} ({numeralWrapper.format(totalGain, nfB)}/s)
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
Buy: {numeralWrapper.format(mat.buy, nf)} <br /> Buy: {numeralWrapper.format(mat.buy, nfB)} <br />
Prod: {numeralWrapper.format(mat.prd, nf)} <br /> Prod: {numeralWrapper.format(mat.prd, nfB)} <br />
Sell: {numeralWrapper.format(mat.sll, nf)} <br /> Sell: {numeralWrapper.format(mat.sll, nfB)} <br />
Export: {numeralWrapper.format(mat.totalExp, nf)} <br /> Export: {numeralWrapper.format(mat.totalExp, nfB)} <br />
Import: {numeralWrapper.format(mat.imp, nf)} Import: {numeralWrapper.format(mat.imp, nfB)}
{ {
corp.unlockUpgrades[2] === 1 && <br /> corp.unlockUpgrades[2] === 1 && <br />
} }
@ -244,7 +261,7 @@ function MaterialComponent(props) {
</span> </span>
</p> <br /> </p> <br />
<p className={"tooltip"}> <p className={"tooltip"}>
Quality: {numeralWrapper.format(mat.qlt, "0.00")} Quality: {numeralWrapper.format(mat.qlt, "0.00a")}
<span className={"tooltiptext"}> <span className={"tooltiptext"}>
The quality of your material. Higher quality will lead to more sales The quality of your material. Higher quality will lead to more sales
</span> </span>
@ -370,7 +387,8 @@ export class IndustryWarehouse extends BaseReactComponent {
// Smart Supply Checkbox // Smart Supply Checkbox
const smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox"; const smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
const smartSupplyOnChange = (e) => { const smartSupplyOnChange = (e) => {
warehouse.smartSupplyEnabled = e.target.value; warehouse.smartSupplyEnabled = e.target.checked;
corp.rerender();
} }
// Materials that affect Production multiplier // Materials that affect Production multiplier
@ -409,14 +427,15 @@ export class IndustryWarehouse extends BaseReactComponent {
if (division.makesProducts && Object.keys(division.products).length > 0) { if (division.makesProducts && Object.keys(division.products).length > 0) {
for (const productName in division.products) { for (const productName in division.products) {
if (division.products[productName] instanceof Product) { if (division.products[productName] instanceof Product) {
products.push({ products.push(ProductComponent({
city: this.props.currentCity,
corp: corp, corp: corp,
division: division, division: division,
eventHandler: this.eventHandler(), eventHandler: this.eventHandler(),
key: productName, key: productName,
product: division.products[productName], product: division.products[productName],
warehouse: warehouse, warehouse: warehouse,
}) }));
} }
} }
} }
@ -425,9 +444,7 @@ export class IndustryWarehouse extends BaseReactComponent {
<div className={"cmpy-mgmt-warehouse-panel"}> <div className={"cmpy-mgmt-warehouse-panel"}>
<p className={"tooltip"} style={sizeUsageStyle}> <p className={"tooltip"} style={sizeUsageStyle}>
Storage: {numeralWrapper.format(warehouse.sizeUsed, "0.000")} / {numeralWrapper.format(warehouse.size, "0.000")} Storage: {numeralWrapper.format(warehouse.sizeUsed, "0.000")} / {numeralWrapper.format(warehouse.size, "0.000")}
<span className={"tooltiptext"}> <span className={"tooltiptext"} dangerouslySetInnerHTML={{__html: warehouse.breakdown}}></span>
{warehouse.breakdown}
</span>
</p> </p>
<button className={upgradeWarehouseClass} onClick={upgradeWarehouseOnClick}> <button className={upgradeWarehouseClass} onClick={upgradeWarehouseOnClick}>
@ -454,7 +471,7 @@ export class IndustryWarehouse extends BaseReactComponent {
id={smartSupplyCheckboxId} id={smartSupplyCheckboxId}
onChange={smartSupplyOnChange} onChange={smartSupplyOnChange}
style={{margin: "3px"}} style={{margin: "3px"}}
value={warehouse.smartSupplyEnabled} checked={warehouse.smartSupplyEnabled}
/> />
</div> </div>
} }
@ -481,9 +498,11 @@ export class IndustryWarehouse extends BaseReactComponent {
return this.renderWarehouseUI(); return this.renderWarehouseUI();
} else { } else {
return ( return (
<button className={"std-button"} onClick={newWarehouseOnClick}> <div className={"cmpy-mgmt-warehouse-panel"}>
Purchase Warehouse ({numeralWrapper.formatMoney(WarehouseInitialCost)}) <button className={"std-button"} onClick={newWarehouseOnClick}>
</button> Purchase Warehouse ({numeralWrapper.formatMoney(WarehouseInitialCost)})
</button>
</div>
) )
} }
} }

@ -23,6 +23,15 @@ export class MainPanel extends BaseReactComponent {
} }
} }
// We can pass this setter to child components
changeCityState(newCity) {
if (Object.values(Cities).includes(newCity)) {
this.state.city = newCity;
} else {
console.error(`Tried to change MainPanel's city state to an invalid city: ${newCity}`);
}
}
// Determines what UI content to render based on routing // Determines what UI content to render based on routing
renderContent() { renderContent() {
if (this.routing().isOnOverviewPage()) { if (this.routing().isOnOverviewPage()) {
@ -68,11 +77,13 @@ export class MainPanel extends BaseReactComponent {
} }
} }
} }
const cityTabs = ( const cityTabs = (
<CityTabs <CityTabs
{...this.props} {...this.props}
city={this.state.city} city={this.state.city}
onClicks={onClicks} onClicks={onClicks}
cityStateSetter={this.changeCityState.bind(this)}
/> />
) )

@ -64,7 +64,7 @@ export class Overview extends BaseReactComponent {
dividendStr + dividendStr +
"Publicly Traded: " + (this.corp().public ? "Yes" : "No") + "<br>" + "Publicly Traded: " + (this.corp().public ? "Yes" : "No") + "<br>" +
"Owned Stock Shares: " + numeralWrapper.format(this.corp().numShares, '0.000a') + "<br>" + "Owned Stock Shares: " + numeralWrapper.format(this.corp().numShares, '0.000a') + "<br>" +
"Stock Price: " + (this.corp().public ? "$" + numeralWrapper.formatMoney(this.corp().sharePrice) : "N/A") + "<br>" + "Stock Price: " + (this.corp().public ? numeralWrapper.formatMoney(this.corp().sharePrice) : "N/A") + "<br>" +
"<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(this.corp().totalShares, "0.000a") + "<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(this.corp().totalShares, "0.000a") +
"<span class='tooltiptext'>" + "<span class='tooltiptext'>" +
`Outstanding Shares: ${numeralWrapper.format(this.corp().issuedShares, "0.000a")}<br>` + `Outstanding Shares: ${numeralWrapper.format(this.corp().issuedShares, "0.000a")}<br>` +

@ -1,3 +1,5 @@
import { Script } from "./Script";
import { calculateRamUsage } from "./RamCalculations"; import { calculateRamUsage } from "./RamCalculations";
import { isScriptFilename } from "./ScriptHelpersTS"; import { isScriptFilename } from "./ScriptHelpersTS";
@ -269,7 +271,7 @@ function saveAndCloseScriptEditor() {
} }
//If the current script does NOT exist, create a new one //If the current script does NOT exist, create a new one
var script = new Script(); const script = new Script();
script.saveScript(getCurrentEditor().getCode(), Player); script.saveScript(getCurrentEditor().getCode(), Player);
s.scripts.push(script); s.scripts.push(script);
} else if (filename.endsWith(".txt")) { } else if (filename.endsWith(".txt")) {

@ -0,0 +1,45 @@
/**
* This is a component that implements a mathematical formula used commonly throughout the
* game. This formula is (typically) used to calculate the effect that various statistics
* have on a game mechanic. It looks something like:
*
* (stat ^ exponential factor) + (stat / linear factor)
*
* where the exponential factor is a number between 0 and 1 and the linear factor
* is typically a relatively larger number.
*
* This formula ensures that the effects of the statistic that is being processed
* has diminishing returns, but never loses its effectiveness as you continue
* to raise it.
*
* There are two implementations of this component. One is simply a function that
* can be called with the stat and the exponential/linear factors. The other is a
* class where the exponential and linear factors are defined upon construction.
*/
export function calculateEffectWithFactors(n: number, expFac: number, linearFac: number): number {
if (expFac <= 0 || expFac >= 1) {
console.warn(`Exponential factor is ${expFac}. This is not an intended value for it`);
}
if (linearFac < 1) {
console.warn(`Linear factor is ${linearFac}. This is not an intended value for it`);
}
return (Math.pow(n, expFac)) + (n / linearFac);
}
export class EffectWithFactors {
// Exponential factor
private expFac: number;
// Linear Factor
private linearFac: number;
constructor(expFac: number, linearFac: number) {
this.expFac = expFac;
this.linearFac = linearFac;
}
calculate(n: number): number {
return calculateEffectWithFactors(n, this.expFac, this.linearFac);
}
}

@ -6,6 +6,7 @@ interface IError {
} }
export function exceptionAlert(e: IError): void { export function exceptionAlert(e: IError): void {
console.error(e);
dialogBoxCreate("Caught an exception: " + e + "<br><br>" + dialogBoxCreate("Caught an exception: " + e + "<br><br>" +
"Filename: " + (e.fileName || "UNKNOWN FILE NAME") + "<br><br>" + "Filename: " + (e.fileName || "UNKNOWN FILE NAME") + "<br><br>" +
"Line Number: " + (e.lineNumber || "UNKNOWN LINE NUMBER") + "<br><br>" + "Line Number: " + (e.lineNumber || "UNKNOWN LINE NUMBER") + "<br><br>" +