mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-11 10:13:52 +01:00
4921 lines
214 KiB
JavaScript
4921 lines
214 KiB
JavaScript
import {BitNodeMultipliers} from "./BitNode.js";
|
|
import {Engine} from "./engine.js";
|
|
import {Factions} from "./Faction.js";
|
|
import {showLiterature} from "./Literature.js";
|
|
import {Locations} from "./Location.js";
|
|
import {Player} from "./Player.js";
|
|
|
|
import Decimal from '../utils/decimal.js';
|
|
import {dialogBoxCreate} from "../utils/DialogBox.js";
|
|
import {getRandomInt, removeElementById,
|
|
createElement, createAccordionElement,
|
|
removeChildrenFromElement, createPopup,
|
|
clearSelector} from "../utils/HelperFunctions.js";
|
|
import {Reviver, Generic_toJSON,
|
|
Generic_fromJSON} from "../utils/JSONReviver.js";
|
|
import numeral from "../utils/numeral.min.js";
|
|
import {formatNumber, isString, generateRandomString} from "../utils/StringHelperFunctions.js";
|
|
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
|
|
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
|
|
yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton,
|
|
yesNoTxtInpBoxGetInput, yesNoBoxClose,
|
|
yesNoTxtInpBoxClose, yesNoBoxOpen} from "../utils/YesNoBox.js";
|
|
|
|
/* State */
|
|
var companyStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
|
function CorporationState() {
|
|
this.state = 0;
|
|
}
|
|
|
|
CorporationState.prototype.nextState = function() {
|
|
if (this.state < 0 || this.state >= companyStates.length) {
|
|
this.state = 0;
|
|
}
|
|
|
|
++this.state;
|
|
if (this.state >= companyStates.length) {
|
|
this.state = 0;
|
|
}
|
|
}
|
|
|
|
CorporationState.prototype.getState = function() {
|
|
return companyStates[this.state];
|
|
}
|
|
|
|
CorporationState.prototype.toJSON = function() {
|
|
return Generic_toJSON("CorporationState", this);
|
|
}
|
|
|
|
CorporationState.fromJSON = function(value) {
|
|
return Generic_fromJSON(CorporationState, value.data);
|
|
}
|
|
|
|
Reviver.constructors.CorporationState = CorporationState;
|
|
|
|
/* Constants */
|
|
var TOTALSHARES = 1e9; //Total number of shares you have at your company
|
|
var CyclesPerMarketCycle = 75;
|
|
var CyclesPerIndustryStateCycle = CyclesPerMarketCycle / companyStates.length;
|
|
var SecsPerMarketCycle = CyclesPerMarketCycle / 5;
|
|
var Cities = ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"];
|
|
var WarehouseInitialCost = 5e9; //Initial purchase cost of warehouse
|
|
var WarehouseInitialSize = 100;
|
|
var WarehouseUpgradeBaseCost = 1e9;
|
|
|
|
var OfficeInitialCost = 4e9;
|
|
var OfficeInitialSize = 3;
|
|
var OfficeUpgradeBaseCost = 1e9;
|
|
|
|
var BribeThreshold = 100e12; //Money needed to be able to bribe for faction rep
|
|
var BribeToRepRatio = 1e9; //Bribe Value divided by this = rep gain
|
|
|
|
var ProductProductionCostRatio = 5; //Ratio of material cost of a product to its production cost
|
|
|
|
function Material(params={}) {
|
|
this.name = params.name ? params.name : "";
|
|
this.qty = 0; //Quantity
|
|
this.qlt = 0; //Quality, unbounded
|
|
this.dmd = 0; //Demand, 0-100?
|
|
this.dmdR = 0; //Range of possible demand
|
|
this.cmp = 0; //Competition, 0-100
|
|
this.cmpR = 0; //Range of possible competition
|
|
this.mv = 0; //Maximum Volatility of stats
|
|
|
|
//Markup. Determines how high of a price you can charge on the material
|
|
//compared to the market price (bCost) based on quality
|
|
//Quality is divided by this to determine markup limits
|
|
//e.g if mku is 10 and quality is 100 then you can mark up prices by 100/10 = 10
|
|
//without consequences
|
|
this.mku = 0;
|
|
|
|
this.buy = 0; //How much of this material is being bought per second
|
|
this.sll = 0; //How much of this material is being sold per second
|
|
this.prd = 0; //How much of this material is being produced per second
|
|
this.exp = []; //Exports of this material to another warehouse/industry
|
|
this.totalExp = 0; //Total export amount for last cycle
|
|
this.imp = 0;
|
|
this.bCost = 0; //$ Cost/sec to buy material
|
|
this.sCost = 0; //$ Cost/sec to sell material
|
|
|
|
//[Whether production/sale is limited, limit amount]
|
|
this.prdman = [false, 0]; //Production for this material is manually limited
|
|
this.sllman = [false, 0]; //Sale of this material is manually limited
|
|
this.init();
|
|
}
|
|
|
|
Material.prototype.init = function(mats={}) {
|
|
switch(this.name) {
|
|
case "Water":
|
|
this.dmd = 75; this.dmdR = [65, 85];
|
|
this.cmp = 50; this.cmpR = [40, 60];
|
|
this.bCost = 1000; this.mv = 0.2;
|
|
this.mku = 6;
|
|
break;
|
|
case "Energy":
|
|
this.dmd = 90; this.dmdR = [80, 100];
|
|
this.cmp = 80; this.cmpR = [65, 95];
|
|
this.bCost = 1500; this.mv = 0.2;
|
|
this.mku = 6;
|
|
break;
|
|
case "Food":
|
|
this.dmd = 80; this.dmdR = [70, 90];
|
|
this.cmp = 60; this.cmpR = [35, 85];
|
|
this.bCost = 5000; this.mv = 1;
|
|
this.mku = 3;
|
|
break;
|
|
case "Plants":
|
|
this.dmd = 70; this.dmdR = [20, 90];
|
|
this.cmp = 50; this.cmpR = [30, 70];
|
|
this.bCost = 3000; this.mv = 0.6;
|
|
this.mku = 3.75;
|
|
break;
|
|
case "Metal":
|
|
this.dmd = 80; this.dmdR = [75, 85];
|
|
this.cmp = 70; this.cmpR = [60, 80];
|
|
this.bCost = 2650; this.mv = 1;
|
|
this.mku = 6;
|
|
break;
|
|
case "Hardware":
|
|
this.dmd = 85; this.dmdR = [80, 90];
|
|
this.cmp = 80; this.cmpR = [65, 95];
|
|
this.bCost = 4000; this.mv = 0.5; //Less mv bc its processed twice
|
|
this.mku = 1;
|
|
break;
|
|
case "Chemicals":
|
|
this.dmd = 55; this.dmdR = [40, 70];
|
|
this.cmp = 60; this.cmpR = [40, 80];
|
|
this.bCost = 6750; this.mv = 1.2;
|
|
this.mku = 2;
|
|
break;
|
|
case "Real Estate":
|
|
this.dmd = 50; this.dmdR = [5, 100];
|
|
this.cmp = 50; this.cmpR = [25, 75];
|
|
this.bCost = 16e3; this.mv = 1.5; //Less mv bc its processed twice
|
|
this.mku = 1.5;
|
|
break;
|
|
case "Drugs":
|
|
this.dmd = 60; this.dmdR = [45, 75];
|
|
this.cmp = 70; this.cmpR = [40, 100];
|
|
this.bCost = 8e3; this.mv = 1.6;
|
|
this.mku = 1;
|
|
break;
|
|
case "Robots":
|
|
this.dmd = 90; this.dmdR = [80, 100];
|
|
this.cmp = 90; this.cmpR = [80, 100];
|
|
this.bCost = 20e3; this.mv = 0.5; //Less mv bc its processed twice
|
|
this.mku = 1;
|
|
break;
|
|
case "AI Cores":
|
|
this.dmd = 90; this.dmdR = [80, 100];
|
|
this.cmp = 90; this.cmpR = [80, 100];
|
|
this.bCost = 27e3; this.mv = 0.8; //Less mv bc its processed twice
|
|
this.mku = 0.5;
|
|
break;
|
|
case "Scientific Research":
|
|
break;
|
|
default:
|
|
console.log("Invalid material type in init(): " + this.name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Process change in demand, competition, and buy cost of this material
|
|
Material.prototype.processMarket = function() {
|
|
//This 1st random check determines whether competition increases or decreases
|
|
//More competition = lower market price
|
|
var v = (Math.random() * this.mv) / 100;
|
|
var pv = (Math.random() * this.mv) / 300;
|
|
if (Math.random() < 0.42) {
|
|
this.cmp *= (1+v);
|
|
if (this.cmp > this.cmpR[1]) {this.cmp = this.cmpR[1]};
|
|
this.bCost *= (1-pv);
|
|
} else {
|
|
this.cmp *= (1-v);
|
|
if (this.cmp < this.cmpR[0]) {this.cmp = this.cmpR[0];}
|
|
this.bCost *= (1+pv);
|
|
}
|
|
|
|
//This 2nd random check determines whether demand increases or decreases
|
|
//More demand = higher market price
|
|
v = (Math.random() * this.mv) / 100;
|
|
pv = (Math.random() * this.mv) / 300;
|
|
if (Math.random() < 0.45) {
|
|
this.dmd *= (1+v);
|
|
if (this.dmd > this.dmdR[1]) {this.dmd = this.dmdR[1];}
|
|
this.bCost *= (1+pv);
|
|
} else {
|
|
this.dmd *= (1-v);
|
|
if (this.dmd < this.dmdR[0]) {this.dmd = this.dmdR[0];}
|
|
this.bCost *= (1-pv);
|
|
}
|
|
}
|
|
|
|
Material.prototype.toJSON = function() {
|
|
return Generic_toJSON("Material", this);
|
|
}
|
|
|
|
Material.fromJSON = function(value) {
|
|
return Generic_fromJSON(Material, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Material = Material;
|
|
|
|
//Map of material (by name) to their sizes (how much space it takes in warehouse)
|
|
let MaterialSizes = {
|
|
Water: 0.05,
|
|
Energy: 0.01,
|
|
Food: 0.03,
|
|
Plants: 0.05,
|
|
Metal: 0.1,
|
|
Hardware: 0.06,
|
|
Chemicals: 0.05,
|
|
Drugs: 0.02,
|
|
Robots: 0.5,
|
|
"AICores": 0.1
|
|
}
|
|
|
|
function Product(params={}) {
|
|
this.name = params.name ? params.name : 0;
|
|
this.dmd = params.demand ? params.demand : 0;
|
|
this.cmp = params.competition ? params.competition : 0;
|
|
this.mku = params.markup ? params.markup : 0;
|
|
this.pCost = 0; //An estimate of how much money it costs to make this
|
|
this.sCost = 0; //How much this is selling for
|
|
|
|
//Variables for creation of product
|
|
this.fin = false; //Finished being created
|
|
this.prog = 0; //0-100% created
|
|
this.createCity = params.createCity ? params.createCity : ""; // City in which the product is being created
|
|
this.designCost = params.designCost ? params.designCost : 0;
|
|
this.advCost = params.advCost ? params.advCost : 0;
|
|
|
|
//Aggregate score for a product's 'rating' based on the other properties below
|
|
//The weighting of the other properties (performance, durability)
|
|
//differs between industries
|
|
this.rat = 0;
|
|
|
|
this.qlt = params.quality ? params.quality : 0;
|
|
this.per = params.performance ? params.performance : 0;
|
|
this.dur = params.durability ? params.durability : 0;
|
|
this.rel = params.reliability ? params.reliability : 0;
|
|
this.aes = params.aesthetics ? params.aesthetics : 0;
|
|
this.fea = params.features ? params.features : 0;
|
|
|
|
//Data refers to the production, sale, and quantity of the products
|
|
//These values are specific to a city
|
|
//The data is [qty, prod, sell]
|
|
this.data = {
|
|
[Locations.Aevum]: [0, 0, 0],
|
|
[Locations.Chongqing]: [0, 0, 0],
|
|
[Locations.Sector12]: [0, 0, 0],
|
|
[Locations.NewTokyo]: [0, 0, 0],
|
|
[Locations.Ishima]: [0, 0, 0],
|
|
[Locations.Volhaven]: [0, 0, 0],
|
|
}
|
|
|
|
//Only applies for location-based products like restaurants/hospitals
|
|
this.loc = params.loc ? params.loc : 0;
|
|
|
|
//How much space it takes in the warehouse. Not applicable for all products
|
|
this.siz = params.size ? params.size : 0;
|
|
|
|
//Material requirements. An object that maps the name of a material to how much it requires
|
|
//to make 1 unit of the product.
|
|
this.reqMats = params.req ? params.req : {};
|
|
|
|
//[Whether production/sale is limited, limit amount]
|
|
this.prdman = {
|
|
[Locations.Aevum]: [false, 0],
|
|
[Locations.Chongqing]: [false, 0],
|
|
[Locations.Sector12]: [false, 0],
|
|
[Locations.NewTokyo]: [false, 0],
|
|
[Locations.Ishima]: [false, 0],
|
|
[Locations.Volhaven]: [false, 0],
|
|
}
|
|
|
|
this.sllman = {
|
|
[Locations.Aevum]: [false, 0],
|
|
[Locations.Chongqing]: [false, 0],
|
|
[Locations.Sector12]: [false, 0],
|
|
[Locations.NewTokyo]: [false, 0],
|
|
[Locations.Ishima]: [false, 0],
|
|
[Locations.Volhaven]: [false, 0],
|
|
}
|
|
}
|
|
|
|
//empWorkMult is a multiplier that increases progress rate based on
|
|
//productivity of employees
|
|
Product.prototype.createProduct = function(marketCycles=1, empWorkMult=1) {
|
|
if (this.fin) {return;}
|
|
this.prog += (marketCycles * .01 * empWorkMult);
|
|
}
|
|
|
|
//'industry' is a reference to the industry that makes the product
|
|
Product.prototype.finishProduct = function(employeeProd, industry) {
|
|
this.fin = true;
|
|
|
|
//Calculate properties
|
|
var progrMult = this.prog / 100;
|
|
|
|
var engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"],
|
|
mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"],
|
|
rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"],
|
|
opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"],
|
|
busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
|
|
var designMult = 1 + (Math.pow(this.designCost, 0.1) / 100);
|
|
console.log("designMult: " + designMult);
|
|
var balanceMult = (1.2 * engrRatio) + (0.9 * mgmtRatio) + (1.3 * rndRatio) +
|
|
(1.5 * opsRatio) + (busRatio);
|
|
var sciMult = 1 + (Math.pow(industry.sciResearch.qty, industry.sciFac) / 800);
|
|
var totalMult = progrMult * balanceMult * designMult * sciMult;
|
|
|
|
this.qlt = totalMult * ((0.10 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.05 * employeeProd[EmployeePositions.Management]) +
|
|
(0.05 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.02 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.02 * employeeProd[EmployeePositions.Business]));
|
|
this.per = totalMult * ((0.15 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.02 * employeeProd[EmployeePositions.Management]) +
|
|
(0.02 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.02 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.02 * employeeProd[EmployeePositions.Business]));
|
|
this.dur = totalMult * ((0.05 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.02 * employeeProd[EmployeePositions.Management]) +
|
|
(0.08 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.05 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.05 * employeeProd[EmployeePositions.Business]));
|
|
this.rel = totalMult * ((0.02 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.08 * employeeProd[EmployeePositions.Management]) +
|
|
(0.02 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.05 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.08 * employeeProd[EmployeePositions.Business]));
|
|
this.aes = totalMult * ((0.00 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.08 * employeeProd[EmployeePositions.Management]) +
|
|
(0.05 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.02 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.10 * employeeProd[EmployeePositions.Business]));
|
|
this.fea = totalMult * ((0.08 * employeeProd[EmployeePositions.Engineer]) +
|
|
(0.05 * employeeProd[EmployeePositions.Management]) +
|
|
(0.02 * employeeProd[EmployeePositions.RandD]) +
|
|
(0.05 * employeeProd[EmployeePositions.Operations]) +
|
|
(0.05 * employeeProd[EmployeePositions.Business]));
|
|
this.calculateRating(industry);
|
|
var advMult = 1 + (Math.pow(this.advCost, 0.1) / 100);
|
|
this.mku = 100 / (advMult * Math.pow((this.qlt + 0.001), 0.65) * (busRatio + mgmtRatio));
|
|
this.dmd = industry.awareness === 0 ? 20 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness)));
|
|
this.cmp = getRandomInt(0, 70);
|
|
|
|
//Calculate the product's required materials
|
|
//For now, just set it to be the same as the requirements to make materials
|
|
for (var matName in industry.reqMats) {
|
|
if (industry.reqMats.hasOwnProperty(matName)) {
|
|
this.reqMats[matName] = industry.reqMats[matName];
|
|
}
|
|
}
|
|
|
|
//Calculate the product's size
|
|
//For now, just set it to be the same size as the requirements to make materials
|
|
this.siz = 0;
|
|
for (var matName in industry.reqMats) {
|
|
this.siz += MaterialSizes[matName] * industry.reqMats[matName];
|
|
}
|
|
|
|
//Delete unneeded variables
|
|
delete this.prog;
|
|
delete this.createCity;
|
|
delete this.designCost;
|
|
delete this.advCost;
|
|
}
|
|
|
|
|
|
Product.prototype.calculateRating = function(industry) {
|
|
var weights = ProductRatingWeights[industry.type];
|
|
if (weights == null) {
|
|
console.log("ERROR: Could not find product rating weights for: " + industry);
|
|
return;
|
|
}
|
|
this.rat = 0;
|
|
this.rat += weights.Quality ? this.qlt * weights.Quality : 0;
|
|
this.rat += weights.Performance ? this.per * weights.Performance : 0;
|
|
this.rat += weights.Durability ? this.dur * weights.Durability : 0;
|
|
this.rat += weights.Reliability ? this.rel * weights.Reliability : 0;
|
|
this.rat += weights.Aesthetics ? this.aes * weights.Aesthetics : 0;
|
|
this.rat += weights.Features ? this.fea * weights.Features : 0;
|
|
}
|
|
|
|
Product.prototype.toJSON = function() {
|
|
return Generic_toJSON("Product", this);
|
|
}
|
|
|
|
Product.fromJSON = function(value) {
|
|
return Generic_fromJSON(Product, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Product = Product;
|
|
|
|
var Industries = {
|
|
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",
|
|
}
|
|
|
|
var IndustryStartingCosts = {
|
|
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,
|
|
}
|
|
|
|
var IndustryDescriptions = {
|
|
Energy: "Engage in the production and distribution of energy.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Energy).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Utilities: "Distributes water and provides wastewater services.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Utilities).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Agriculture: "Cultive crops and breed livestock to produce food.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Agriculture).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: YES",
|
|
Fishing: "Produce food through the breeding and processing of fish and fish products<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Fishing).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Mining: "Extract and process metals from the earth.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Mining).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Food: "Create your own restaurants all around the world.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Food).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: YES",
|
|
Tobacco: "Create and distribute tobacco and tobacco-related products.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Tobacco).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: YES",
|
|
Chemical: "Product industrial chemicals<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Chemical).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Pharmaceutical: "Discover, develop, and create new pharmaceutical drugs.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Pharmaceutical).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Computer: "Develop and manufacture new computer hardware and networking infrastructures.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Computer).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Robotics: "Develop and create robots.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Robotics).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
Software: "Develop computer software and create AI Cores.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Software).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: YES",
|
|
Healthcare: "Create and manage hospitals.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.Healthcare).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
RealEstate: "Develop and manage real estate properties.<br><br>" +
|
|
"Starting cost: " + numeral(IndustryStartingCosts.RealEstate).format("$0.000a") + "<br>" +
|
|
"Recommended starting Industry: NO",
|
|
}
|
|
|
|
var ProductRatingWeights = {
|
|
[Industries.Food]: {
|
|
Quality: 0.7,
|
|
Durability: 0.1,
|
|
Aesthetics: 0.2,
|
|
},
|
|
[Industries.Tobacco]: {
|
|
Quality: 0.4,
|
|
Durability: 0.2,
|
|
Reliability: 0.2,
|
|
Aesthetics: 0.2,
|
|
},
|
|
[Industries.Pharmaceutical]: {
|
|
Quality: 0.2,
|
|
Performance: 0.2,
|
|
Durability: 0.1,
|
|
Reliability: 0.3,
|
|
Features: 0.2,
|
|
},
|
|
[Industries.Computer]: {
|
|
Quality: 0.15,
|
|
Performance: 0.25,
|
|
Durability: 0.25,
|
|
Reliability: 0.2,
|
|
Aesthetics: 0.05,
|
|
Features: 0.1,
|
|
},
|
|
"Computer" : { //Repeat
|
|
Quality: 0.15,
|
|
Performance: 0.25,
|
|
Durability: 0.25,
|
|
Reliability: 0.2,
|
|
Aesthetics: 0.05,
|
|
Features: 0.1,
|
|
},
|
|
[Industries.Robotics]: {
|
|
Quality: 0.1,
|
|
Performance: 0.2,
|
|
Durability: 0.2,
|
|
Reliability: 0.2,
|
|
Aesthetics: 0.1,
|
|
Features: 0.2,
|
|
},
|
|
[Industries.Software]: {
|
|
Quality: 0.2,
|
|
Performance: 0.2,
|
|
Reliability: 0.2,
|
|
Durability: 0.2,
|
|
Features: 0.2,
|
|
},
|
|
[Industries.Healthcare]: {
|
|
Quality: 0.4,
|
|
Performance: 0.1,
|
|
Durability: 0.1,
|
|
Reliability: 0.3,
|
|
Features: 0.1,
|
|
},
|
|
[Industries.RealEstate]: {
|
|
Quality: 0.2,
|
|
Durability: 0.25,
|
|
Reliability: 0.1,
|
|
Aesthetics: 0.35,
|
|
Features: 0.1,
|
|
}
|
|
}
|
|
|
|
//Industry upgrades
|
|
//The structure is:
|
|
// [index in array, base price, price mult, benefit mult (if applicable), name, desc]
|
|
var IndustryUpgrades = {
|
|
"0": [0, 500e3, 1, 1.05,
|
|
"Coffee", "Provide your employees with coffee, increasing their energy by 5%."],
|
|
"1": [1, 1e9, 1.06, 1.03,
|
|
"AdVert.Inc", "Hire AdVert.Inc to advertise your company. Each level of " +
|
|
"this upgrade grants your company a static increase of 3 and 1 to its awareness and " +
|
|
"popularity, respectively. It will then increase your company's awareness by 1%, and its popularity " +
|
|
"by a random percentage between 1% and 3%. These effects are increased by other upgrades " +
|
|
"that increase the power of your advertising."]
|
|
}
|
|
|
|
var empManualAssignmentModeActive = false;
|
|
function Industry(params={}) {
|
|
this.offices = { //Maps locations to offices. 0 if no office at that location
|
|
[Locations.Aevum]: 0,
|
|
[Locations.Chongqing]: 0,
|
|
[Locations.Sector12]: new OfficeSpace({
|
|
loc:Locations.Sector12,
|
|
size:OfficeInitialSize,
|
|
}),
|
|
[Locations.NewTokyo]: 0,
|
|
[Locations.Ishima]: 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.type = params.type ? params.type : 0;
|
|
|
|
this.sciResearch = new Material({name: "Scientific Research"});
|
|
|
|
//A map of the NAME of materials required to create produced materials to
|
|
//how many are needed to produce 1 unit of produced materials
|
|
this.reqMats = {};
|
|
|
|
//An array of the name of materials being produced
|
|
this.prodMats = [];
|
|
|
|
this.products = {};
|
|
this.makesProducts = false;
|
|
|
|
this.awareness = 0;
|
|
this.popularity = 0; //Should always be less than awareness
|
|
this.startingCost = 0;
|
|
|
|
/* The following are factors for how much production/other things are increased by
|
|
different factors. The production increase always has diminishing returns,
|
|
and they are all reprsented by exponentials of < 1 (e.g x ^ 0.5, x ^ 0.8)
|
|
The number for these represent the exponential. A lower number means more
|
|
diminishing returns */
|
|
this.reFac = 0; //Real estate Factor
|
|
this.sciFac = 0; //Scientific Research Factor, affects quality
|
|
this.hwFac = 0; //Hardware factor
|
|
this.robFac = 0; //Robotics Factor
|
|
this.aiFac = 0; //AI Cores factor;
|
|
this.advFac = 0; //Advertising factor, affects sales
|
|
|
|
this.prodMult = 0; //Production multiplier
|
|
|
|
//Financials
|
|
this.lastCycleRevenue = new Decimal(0);
|
|
this.lastCycleExpenses = new Decimal(0);
|
|
this.thisCycleRevenue = new Decimal(0);
|
|
this.thisCycleExpenses = new Decimal(0);
|
|
|
|
//Upgrades
|
|
var numUpgrades = Object.keys(IndustryUpgrades).length;
|
|
this.upgrades = Array(numUpgrades).fill(0);
|
|
|
|
this.state = "START";
|
|
this.newInd = true;
|
|
|
|
this.init();
|
|
}
|
|
|
|
Industry.prototype.init = function() {
|
|
//Set the unique properties of an industry (how much its affected by real estate/scientific research, etc.)
|
|
this.startingCost = IndustryStartingCosts[this.type];
|
|
switch (this.type) {
|
|
case Industries.Energy:
|
|
this.reFac = 0.65;
|
|
this.sciFac = 0.7;
|
|
this.robFac = 0.05;
|
|
this.aiFac = 0.3;
|
|
this.advFac = 0.08;
|
|
this.reqMats = {
|
|
"Hardware": 0.1,
|
|
"Metal": 0.2,
|
|
};
|
|
this.prodMats = ["Energy"];
|
|
break;
|
|
case Industries.Utilities:
|
|
case "Utilities":
|
|
this.reFac = 0.5;
|
|
this.sciFac = 0.6;
|
|
this.robFac = 0.4;
|
|
this.aiFac = 0.4;
|
|
this.advFac = 0.08;
|
|
this.reqMats = {
|
|
"Hardware": 0.1,
|
|
"Metal": 0.1,
|
|
}
|
|
this.prodMats = ["Water"];
|
|
break;
|
|
case Industries.Agriculture:
|
|
this.reFac = 0.75;
|
|
this.sciFac = 0.5;
|
|
this.hwFac = 0.2;
|
|
this.robFac = 0.3;
|
|
this.aiFac = 0.3;
|
|
this.advFac = 0.04;
|
|
this.reqMats = {
|
|
"Water": 0.5,
|
|
"Energy": 0.5,
|
|
}
|
|
this.prodMats = ["Plants", "Food"];
|
|
break;
|
|
case Industries.Fishing:
|
|
this.reFac = 0.15;
|
|
this.sciFac = 0.35;
|
|
this.hwFac = 0.35;
|
|
this.robFac = 0.5;
|
|
this.aiFac = 0.2;
|
|
this.advFac = 0.08;
|
|
this.reqMats = {
|
|
"Energy": 0.5,
|
|
}
|
|
this.prodMats = ["Food"];
|
|
break;
|
|
case Industries.Mining:
|
|
this.reFac = 0.3;
|
|
this.sciFac = 0.26;
|
|
this.hwFac = 0.4;
|
|
this.robFac = 0.45;
|
|
this.aiFac = 0.45;
|
|
this.advFac = 0.06;
|
|
this.reqMats = {
|
|
"Energy": 0.8,
|
|
}
|
|
this.prodMats = ["Metal"];
|
|
break;
|
|
case Industries.Food:
|
|
//reFac is unique for this bc it diminishes greatly per city. Handle this separately in code?
|
|
this.sciFac = 0.12;
|
|
this.hwFac = 0.15;
|
|
this.robFac = 0.3;
|
|
this.aiFac = 0.25;
|
|
this.advFac = 0.25;
|
|
this.reFac = 0.05;
|
|
this.reqMats = {
|
|
"Food": 0.5,
|
|
"Water": 0.5,
|
|
"Energy": 0.2,
|
|
}
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Tobacco:
|
|
this.reFac = 0.15;
|
|
this.sciFac = 0.75;
|
|
this.hwFac = 0.15;
|
|
this.robFac = 0.2;
|
|
this.aiFac = 0.15;
|
|
this.advFac = 0.2;
|
|
this.reqMats = {
|
|
"Plants": 1,
|
|
"Water": 0.2,
|
|
}
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Chemical:
|
|
this.reFac = 0.25;
|
|
this.sciFac = 0.75;
|
|
this.hwFac = 0.2;
|
|
this.robFac = 0.25;
|
|
this.aiFac = 0.2;
|
|
this.advFac = 0.07;
|
|
this.reqMats = {
|
|
"Plants": 1,
|
|
"Energy": 0.5,
|
|
"Water": 0.5,
|
|
}
|
|
this.prodMats = ["Chemicals"];
|
|
break;
|
|
case Industries.Pharmaceutical:
|
|
this.reFac = 0.05;
|
|
this.sciFac = 0.8;
|
|
this.hwFac = 0.15;
|
|
this.robFac = 0.25;
|
|
this.aiFac = 0.2;
|
|
this.advFac = 0.16;
|
|
this.reqMats = {
|
|
"Chemicals": 2,
|
|
"Energy": 1,
|
|
"Water": 0.5,
|
|
}
|
|
this.prodMats = ["Drugs"];
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Computer:
|
|
case "Computer":
|
|
this.reFac = 0.2;
|
|
this.sciFac = 0.62;
|
|
this.robFac = 0.36;
|
|
this.aiFac = 0.19;
|
|
this.advFac = 0.17;
|
|
this.reqMats = {
|
|
"Metal": 2.5,
|
|
"Energy": 1,
|
|
}
|
|
this.prodMats = ["Hardware"];
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Robotics:
|
|
this.reFac = 0.32;
|
|
this.sciFac = 0.65;
|
|
this.aiFac = 0.36;
|
|
this.advFac = 0.18;
|
|
this.hwFac = 0.19;
|
|
this.reqMats = {
|
|
"Hardware": 5,
|
|
"Energy": 3,
|
|
}
|
|
this.prodMats = ["Robots"];
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Software:
|
|
this.sciFac = 0.62;
|
|
this.advFac = 0.16;
|
|
this.hwFac = 0.25;
|
|
this.reFac = 0.1;
|
|
this.aiFac = 0.1;
|
|
this.robFac = 0.05;
|
|
this.reqMats = {
|
|
"Hardware": 0.5,
|
|
"Energy": 1,
|
|
}
|
|
this.prodMats = ["AICores"];
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.Healthcare:
|
|
this.reFac = 0.1;
|
|
this.sciFac = 0.75;
|
|
this.advFac = 0.11;
|
|
this.hwFac = 0.1;
|
|
this.robFac = 0.1;
|
|
this.aiFac = 0.1;
|
|
this.reqMats = {
|
|
"Robots": 10,
|
|
"AICores": 5,
|
|
"Energy": 5,
|
|
"Water": 5,
|
|
}
|
|
this.makesProducts = true;
|
|
break;
|
|
case Industries.RealEstate:
|
|
this.robFac = 0.6;
|
|
this.aiFac = 0.6;
|
|
this.advFac = 0.25;
|
|
this.sciFac = 0.05;
|
|
this.hwFac = 0.05;
|
|
this.reqMats = {
|
|
"Metal": 20,
|
|
"Energy": 10,
|
|
"Water": 10,
|
|
"Hardware": 5
|
|
}
|
|
this.prodMats = ["RealEstate"];
|
|
this.makesProducts = true;
|
|
break;
|
|
default:
|
|
console.log("ERR: Invalid Industry Type passed into Industry.init(): " + this.type);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Industry.prototype.getProductDescriptionText = function() {
|
|
if (!this.makesProducts) {return;}
|
|
switch (this.type) {
|
|
case Industries.Food:
|
|
return "create and manage restaurants";
|
|
break;
|
|
case Industries.Tobacco:
|
|
return "create tobacco and tobacco-related products";
|
|
break;
|
|
case Industries.Pharmaceutical:
|
|
return "develop new pharmaceutical drugs";
|
|
break;
|
|
case Industries.Computer:
|
|
case "Computer":
|
|
return "create new computer hardware and networking infrastructures";
|
|
break;
|
|
case Industries.Robotics:
|
|
return "build specialized robots and robot-related products";
|
|
break;
|
|
case Industries.Software:
|
|
return "develop computer software";
|
|
break;
|
|
case Industries.HealthCare:
|
|
return "build and manage hospitals";
|
|
break;
|
|
case Industries.RealEstate:
|
|
return "develop and manage real estate properties";
|
|
break;
|
|
default:
|
|
console.log("ERROR: Invalid industry type in Industry.getProductDescriptionText");
|
|
return "";
|
|
}
|
|
}
|
|
|
|
//Calculates the values that factor into the production and properties of
|
|
//materials/products (such as quality, etc.)
|
|
Industry.prototype.calculateProductionFactors = function() {
|
|
var multSum = 0;
|
|
for (var i = 0; i < Cities.length; ++i) {
|
|
var city = Cities[i];
|
|
var warehouse = this.warehouses[city];
|
|
if (!(warehouse instanceof Warehouse)) {
|
|
continue;
|
|
}
|
|
|
|
var materials = warehouse.materials,
|
|
office = this.offices[city];
|
|
|
|
var cityMult = Math.pow(0.002 * materials.RealEstate.qty+1, this.reFac) *
|
|
Math.pow(0.002 * materials.Hardware.qty+1, this.hwFac) *
|
|
Math.pow(0.002 * materials.Robots.qty+1, this.robFac) *
|
|
Math.pow(0.002 * materials.AICores.qty+1, this.aiFac);
|
|
multSum += Math.pow(cityMult, 0.73);
|
|
}
|
|
|
|
multSum < 1 ? this.prodMult = 1 : this.prodMult = multSum;
|
|
}
|
|
|
|
Industry.prototype.updateWarehouseSizeUsed = function(warehouse) {
|
|
if (warehouse instanceof Warehouse) {
|
|
//This resets the size back to 0 and then accounts for materials
|
|
warehouse.updateMaterialSizeUsed();
|
|
}
|
|
|
|
for (var prodName in this.products) {
|
|
if (this.products.hasOwnProperty(prodName)) {
|
|
var prod = this.products[prodName];
|
|
warehouse.sizeUsed += (prod.data[warehouse.loc][0] * prod.siz);
|
|
if (prod.data[warehouse.loc][0] > 0) {
|
|
warehouse.breakdown += (prodName + ": " + formatNumber(prod.data[warehouse.loc][0] * prod.siz, 0) + "<br>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Industry.prototype.process = function(marketCycles=1, state, company) {
|
|
this.state = state;
|
|
|
|
//At the start of a cycle, store and reset revenue/expenses
|
|
//Then calculate salaries and processs the markets
|
|
if (state === "START") {
|
|
if (isNaN(this.thisCycleRevenue) || isNaN(this.thisCycleExpenses)) {
|
|
console.log("ERROR: NaN in Corporation's computed revenue/expenses");
|
|
console.log(this.thisCycleRevenue.toString());
|
|
console.log(this.thisCycleExpenses.toString());
|
|
dialogBoxCreate("Something went wrong when compting Corporation's revenue/expenses. This is a bug. Please report to game developer");
|
|
this.thisCycleRevenue = new Decimal(0);
|
|
this.thisCycleExpenses = new Decimal(0);
|
|
}
|
|
this.lastCycleRevenue = this.thisCycleRevenue.dividedBy(marketCycles * SecsPerMarketCycle);
|
|
this.lastCycleExpenses = this.thisCycleExpenses.dividedBy(marketCycles * SecsPerMarketCycle);
|
|
this.thisCycleRevenue = new Decimal(0);
|
|
this.thisCycleExpenses = new Decimal(0);
|
|
|
|
//Once you start making revenue, the player should no longer be
|
|
//considered new, and therefore no longer needs the 'tutorial' UI elements
|
|
if (this.lastCycleRevenue.gt(0)) {this.newInd = false;}
|
|
|
|
//Process offices (and the employees in them)
|
|
var employeeSalary = 0;
|
|
for (var officeLoc in this.offices) {
|
|
if (this.offices.hasOwnProperty(officeLoc) &&
|
|
this.offices[officeLoc] instanceof OfficeSpace) {
|
|
employeeSalary += this.offices[officeLoc].process(marketCycles, {industry:this, corporation:company});
|
|
}
|
|
}
|
|
this.thisCycleExpenses = this.thisCycleExpenses.plus(employeeSalary);
|
|
|
|
//Process change in demand/competition of materials/products
|
|
this.processMaterialMarket(marketCycles);
|
|
this.processProductMarket(marketCycles);
|
|
|
|
//Process loss of popularity
|
|
this.popularity -= (marketCycles * .0001);
|
|
this.popularity = Math.max(0, this.popularity);
|
|
|
|
//Process Dreamsense gains
|
|
var popularityGain = company.getDreamSenseGain(), awarenessGain = popularityGain * 4;
|
|
if (popularityGain > 0) {
|
|
this.popularity += (popularityGain * marketCycles);
|
|
this.awareness += (awarenessGain * marketCycles);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//Process production, purchase, and import/export of materials
|
|
var res = this.processMaterials(marketCycles, company);
|
|
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
|
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
|
|
|
//Process creation, production & sale of products
|
|
res = this.processProducts(marketCycles, company);
|
|
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
|
|
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
|
|
|
|
}
|
|
|
|
//Process change in demand and competition for this industry's materials
|
|
Industry.prototype.processMaterialMarket = function(marketCycles=1) {
|
|
//References to prodMats and reqMats
|
|
var reqMats = this.reqMats, prodMats = this.prodMats;
|
|
|
|
//Only 'process the market' for materials that this industry deals with
|
|
for (var i = 0; i < Cities.length; ++i) {
|
|
//If this industry has a warehouse in this city, process the market
|
|
//for every material this industry requires or produces
|
|
if (this.warehouses[Cities[i]] instanceof Warehouse) {
|
|
var wh = this.warehouses[Cities[i]];
|
|
for (var name in reqMats) {
|
|
if (reqMats.hasOwnProperty(name)) {
|
|
wh.materials[name].processMarket();
|
|
}
|
|
}
|
|
|
|
//Produced materials are stored in an array
|
|
for (var foo = 0; foo < prodMats.length; ++foo) {
|
|
wh.materials[prodMats[foo]].processMarket();
|
|
}
|
|
|
|
//Process these twice because these boost production
|
|
wh.materials["Hardware"].processMarket();
|
|
wh.materials["Robots"].processMarket();
|
|
wh.materials["AICores"].processMarket();
|
|
wh.materials["RealEstate"].processMarket();
|
|
}
|
|
}
|
|
}
|
|
|
|
//Process change in demand and competition for this industry's products
|
|
Industry.prototype.processProductMarket = function(marketCycles=1) {
|
|
//Demand gradually decreases, and competition gradually increases
|
|
for (var name in this.products) {
|
|
if (this.products.hasOwnProperty(name)) {
|
|
var product = this.products[name];
|
|
var change = getRandomInt(1, 3) * 0.0004;
|
|
if (this.type === Industries.Pharmaceutical || this.type === Industries.Software ||
|
|
this.type === Industries.Robotics) {
|
|
change *= 3;
|
|
}
|
|
change *= marketCycles;
|
|
product.dmd -= change;
|
|
product.cmp += change;
|
|
product.cmp = Math.min(product.cmp, 99.99);
|
|
product.dmd = Math.max(product.dmd, 0.001);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Process production, purchase, and import/export of materials
|
|
Industry.prototype.processMaterials = function(marketCycles=1, company) {
|
|
var revenue = 0, expenses = 0, industry = this;
|
|
this.calculateProductionFactors();
|
|
|
|
//At the start of the export state, set the imports of everything to 0
|
|
if (this.state === "EXPORT") {
|
|
for (var i = 0; i < Cities.length; ++i) {
|
|
var city = Cities[i], office = this.offices[city];
|
|
if (!(this.warehouses[city] instanceof Warehouse)) {
|
|
continue;
|
|
}
|
|
var warehouse = this.warehouses[city];
|
|
for (var matName in warehouse.materials) {
|
|
if (warehouse.materials.hasOwnProperty(matName)) {
|
|
var mat = warehouse.materials[matName];
|
|
mat.imp = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < Cities.length; ++i) {
|
|
var city = Cities[i], office = this.offices[city];
|
|
|
|
if (this.warehouses[city] instanceof Warehouse) {
|
|
var warehouse = this.warehouses[city];
|
|
|
|
switch(this.state) {
|
|
|
|
case "PURCHASE":
|
|
/* Process purchase of materials */
|
|
for (var matName in warehouse.materials) {
|
|
if (warehouse.materials.hasOwnProperty(matName)) {
|
|
(function(matName, ind) {
|
|
var mat = warehouse.materials[matName];
|
|
var buyAmt, maxAmt;
|
|
if (warehouse.smartSupplyEnabled && Object.keys(ind.reqMats).includes(matName)) {
|
|
//Smart supply tracker is stored as per second rate
|
|
mat.buy = ind.reqMats[matName] * warehouse.smartSupplyStore;
|
|
buyAmt = mat.buy * SecsPerMarketCycle * marketCycles;
|
|
} else {
|
|
buyAmt = (mat.buy * SecsPerMarketCycle * marketCycles);
|
|
}
|
|
|
|
if (matName == "RealEstate") {
|
|
maxAmt = buyAmt;
|
|
} else {
|
|
maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / MaterialSizes[matName]);
|
|
}
|
|
var buyAmt = Math.min(buyAmt, maxAmt);
|
|
if (buyAmt > 0) {
|
|
mat.qty += buyAmt;
|
|
expenses += (buyAmt * mat.bCost);
|
|
}
|
|
})(matName, industry);
|
|
this.updateWarehouseSizeUsed(warehouse);
|
|
}
|
|
} //End process purchase of materials
|
|
break;
|
|
|
|
case "PRODUCTION":
|
|
warehouse.smartSupplyStore = 0; //Reset smart supply amount
|
|
|
|
/* Process production of materials */
|
|
if (this.prodMats.length > 0) {
|
|
var mat = warehouse.materials[this.prodMats[0]];
|
|
//Calculate the maximum production of this material based
|
|
//on the office's productivity
|
|
var maxProd = this.getOfficeProductivity(office) * this.prodMult * company.getProductionMultiplier(), prod;
|
|
|
|
if (mat.prdman[0]) {
|
|
//Production is manually limited
|
|
prod = Math.min(maxProd, mat.prdman[1]);
|
|
} else {
|
|
prod = maxProd;
|
|
}
|
|
prod *= (SecsPerMarketCycle * marketCycles); //Convert production from per second to per market cycle
|
|
//Calculate net change in warehouse storage making
|
|
//the produced materials will cost
|
|
var totalMatSize = 0;
|
|
for (var tmp = 0; tmp < this.prodMats.length; ++tmp) {
|
|
totalMatSize += (MaterialSizes[this.prodMats[tmp]]);
|
|
}
|
|
for (var reqMatName in this.reqMats) {
|
|
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
|
var normQty = this.reqMats[reqMatName];
|
|
totalMatSize -= (MaterialSizes[reqMatName] * normQty);
|
|
}
|
|
}
|
|
//If not enough space in warehouse, limit the amount of produced materials
|
|
if (totalMatSize > 0) {
|
|
var maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / totalMatSize);
|
|
prod = Math.min(maxAmt, prod);
|
|
}
|
|
|
|
if (prod < 0) {prod = 0;}
|
|
|
|
//Keep track of production for smart supply (/s)
|
|
warehouse.smartSupplyStore += (prod / (SecsPerMarketCycle * marketCycles));
|
|
|
|
//Make sure we have enough resource to make our materials
|
|
var producableFrac = 1;
|
|
for (var reqMatName in this.reqMats) {
|
|
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
|
var req = this.reqMats[reqMatName] * prod;
|
|
if (warehouse.materials[reqMatName].qty < req) {
|
|
producableFrac = Math.min(producableFrac, warehouse.materials[reqMatName].qty / req);
|
|
}
|
|
}
|
|
}
|
|
if (producableFrac <= 0) {producableFrac = 0; prod = 0;}
|
|
|
|
//Make our materials if they are producable
|
|
if (producableFrac > 0 && prod > 0) {
|
|
for (var reqMatName in this.reqMats) {
|
|
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
|
var reqMatQtyNeeded = (this.reqMats[reqMatName] * prod * producableFrac);
|
|
warehouse.materials[reqMatName].qty -= reqMatQtyNeeded;
|
|
warehouse.materials[reqMatName].prd = 0;
|
|
warehouse.materials[reqMatName].prd -= reqMatQtyNeeded / (SecsPerMarketCycle * marketCycles);
|
|
}
|
|
}
|
|
for (var j = 0; j < this.prodMats.length; ++j) {
|
|
warehouse.materials[this.prodMats[j]].qty += (prod * producableFrac);
|
|
warehouse.materials[this.prodMats[j]].qlt =
|
|
(office.employeeProd[EmployeePositions.Engineer] / 100 +
|
|
Math.pow(this.sciResearch.qty, this.sciFac) +
|
|
Math.pow(warehouse.materials["AICores"].qty, this.aiFac) / 10e3);
|
|
}
|
|
} else {
|
|
for (var reqMatName in this.reqMats) {
|
|
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
|
warehouse.materials[reqMatName].prd = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Per second
|
|
var fooProd = prod * producableFrac / (SecsPerMarketCycle * marketCycles);
|
|
for (var fooI = 0; fooI < this.prodMats.length; ++fooI) {
|
|
warehouse.materials[this.prodMats[fooI]].prd = fooProd;
|
|
}
|
|
} else {
|
|
//If this doesn't produce any materials, then it only creates
|
|
//Products. Creating products will consume materials. The
|
|
//Production of all consumed materials must be set to 0
|
|
for (var reqMatName in this.reqMats) {
|
|
if (this.reqMats.hasOwnProperty(reqMatName)) {
|
|
warehouse.materials[reqMatName].prd = 0;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "SALE":
|
|
/* Process sale of materials */
|
|
for (var matName in warehouse.materials) {
|
|
if (warehouse.materials.hasOwnProperty(matName)) {
|
|
var mat = warehouse.materials[matName];
|
|
if (mat.sCost < 0 || mat.sllman[0] === false) {
|
|
mat.sll = 0;
|
|
continue;
|
|
}
|
|
var mat = warehouse.materials[matName];
|
|
|
|
var sCost;
|
|
if (isString(mat.sCost)) {
|
|
sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
|
sCost = eval(sCost);
|
|
} else {
|
|
sCost = mat.sCost;
|
|
}
|
|
|
|
//Calculate how much of the material sells (per second)
|
|
var markup = 1, markupLimit = mat.qlt / mat.mku;
|
|
if (sCost > mat.bCost) {
|
|
//Penalty if difference between sCost and bCost is greater than markup limit
|
|
if ((sCost - mat.bCost) > markupLimit) {
|
|
markup = markupLimit / (sCost - mat.bCost);
|
|
}
|
|
} 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;
|
|
}
|
|
}
|
|
//var businessFactor = 1 + (office.employeeProd[EmployeePositions.Business] / office.employeeProd["total"]);
|
|
var businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
|
var advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
|
var marketFactor = this.getMarketFactor(mat); //Competition + demand
|
|
var maxSell = (mat.qlt + .001) * marketFactor * markup * businessFactor *
|
|
company.getSalesMultiplier() * advertisingFactor;
|
|
|
|
var sellAmt;
|
|
if (isString(mat.sllman[1])) {
|
|
//Dynamically evaluated
|
|
var tmp = mat.sllman[1].replace(/MAX/g, maxSell);
|
|
tmp = tmp.replace(/PROD/g, mat.prd);
|
|
try {
|
|
sellAmt = eval(tmp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Error evaluating your sell amount for material " + mat.name +
|
|
" in " + this.name + "'s " + city + " office. The sell amount " +
|
|
"is being set to zero");
|
|
sellAmt = 0;
|
|
}
|
|
sellAmt = Math.min(maxSell, sellAmt);
|
|
} else if (mat.sllman[1] === -1) {
|
|
//Backwards compatibility, -1 = MAX
|
|
sellAmt = maxSell;
|
|
} else {
|
|
//Player's input value is just a number
|
|
sellAmt = Math.min(maxSell, mat.sllman[1]);
|
|
}
|
|
|
|
sellAmt = (sellAmt * SecsPerMarketCycle * marketCycles);
|
|
sellAmt = Math.min(mat.qty, sellAmt);
|
|
if (sellAmt < 0) {
|
|
console.log("sellAmt calculated to be negative");
|
|
mat.sll = 0;
|
|
continue;
|
|
}
|
|
if (sellAmt && sCost >= 0) {
|
|
mat.qty -= sellAmt;
|
|
revenue += (sellAmt * sCost);
|
|
mat.sll = sellAmt / (SecsPerMarketCycle * marketCycles);
|
|
} else {
|
|
mat.sll = 0;
|
|
}
|
|
}
|
|
} //End processing of sale of materials
|
|
break;
|
|
|
|
case "EXPORT":
|
|
for (var matName in warehouse.materials) {
|
|
if (warehouse.materials.hasOwnProperty(matName)) {
|
|
var mat = warehouse.materials[matName];
|
|
mat.totalExp = 0; //Reset export
|
|
for (var expI = 0; expI < mat.exp.length; ++expI) {
|
|
var exp = mat.exp[expI];
|
|
var amt = exp.amt.replace(/MAX/g, mat.qty / (SecsPerMarketCycle * marketCycles));
|
|
try {
|
|
amt = eval(amt);
|
|
} catch(e) {
|
|
dialogBoxCreate("Calculating export for " + mat.name + " in " +
|
|
this.name + "'s " + city + " division failed with " +
|
|
"error: " + e);
|
|
continue;
|
|
}
|
|
if (isNaN(amt)) {
|
|
dialogBoxCreate("Error calculating export amount for " + mat.name + " in " +
|
|
this.name + "'s " + city + " division.");
|
|
continue;
|
|
}
|
|
amt = amt * SecsPerMarketCycle * marketCycles;
|
|
|
|
if (mat.qty < amt) {
|
|
amt = mat.qty;
|
|
}
|
|
if (amt === 0) {
|
|
break; //None left
|
|
}
|
|
for (var foo = 0; foo < company.divisions.length; ++foo) {
|
|
if (company.divisions[foo].name === exp.ind) {
|
|
var expIndustry = company.divisions[foo];
|
|
var expWarehouse = expIndustry.warehouses[exp.city];
|
|
if (!(expWarehouse instanceof Warehouse)) {
|
|
console.log("ERROR: Invalid export! " + expIndustry.name + " " + exp.city);
|
|
break;
|
|
}
|
|
|
|
//Make sure theres enough space in warehouse
|
|
if (expWarehouse.sizeUsed >= expWarehouse.size) {
|
|
return; //Warehouse at capacity
|
|
} else {
|
|
var maxAmt = Math.floor((expWarehouse.size - expWarehouse.sizeUsed) / MaterialSizes[matName]);
|
|
amt = Math.min(maxAmt, amt);
|
|
}
|
|
expWarehouse.materials[matName].imp += (amt / (SecsPerMarketCycle * marketCycles));
|
|
expWarehouse.materials[matName].qty += amt;
|
|
expWarehouse.materials[matName].qlt = mat.qlt;
|
|
mat.qty -= amt;
|
|
mat.totalExp += amt;
|
|
expIndustry.updateWarehouseSizeUsed(expWarehouse);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//totalExp should be per second
|
|
mat.totalExp /= (SecsPerMarketCycle * marketCycles);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case "START":
|
|
break;
|
|
default:
|
|
console.log("ERROR: Invalid state: " + this.state);
|
|
break;
|
|
} //End switch(this.state)
|
|
this.updateWarehouseSizeUsed(warehouse);
|
|
|
|
} // End warehouse
|
|
|
|
//Produce Scientific Research based on R&D employees
|
|
//Scientific Research can be produced without a warehouse
|
|
if (office instanceof OfficeSpace) {
|
|
this.sciResearch.qty += (.005 * Math.pow(office.employeeProd[EmployeePositions.RandD], 0.5)
|
|
* company.getScientificResearchMultiplier());
|
|
}
|
|
}
|
|
return [revenue, expenses];
|
|
}
|
|
|
|
//Process production & sale of this industry's FINISHED products (including all of their stats)
|
|
Industry.prototype.processProducts = function(marketCycles=1, corporation) {
|
|
var revenue = 0, expenses = 0;
|
|
|
|
//Create products
|
|
if (this.state === "PRODUCTION") {
|
|
for (var prodName in this.products) {
|
|
if (this.products.hasOwnProperty(prodName)) {
|
|
var prod = this.products[prodName];
|
|
if (!prod.fin) {
|
|
var city = prod.createCity, office = this.offices[city];
|
|
var total = office.employeeProd[EmployeePositions.Operations] +
|
|
office.employeeProd[EmployeePositions.Engineer] +
|
|
office.employeeProd[EmployeePositions.Management], ratio;
|
|
if (total === 0) {
|
|
ratio = 0;
|
|
} else {
|
|
ratio = office.employeeProd[EmployeePositions.Engineer] / total +
|
|
office.employeeProd[EmployeePositions.Operations] / total +
|
|
office.employeeProd[EmployeePositions.Management] / total;
|
|
}
|
|
prod.createProduct(marketCycles, ratio * Math.pow(total, 0.29));
|
|
if (prod.prog >= 100) {
|
|
prod.finishProduct(office.employeeProd, this);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Produce Products
|
|
for (var prodName in this.products) {
|
|
if (this.products.hasOwnProperty(prodName)) {
|
|
var prod = this.products[prodName];
|
|
if (prod instanceof Product && prod.fin) {
|
|
revenue += this.processProduct(marketCycles, prod, corporation);
|
|
}
|
|
}
|
|
}
|
|
return [revenue, expenses];
|
|
}
|
|
|
|
//Processes FINISHED products
|
|
Industry.prototype.processProduct = function(marketCycles=1, product, corporation) {
|
|
var totalProfit = 0;
|
|
for (var i = 0; i < Cities.length; ++i) {
|
|
var city = Cities[i], office = this.offices[city], warehouse = this.warehouses[city];
|
|
if (warehouse instanceof Warehouse) {
|
|
switch(this.state) {
|
|
|
|
case "PRODUCTION":
|
|
//Calculate the maximum production of this material based
|
|
//on the office's productivity
|
|
var maxProd = this.getOfficeProductivity(office, {forProduct:true}) *
|
|
corporation.getProductionMultiplier() * this.prodMult, prod;
|
|
|
|
//Account for whether production is manually limited
|
|
if (product.prdman[city][0]) {
|
|
prod = Math.min(maxProd, product.prdman[city][1]);
|
|
} else {
|
|
prod = maxProd;
|
|
}
|
|
prod *= (SecsPerMarketCycle * marketCycles);
|
|
|
|
//Calculate net change in warehouse storage making the Products will cost
|
|
var netStorageSize = product.siz;
|
|
for (var reqMatName in product.reqMats) {
|
|
if (product.reqMats.hasOwnProperty(reqMatName)) {
|
|
var normQty = product.reqMats[reqMatName];
|
|
netStorageSize -= (MaterialSizes[reqMatName] * normQty);
|
|
}
|
|
}
|
|
|
|
//If there's not enough space in warehouse, limit the amount of Product
|
|
if (netStorageSize > 0) {
|
|
var maxAmt = Math.floor((warehouse.size - warehouse.sizeUsed) / netStorageSize);
|
|
prod = Math.min(maxAmt, prod);
|
|
}
|
|
|
|
warehouse.smartSupplyStore += (prod / (SecsPerMarketCycle * marketCycles));
|
|
|
|
//Make sure we have enough resources to make our Products
|
|
var producableFrac = 1;
|
|
for (var reqMatName in product.reqMats) {
|
|
if (product.reqMats.hasOwnProperty(reqMatName)) {
|
|
var req = product.reqMats[reqMatName] * prod;
|
|
if (warehouse.materials[reqMatName].qty < req) {
|
|
producableFrac = Math.min(producableFrac, warehouse.materials[reqMatName].qty / req);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Make our Products if they are producable
|
|
if (producableFrac > 0 && prod > 0) {
|
|
for (var reqMatName in product.reqMats) {
|
|
if (product.reqMats.hasOwnProperty(reqMatName)) {
|
|
var reqMatQtyNeeded = (product.reqMats[reqMatName] * prod * producableFrac);
|
|
warehouse.materials[reqMatName].qty -= reqMatQtyNeeded;
|
|
warehouse.materials[reqMatName].prd -= reqMatQtyNeeded / (SecsPerMarketCycle * marketCycles);
|
|
}
|
|
}
|
|
//Quantity
|
|
product.data[city][0] += (prod * producableFrac);
|
|
}
|
|
|
|
//Keep track of production Per second
|
|
product.data[city][1] = prod * producableFrac / (SecsPerMarketCycle * marketCycles);
|
|
break;
|
|
|
|
case "SALE":
|
|
//Process sale of Products
|
|
product.pCost = 0; //Estimated production cost
|
|
for (var reqMatName in product.reqMats) {
|
|
if (product.reqMats.hasOwnProperty(reqMatName)) {
|
|
product.pCost += (product.reqMats[reqMatName] * warehouse.materials[reqMatName].bCost);
|
|
}
|
|
}
|
|
|
|
//Since its a product, its production cost is increased for labor
|
|
product.pCost *= ProductProductionCostRatio;
|
|
|
|
//Calculate Sale Cost (sCost), which could be dynamically evaluated
|
|
var sCost;
|
|
if (isString(product.sCost)) {
|
|
sCost = product.sCost.replace(/MP/g, product.pCost + product.rat / product.mku);
|
|
sCost = eval(sCost);
|
|
} else {
|
|
sCost = product.sCost;
|
|
}
|
|
|
|
var markup = 1, markupLimit = product.rat / product.mku;
|
|
if (sCost > product.pCost) {
|
|
if ((sCost - product.pCost) > markupLimit) {
|
|
markup = markupLimit / (sCost - product.pCost);
|
|
}
|
|
}
|
|
var businessFactor = this.getBusinessFactor(office); //Business employee productivity
|
|
var advertisingFactor = this.getAdvertisingFactors()[0]; //Awareness + popularity
|
|
var marketFactor = this.getMarketFactor(product); //Competition + demand
|
|
var maxSell = 0.5 * Math.pow(product.rat, 0.65) * marketFactor * corporation.getSalesMultiplier() *
|
|
Math.pow(markup, 2) * businessFactor * advertisingFactor;
|
|
var sellAmt;
|
|
if (product.sllman[city][0] && isString(product.sllman[city][1])) {
|
|
//Sell amount is dynamically evaluated
|
|
var tmp = product.sllman[city][1].replace(/MAX/g, maxSell);
|
|
tmp = tmp.replace(/PROD/g, product.data[city][1]);
|
|
try {
|
|
tmp = eval(tmp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Error evaluating your sell price expression for " + product.name +
|
|
" in " + this.name + "'s " + city + " office. Sell price is being set to MAX");
|
|
tmp = maxSell;
|
|
}
|
|
sellAmt = Math.min(maxSell, tmp);
|
|
} else if (product.sllman[city][0] && product.sllman[city][1] > 0) {
|
|
//Sell amount is manually limited
|
|
sellAmt = Math.min(maxSell, product.sllman[city][1]);
|
|
} else {
|
|
//Backwards compatibility, -1 = 0
|
|
sellAmt = maxSell;
|
|
}
|
|
sellAmt = sellAmt * SecsPerMarketCycle * marketCycles;
|
|
sellAmt = Math.min(product.data[city][0], sellAmt); //data[0] is qty
|
|
if (sellAmt && sCost) {
|
|
product.data[city][0] -= sellAmt; //data[0] is qty
|
|
totalProfit += (sellAmt * sCost);
|
|
product.data[city][2] = sellAmt / (SecsPerMarketCycle * marketCycles); //data[2] is sell property
|
|
} else {
|
|
product.data[city][2] = 0; //data[2] is sell property
|
|
}
|
|
break;
|
|
|
|
case "START":
|
|
case "PURCHASE":
|
|
case "EXPORT":
|
|
break;
|
|
default:
|
|
console.log("ERROR: Invalid State: " + this.state);
|
|
break;
|
|
} //End switch(this.state)
|
|
}
|
|
}
|
|
return totalProfit;
|
|
}
|
|
|
|
Industry.prototype.discontinueProduct = function(product, parentRefs) {
|
|
var company = parentRefs.company, industry = parentRefs.industry;
|
|
for (var productName in this.products) {
|
|
if (this.products.hasOwnProperty(productName)) {
|
|
if (product === this.products[productName]) {
|
|
delete this.products[productName];
|
|
company.updateUIContent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Industry.prototype.upgrade = function(upgrade, refs) {
|
|
var corporation = refs.corporation, division = refs.division,
|
|
office = refs.office;
|
|
var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2],
|
|
upgradeBenefit = upgrade[3];
|
|
while (this.upgrades.length <= upgN) {this.upgrades.push(0);}
|
|
++this.upgrades[upgN];
|
|
|
|
switch (upgN) {
|
|
case 0: //Coffee, 5% energy per employee
|
|
for (var i = 0; i < office.employees.length; ++i) {
|
|
office.employees[i].ene = Math.min(office.employees[i].ene * 1.05, 100);
|
|
}
|
|
break;
|
|
case 1: //AdVert.Inc,
|
|
var advMult = corporation.getAdvertisingMultiplier();
|
|
this.awareness += (3 * advMult);
|
|
this.popularity += (1 * advMult);
|
|
this.awareness *= (1.01 * advMult);
|
|
this.popularity *= ((1 + getRandomInt(1, 3) / 100) * advMult);
|
|
break;
|
|
default:
|
|
console.log("ERROR: Un-implemented function index: " + upgN);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Returns how much of a material can be produced based of office productivity (employee stats)
|
|
Industry.prototype.getOfficeProductivity = function(office, params) {
|
|
var total = office.employeeProd[EmployeePositions.Operations] +
|
|
office.employeeProd[EmployeePositions.Engineer] +
|
|
office.employeeProd[EmployeePositions.Management], ratio;
|
|
if (total === 0) {
|
|
ratio = 0;
|
|
} else {
|
|
ratio = (office.employeeProd[EmployeePositions.Operations] / total) *
|
|
(office.employeeProd[EmployeePositions.Engineer] / total) *
|
|
(office.employeeProd[EmployeePositions.Management] / total);
|
|
ratio = Math.max(0.01, ratio); //Minimum ratio value if you have employees
|
|
}
|
|
if (params && params.forProduct) {
|
|
return ratio * Math.pow(total, 0.2);
|
|
} else {
|
|
return 2 * ratio * Math.pow(total, 0.3);
|
|
}
|
|
}
|
|
|
|
//Returns a multiplier based on the office' 'Business' employees that affects sales
|
|
Industry.prototype.getBusinessFactor = function(office) {
|
|
var ratioMult = 1;
|
|
if (office.employeeProd["total"] > 0) {
|
|
ratioMult = 1 + (office.employeeProd[EmployeePositions.Business] / office.employeeProd["total"]);
|
|
}
|
|
return ratioMult * Math.pow(1 + office.employeeProd[EmployeePositions.Business], 0.15);
|
|
}
|
|
|
|
//Returns a set of multipliers based on the Industry's awareness, popularity, and advFac. This
|
|
//multiplier affects sales. The result is:
|
|
// [Total sales mult, total awareness mult, total pop mult, awareness/pop ratio mult]
|
|
Industry.prototype.getAdvertisingFactors = function() {
|
|
var awarenessFac = Math.pow(this.awareness + 1, this.advFac);
|
|
var popularityFac = Math.pow(this.popularity + 1, this.advFac);
|
|
var ratioFac = (this.awareness === 0 ? 0.01 : Math.max((this.popularity + .001) / this.awareness, 0.01));
|
|
var totalFac = Math.pow(awarenessFac * popularityFac * ratioFac, 0.85);
|
|
return [totalFac, awarenessFac, popularityFac, ratioFac];
|
|
}
|
|
|
|
//Returns a multiplier based on a materials demand and competition that affects sales
|
|
Industry.prototype.getMarketFactor = function(mat) {
|
|
return mat.dmd * (100 - mat.cmp)/100;
|
|
}
|
|
|
|
Industry.prototype.toJSON = function() {
|
|
return Generic_toJSON("Industry", this);
|
|
}
|
|
|
|
Industry.fromJSON = function(value) {
|
|
return Generic_fromJSON(Industry, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Industry = Industry;
|
|
|
|
var EmployeePositions = {
|
|
Operations: "Operations",
|
|
Engineer: "Engineer",
|
|
Business: "Business",
|
|
Management: "Management",
|
|
RandD: "Research & Development",
|
|
Training:"Training",
|
|
Unassigned:"Unassigned",
|
|
}
|
|
|
|
function Employee(params={}) {
|
|
if (!(this instanceof Employee)) {
|
|
return new Employee(params);
|
|
}
|
|
this.name = params.name ? params.name : "Bobby";
|
|
|
|
//Morale, happiness, and energy are 0-100
|
|
this.mor = params.morale ? params.morale : getRandomInt(50, 100);
|
|
this.hap = params.happiness ? params.happiness : getRandomInt(50, 100);
|
|
this.ene = params.energy ? params.energy : getRandomInt(50, 100);
|
|
|
|
this.age = params.age ? params.age : getRandomInt(20, 50);
|
|
this.int = params.intelligence ? params.intelligence : getRandomInt(10, 50);
|
|
this.cha = params.charisma ? params.charisma : getRandomInt(10, 50);
|
|
this.exp = params.experience ? params.experience : getRandomInt(10, 50);
|
|
this.cre = params.creativity ? params.creativity : getRandomInt(10, 50);
|
|
this.eff = params.efficiency ? params.efficiency : getRandomInt(10, 50);
|
|
this.sal = params.salary ? params.salary : getRandomInt(0.1, 5);
|
|
this.pro = 0; //Productivity, This is calculated
|
|
|
|
this.loc = params.loc ? params.loc : "";
|
|
this.pos = EmployeePositions.Unassigned;
|
|
}
|
|
|
|
//Returns the amount the employee needs to be paid
|
|
Employee.prototype.process = function(marketCycles=1, office) {
|
|
var gain = 0.001 * marketCycles,
|
|
det = gain * Math.random();
|
|
this.age += gain;
|
|
this.exp += gain;
|
|
if (this.age > 150) {
|
|
this.int -= det;
|
|
this.eff -= det;
|
|
this.cha -= det;
|
|
}
|
|
|
|
//Training
|
|
var trainingEff = gain * Math.random();
|
|
if (this.pos === EmployeePositions.Training) {
|
|
//To increase creativity and intelligence special upgrades are needed
|
|
this.cha += trainingEff;
|
|
this.exp += trainingEff;
|
|
this.eff += trainingEff;
|
|
}
|
|
|
|
//Weight based on how full office is
|
|
//Too many employees = more likely to decrease energy and happiness
|
|
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.hap < office.minHap) {this.hap = office.minHap;}
|
|
var salary = this.sal * marketCycles * SecsPerMarketCycle;
|
|
return salary;
|
|
}
|
|
|
|
Employee.prototype.calculateProductivity = function(corporation) {
|
|
var effCre = this.cre * corporation.getEmployeeCreMultiplier(),
|
|
effCha = this.cha * corporation.getEmployeeChaMultiplier(),
|
|
effInt = this.int * corporation.getEmployeeIntMultiplier(),
|
|
effEff = this.eff * corporation.getEmployeeEffMultiplier();
|
|
var prodBase = this.mor * this.hap * this.ene * 1e-6, prodMult;
|
|
switch(this.pos) {
|
|
//Calculate productivity based on position. This is multipled by prodBase
|
|
//to get final value
|
|
case EmployeePositions.Operations:
|
|
prodMult = (0.6 * effInt) + (0.1 * effCha) + (this.exp) +
|
|
(0.5 * effCre) + (effEff);
|
|
break;
|
|
case EmployeePositions.Engineer:
|
|
prodMult = (effInt) + (0.1 * effCha) + (1.5 * this.exp) +
|
|
(effEff);
|
|
break;
|
|
case EmployeePositions.Business:
|
|
prodMult = (0.4 * effInt) + (effCha) + (0.5 * this.exp);
|
|
break;
|
|
case EmployeePositions.Management:
|
|
prodMult = (2 * effCha) + (this.exp) + (0.2 * effCre) +
|
|
(0.7 * effEff);
|
|
break;
|
|
case EmployeePositions.RandD:
|
|
prodMult = (1.5 * effInt) + (0.8 * this.exp) + (effCre) +
|
|
(0.5 * effEff);
|
|
break;
|
|
case EmployeePositions.Unassigned:
|
|
case EmployeePositions.Training:
|
|
prodMult = 0;
|
|
break;
|
|
default:
|
|
console.log("ERROR: Invalid employee position: " + this.pos);
|
|
break;
|
|
}
|
|
return prodBase * prodMult;
|
|
}
|
|
|
|
//Process benefits from having an office party thrown
|
|
Employee.prototype.throwParty = function(money) {
|
|
var mult = 1 + (money / 10e6);
|
|
this.mor *= mult;
|
|
this.mor = Math.min(100, this.mor);
|
|
this.hap *= mult;
|
|
this.hap = Math.min(100, this.hap);
|
|
return mult;
|
|
}
|
|
|
|
//'panel' is the DOM element on which to create the UI
|
|
Employee.prototype.createUI = function(panel, corporation) {
|
|
var effCre = this.cre * corporation.getEmployeeCreMultiplier(),
|
|
effCha = this.cha * corporation.getEmployeeChaMultiplier(),
|
|
effInt = this.int * corporation.getEmployeeIntMultiplier(),
|
|
effEff = this.eff * corporation.getEmployeeEffMultiplier();
|
|
panel.style.color = "white";
|
|
panel.appendChild(createElement("p", {
|
|
id:"cmpy-mgmt-employee-" + this.name + "-panel-text",
|
|
innerHTML:"Morale: " + formatNumber(this.mor, 3) + "<br>" +
|
|
"Happiness: " + formatNumber(this.hap, 3) + "<br>" +
|
|
"Energy: " + formatNumber(this.ene, 3) + "<br>" +
|
|
"Age: " + formatNumber(this.age, 3) + "<br>" +
|
|
"Intelligence: " + formatNumber(effInt, 3) + "<br>" +
|
|
"Charisma: " + formatNumber(effCha, 3) + "<br>" +
|
|
"Experience: " + formatNumber(this.exp, 3) + "<br>" +
|
|
"Creativity: " + formatNumber(effCre, 3) + "<br>" +
|
|
"Efficiency: " + formatNumber(effEff, 3) + "<br>" +
|
|
"Salary: " + numeral(this.sal).format("$0.000a") + "/ s<br>",
|
|
}));
|
|
|
|
//Selector for employee position
|
|
var selector = createElement("select", {});
|
|
for (var key in EmployeePositions) {
|
|
if (EmployeePositions.hasOwnProperty(key)) {
|
|
selector.add(createElement("option", {
|
|
text: EmployeePositions[key],
|
|
value: EmployeePositions[key],
|
|
}));
|
|
}
|
|
}
|
|
|
|
selector.addEventListener("change", ()=>{
|
|
this.pos = selector.options[selector.selectedIndex].value;
|
|
});
|
|
|
|
//Set initial value of selector
|
|
for (var i = 0; i < selector.length; ++i) {
|
|
if (selector.options[i].value === this.pos) {
|
|
selector.selectedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
panel.appendChild(selector);
|
|
}
|
|
|
|
Employee.prototype.updateUI = function(panel, corporation) {
|
|
var effCre = this.cre * corporation.getEmployeeCreMultiplier(),
|
|
effCha = this.cha * corporation.getEmployeeChaMultiplier(),
|
|
effInt = this.int * corporation.getEmployeeIntMultiplier(),
|
|
effEff = this.eff * corporation.getEmployeeEffMultiplier();
|
|
if (panel == null) {
|
|
console.log("ERROR: Employee.updateUI() called with null panel");
|
|
return;
|
|
}
|
|
var text = document.getElementById("cmpy-mgmt-employee-" + this.name + "-panel-text");
|
|
if (text == null) {
|
|
return this.createUI(panel);
|
|
}
|
|
text.innerHTML = "Morale: " + formatNumber(this.mor, 3) + "<br>" +
|
|
"Happiness: " + formatNumber(this.hap, 3) + "<br>" +
|
|
"Energy: " + formatNumber(this.ene, 3) + "<br>" +
|
|
"Age: " + formatNumber(this.age, 3) + "<br>" +
|
|
"Intelligence: " + formatNumber(effInt, 3) + "<br>" +
|
|
"Charisma: " + formatNumber(effCha, 3) + "<br>" +
|
|
"Experience: " + formatNumber(this.exp, 3) + "<br>" +
|
|
"Creativity: " + formatNumber(effCre, 3) + "<br>" +
|
|
"Efficiency: " + formatNumber(effEff, 3) + "<br>" +
|
|
"Salary: " + numeral(this.sal).format("$0.000a") + "/ s<br>";
|
|
}
|
|
|
|
Employee.prototype.toJSON = function() {
|
|
return Generic_toJSON("Employee", this);
|
|
}
|
|
|
|
Employee.fromJSON = function(value) {
|
|
return Generic_fromJSON(Employee, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Employee = Employee;
|
|
|
|
var OfficeSpaceTiers = {
|
|
Basic: "Basic",
|
|
Enhanced: "Enhanced",
|
|
Luxurious: "Luxurious",
|
|
Extravagant: "Extravagant"
|
|
}
|
|
|
|
function OfficeSpace(params={}) {
|
|
this.loc = params.loc ? params.loc : "";
|
|
this.cost = params.cost ? params.cost : 1;
|
|
this.size = params.size ? params.size : 1;
|
|
this.comf = params.comfort ? params.comfort : 1;
|
|
this.beau = params.beauty ? params.beauty : 1;
|
|
this.tier = OfficeSpaceTiers.Basic;
|
|
|
|
this.minEne = 0; //Minimum energy of employees, based on office
|
|
this.minHap = 0; //Minimum happiness of employees, based on office.
|
|
|
|
this.employees = [];
|
|
this.employeeProd = {
|
|
[EmployeePositions.Operations]: 0,
|
|
[EmployeePositions.Engineer]: 0,
|
|
[EmployeePositions.Business]: 0,
|
|
[EmployeePositions.Management]: 0,
|
|
[EmployeePositions.RandD]: 0,
|
|
total: 0,
|
|
};
|
|
}
|
|
|
|
OfficeSpace.prototype.process = function(marketCycles=1, parentRefs) {
|
|
var corporation = parentRefs.corporation, industry = parentRefs.industry;
|
|
var perfMult=1; //Multiplier for employee morale/happiness/energy based on company performance
|
|
if (industry.funds < 0 && industry.lastCycleRevenue < 0) {
|
|
perfMult = Math.pow(0.99, marketCycles);
|
|
} else if (industry.funds > 0 && industry.lastCycleRevenue > 0) {
|
|
perfMult = Math.pow(1.01, marketCycles);
|
|
}
|
|
|
|
var salaryPaid = 0;
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
var emp = this.employees[i];
|
|
emp.mor *= perfMult;
|
|
emp.hap *= perfMult;
|
|
emp.ene *= perfMult;
|
|
var salary = emp.process(marketCycles, this);
|
|
salaryPaid += salary;
|
|
}
|
|
this.calculateEmployeeProductivity(marketCycles, corporation);
|
|
return salaryPaid;
|
|
}
|
|
|
|
OfficeSpace.prototype.calculateEmployeeProductivity = function(marketCycles=1, corporation) {
|
|
//Reset
|
|
for (var name in this.employeeProd) {
|
|
if (this.employeeProd.hasOwnProperty(name)) {
|
|
this.employeeProd[name] = 0;
|
|
}
|
|
}
|
|
|
|
var total = 0;
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
var employee = this.employees[i];
|
|
var prod = employee.calculateProductivity(corporation);
|
|
this.employeeProd[employee.pos] += prod;
|
|
total += prod;
|
|
}
|
|
this.employeeProd["total"] = total;
|
|
}
|
|
|
|
//Takes care of UI as well
|
|
OfficeSpace.prototype.findEmployees = function(parentRefs) {
|
|
var company = parentRefs.corporation, division = parentRefs.division;
|
|
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) {return;}
|
|
|
|
//Generate three random employees (meh, decent, amazing)
|
|
var mult1 = getRandomInt(25, 50)/100,
|
|
mult2 = getRandomInt(51, 75)/100,
|
|
mult3 = getRandomInt(76, 100)/100;
|
|
var int = getRandomInt(50, 100),
|
|
cha = getRandomInt(50, 100),
|
|
exp = getRandomInt(50, 100),
|
|
cre = getRandomInt(50, 100),
|
|
eff = getRandomInt(50, 100),
|
|
sal = 2.2 * (int + cha + exp + cre + eff);
|
|
|
|
var emp1 = new Employee({
|
|
intelligence: int * mult1,
|
|
charisma: cha * mult1,
|
|
experience: exp * mult1,
|
|
creativity: cre * mult1,
|
|
efficiency: eff * mult1,
|
|
salary: sal * mult1,
|
|
});
|
|
|
|
var emp2 = new Employee({
|
|
intelligence: int * mult2,
|
|
charisma: cha * mult2,
|
|
experience: exp * mult2,
|
|
creativity: cre * mult2,
|
|
efficiency: eff * mult2,
|
|
salary: sal * mult2,
|
|
});
|
|
|
|
var emp3 = new Employee({
|
|
intelligence: int * mult3,
|
|
charisma: cha * mult3,
|
|
experience: exp * mult3,
|
|
creativity: cre * mult3,
|
|
efficiency: eff * mult3,
|
|
salary: sal * mult3,
|
|
});
|
|
|
|
var text = createElement("h1", {
|
|
innerHTML: "Select one of the following candidates for hire:",
|
|
});
|
|
|
|
var createEmpDiv = function(employee, office) {
|
|
var div = createElement("div", {
|
|
class:"cmpy-mgmt-find-employee-option",
|
|
innerHTML: "Intelligence: " + formatNumber(employee.int, 1) + "<br>" +
|
|
"Charisma: " + formatNumber(employee.cha, 1) + "<br>" +
|
|
"Experience: " + formatNumber(employee.exp, 1) + "<br>" +
|
|
"Creativity: " + formatNumber(employee.cre, 1) + "<br>" +
|
|
"Efficiency: " + formatNumber(employee.eff, 1) + "<br>" +
|
|
"Salary: " + numeral(employee.sal).format('$0.000a') + " \ s<br>",
|
|
clickListener:()=>{
|
|
office.hireEmployee(employee, parentRefs);
|
|
removeElementById("cmpy-mgmt-hire-employee-popup");
|
|
return false;
|
|
}
|
|
});
|
|
return div;
|
|
};
|
|
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Cancel",
|
|
float:"right",
|
|
clickListener:()=>{
|
|
removeElementById("cmpy-mgmt-hire-employee-popup");
|
|
return false;
|
|
}
|
|
});
|
|
|
|
var elems = [text,
|
|
createEmpDiv(emp1, this),
|
|
createEmpDiv(emp2, this),
|
|
createEmpDiv(emp3, this),
|
|
cancelBtn];
|
|
|
|
createPopup("cmpy-mgmt-hire-employee-popup", elems);
|
|
}
|
|
|
|
OfficeSpace.prototype.hireEmployee = function(employee, parentRefs) {
|
|
var company = parentRefs.corporation, division = parentRefs.division;
|
|
var yesBtn = yesNoTxtInpBoxGetYesButton(),
|
|
noBtn = yesNoTxtInpBoxGetNoButton();
|
|
yesBtn.innerHTML = "Hire";
|
|
noBtn.innerHTML = "Cancel";
|
|
yesBtn.addEventListener("click", ()=>{
|
|
var name = yesNoTxtInpBoxGetInput();
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
if (this.employees[i].name === name) {
|
|
dialogBoxCreate("You already have an employee with this nickname! Please give every employee a unique nickname.");
|
|
return false;
|
|
}
|
|
}
|
|
employee.name = name;
|
|
this.employees.push(employee);
|
|
company.displayDivisionContent(division, currentCityUi);
|
|
return yesNoTxtInpBoxClose();
|
|
});
|
|
noBtn.addEventListener("click", ()=>{
|
|
return yesNoTxtInpBoxClose();
|
|
});
|
|
yesNoTxtInpBoxCreate("Give your employee a nickname!");
|
|
}
|
|
|
|
OfficeSpace.prototype.hireRandomEmployee = function(parentRefs) {
|
|
var company = parentRefs.corporation, division = parentRefs.division;
|
|
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) {return;}
|
|
|
|
//Generate three random employees (meh, decent, amazing)
|
|
var mult = getRandomInt(76, 100)/100;
|
|
var int = getRandomInt(50, 100),
|
|
cha = getRandomInt(50, 100),
|
|
exp = getRandomInt(50, 100),
|
|
cre = getRandomInt(50, 100),
|
|
eff = getRandomInt(50, 100),
|
|
sal = 2.2 * (int + cha + exp + cre + eff);
|
|
|
|
var emp = new Employee({
|
|
intelligence: int * mult,
|
|
charisma: cha * mult,
|
|
experience: exp * mult,
|
|
creativity: cre * mult,
|
|
efficiency: eff * mult,
|
|
salary: sal * mult,
|
|
});
|
|
|
|
var name = generateRandomString(7);
|
|
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
if (this.employees[i].name === name) {
|
|
return this.hireRandomEmployee(parentRefs);
|
|
}
|
|
}
|
|
emp.name = name;
|
|
this.employees.push(emp);
|
|
company.displayDivisionContent(division, currentCityUi);
|
|
}
|
|
|
|
//Finds the first unassigned employee and assigns its to the specified job
|
|
OfficeSpace.prototype.assignEmployeeToJob = function(job) {
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
if (this.employees[i].pos === EmployeePositions.Unassigned) {
|
|
this.employees[i].pos = job;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//Finds the first employee with the given job and unassigns it
|
|
OfficeSpace.prototype.unassignEmployeeFromJob = function(job) {
|
|
for (var i = 0; i < this.employees.length; ++i) {
|
|
if (this.employees[i].pos === job) {
|
|
this.employees[i].pos = EmployeePositions.Unassigned;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
OfficeSpace.prototype.toJSON = function() {
|
|
return Generic_toJSON("OfficeSpace", this);
|
|
}
|
|
|
|
OfficeSpace.fromJSON = function(value) {
|
|
return Generic_fromJSON(OfficeSpace, value.data);
|
|
}
|
|
|
|
Reviver.constructors.OfficeSpace = OfficeSpace;
|
|
|
|
function Warehouse(params={}) {
|
|
this.loc = params.loc ? params.loc : "";
|
|
this.size = params.size ? params.size : 0;
|
|
this.level = 0;
|
|
this.sizeUsed = 0;
|
|
this.smartSupplyEnabled = false; //Whether or not smart supply is enabled
|
|
this.breakdown = "";
|
|
|
|
//Stores the amount of product to be produced. Used for Smart Supply unlock.
|
|
//The production tracked by smart supply is always based on the previous cycle,
|
|
//so it will always trail the "true" production by 1 cycle
|
|
this.smartSupplyStore = 0;
|
|
|
|
this.materials = {
|
|
Water: new Material({name: "Water"}),
|
|
Energy: new Material({name: "Energy"}),
|
|
Food: new Material({name: "Food"}),
|
|
Plants: new Material({name: "Plants"}),
|
|
Metal: new Material({name: "Metal"}),
|
|
Hardware: new Material({name: "Hardware"}),
|
|
Chemicals: new Material({name: "Chemicals"}),
|
|
Drugs: new Material({name: "Drugs"}),
|
|
Robots: new Material({name: "Robots"}),
|
|
AICores: new Material({name: "AI Cores"}),
|
|
RealEstate: new Material({name: "Real Estate"})
|
|
}
|
|
}
|
|
|
|
Warehouse.prototype.updateMaterialSizeUsed = function() {
|
|
this.sizeUsed = 0;
|
|
this.breakdown = "";
|
|
for (var matName in this.materials) {
|
|
if (this.materials.hasOwnProperty(matName)) {
|
|
var mat = this.materials[matName];
|
|
if (MaterialSizes.hasOwnProperty(matName)) {
|
|
this.sizeUsed += (mat.qty * MaterialSizes[matName]);
|
|
if (mat.qty > 0) {
|
|
this.breakdown += (matName + ": " + formatNumber(mat.qty * MaterialSizes[matName], 0) + "<br>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (this.sizeUsed > this.size) {
|
|
console.log("ERROR: Warehouse size used greater than capacity, something went wrong");
|
|
}
|
|
}
|
|
|
|
Warehouse.prototype.updateSize = function(corporation) {
|
|
//Backwards compatibility
|
|
if (this.level == null || this.level === 0) {
|
|
this.level = Math.round(this.size / 100);
|
|
}
|
|
|
|
this.size = (this.level * 100) * corporation.getStorageMultiplier();
|
|
}
|
|
|
|
Warehouse.prototype.createUI = function(parentRefs) {
|
|
if (parentRefs.company == null || parentRefs.industry == null) {
|
|
console.log("ERROR: Warehouse.createUI called without parentRefs.company or parentRefs.industry");
|
|
return;
|
|
}
|
|
var company = parentRefs.company, industry = parentRefs.industry;
|
|
removeChildrenFromElement(industryWarehousePanel);
|
|
industryWarehouseStorageText = createElement("p", {
|
|
display:"inline-block", class:"tooltip",
|
|
color: this.sizeUsed >= this.size ? "red" : "white",
|
|
});
|
|
industryWarehousePanel.appendChild(industryWarehouseStorageText);
|
|
|
|
//Upgrade warehouse size button
|
|
var upgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, this.level+1);
|
|
industryWarehouseUpgradeSizeButton = createElement("a", {
|
|
innerText:"Upgrade Warehouse Size - " + numeral(upgradeCost).format('$0.000a'),
|
|
display:"inline-block",
|
|
class: company.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button",
|
|
clickListener:()=>{
|
|
//Backwards compatibility
|
|
if (this.level == null || this.level === 0) {
|
|
this.level = Math.round(this.size / 100);
|
|
}
|
|
|
|
++this.level;
|
|
this.updateSize(company);
|
|
company.funds = company.funds.minus(upgradeCost);
|
|
this.createUI(parentRefs);
|
|
return;
|
|
}
|
|
});
|
|
industryWarehousePanel.appendChild(industryWarehouseUpgradeSizeButton);
|
|
|
|
//Material requirement text
|
|
var reqText = "This Industry uses [" + Object.keys(industry.reqMats).join(", ") +
|
|
"] in order to ";
|
|
if (industry.prodMats.length > 0) {
|
|
reqText += "produce [" + industry.prodMats.join(", ") + "] ";
|
|
if (industry.makesProducts) {
|
|
reqText += " and " + industry.getProductDescriptionText();
|
|
}
|
|
} else if (industry.makesProducts) {
|
|
reqText += industry.getProductDescriptionText();
|
|
}
|
|
reqText += "<br><br>To get started with production, purchase your required " +
|
|
"materials or import them from another of your company's divisions.<br><br>";
|
|
|
|
//Material ratio text for tooltip
|
|
var reqRatioText = "The exact requirements for production are:<br>";
|
|
for (var matName in industry.reqMats) {
|
|
if (industry.reqMats.hasOwnProperty(matName)) {
|
|
reqRatioText += (industry.reqMats[matName] + " " + matName + "<br>");
|
|
}
|
|
}
|
|
reqRatioText += "in order to create ";
|
|
if (industry.prodMats.length > 0) {
|
|
reqRatioText += "one of each produced Material (" + industry.prodMats.join(", ") + ") ";
|
|
if (industry.makesProducts) {
|
|
reqRatioText += "or to create one of its Products";
|
|
}
|
|
} else if (industry.makesProducts) {
|
|
reqRatioText += "one of its Products";
|
|
}
|
|
|
|
industryWarehousePanel.appendChild(createElement("p", {
|
|
innerHTML:reqText, tooltipleft:reqRatioText
|
|
}));
|
|
|
|
//Current state
|
|
industryWarehouseStateText = createElement("p");
|
|
industryWarehousePanel.appendChild(industryWarehouseStateText);
|
|
|
|
//Smart Supply Enable/Disable
|
|
if (company.unlockUpgrades[1]) {
|
|
if (this.smartSupplyEnabled == null) {this.smartSupplyEnabled = false;}
|
|
var smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
|
|
industryWarehousePanel.appendChild(createElement("label", {
|
|
for:smartSupplyCheckboxId, innerText:"Enable Smart Supply",
|
|
color:"white"
|
|
}));
|
|
industrySmartSupplyCheckbox = createElement("input", {
|
|
type:"checkbox", id:smartSupplyCheckboxId, margin:"3px",
|
|
changeListener:()=>{
|
|
this.smartSupplyEnabled = industrySmartSupplyCheckbox.checked;
|
|
}
|
|
});
|
|
industrySmartSupplyCheckbox.checked = this.smartSupplyEnabled;
|
|
industryWarehousePanel.appendChild(industrySmartSupplyCheckbox);
|
|
}
|
|
|
|
//Materials
|
|
industryWarehousePanel.appendChild(createElement("p", {
|
|
innerHTML: "<br>Materials:<br>",
|
|
}));
|
|
industryWarehouseMaterials = createElement("ul");
|
|
industryWarehousePanel.appendChild(industryWarehouseMaterials);
|
|
|
|
//Products
|
|
if (industry.makesProducts && Object.keys(industry.products).length > 0) {
|
|
industryWarehousePanel.appendChild(createElement("p", {
|
|
innerHTML: "<br>Products:<br>",
|
|
}));
|
|
industryWarehouseProducts = createElement("ul");
|
|
industryWarehousePanel.appendChild(industryWarehouseProducts);
|
|
}
|
|
|
|
this.updateUI(parentRefs);
|
|
}
|
|
|
|
Warehouse.prototype.updateUI = function(parentRefs) {
|
|
if (parentRefs.company == null || parentRefs.industry == null) {
|
|
console.log("ERROR: Warehouse.updateUI called without parentRefs.company or parentRefs.industry");
|
|
return;
|
|
}
|
|
var company = parentRefs.company, industry = parentRefs.industry;
|
|
|
|
//Storage text
|
|
var storageText = "Storage: " +
|
|
(this.sizedUsed >= this.size ? formatNumber(this.sizeUsed, 3) : formatNumber(this.sizeUsed, 3)) +
|
|
"/" + formatNumber(this.size, 3);
|
|
if (this.breakdown != null && this.breakdown != "") {
|
|
storageText += ("<span class='tooltiptext'>" +
|
|
this.breakdown + "</span>");
|
|
}
|
|
industryWarehouseStorageText.innerHTML = storageText;
|
|
|
|
//Upgrade warehouse size button
|
|
var upgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, this.level+1);
|
|
if (company.funds.lt(upgradeCost)) {
|
|
industryWarehouseUpgradeSizeButton.className = "a-link-button-inactive";
|
|
} else {
|
|
industryWarehouseUpgradeSizeButton.className = "a-link-button";
|
|
}
|
|
|
|
//Current state
|
|
var stateText = "Current state: ";
|
|
switch(industry.state) {
|
|
case "START":
|
|
stateText += "Preparing...";
|
|
break;
|
|
case "PURCHASE":
|
|
stateText += "Purchasing materials...";
|
|
break;
|
|
case "PRODUCTION":
|
|
stateText += "Producing materials and/or products...";
|
|
break;
|
|
case "SALE":
|
|
stateText += "Selling materials and/or products...";
|
|
break;
|
|
case "EXPORT":
|
|
stateText += "Exporting materials and/or products...";
|
|
break;
|
|
default:
|
|
console.log("ERROR: Invalid state: " + industry.state);
|
|
break;
|
|
}
|
|
industryWarehouseStateText.innerText = stateText;
|
|
|
|
//Materials
|
|
removeChildrenFromElement(industryWarehouseMaterials);
|
|
for (var matName in this.materials) {
|
|
if (this.materials.hasOwnProperty(matName) && this.materials[matName] instanceof Material) {
|
|
if (Object.keys(industry.reqMats).includes(matName) || industry.prodMats.includes(matName) ||
|
|
matName === "Hardware" || matName === "Robots" || matName === "AICores" ||
|
|
matName === "RealEstate") {
|
|
industryWarehouseMaterials.appendChild(this.createMaterialUI(this.materials[matName], matName, parentRefs));
|
|
}
|
|
}
|
|
}
|
|
|
|
//Products
|
|
removeChildrenFromElement(industryWarehouseProducts);
|
|
if (industry.makesProducts && Object.keys(industry.products).length > 0) {
|
|
for (var productName in industry.products) {
|
|
if (industry.products.hasOwnProperty(productName) && industry.products[productName] instanceof Product) {
|
|
industryWarehouseProducts.appendChild(this.createProductUI(industry.products[productName], parentRefs));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
|
|
if (parentRefs.company == null || parentRefs.industry == null) {
|
|
console.log("ERROR: Warehouse.createMaterialUI called without industry or company parent refs");
|
|
return;
|
|
}
|
|
var company = parentRefs.company, industry = parentRefs.industry;
|
|
var purchasePopupId = "cmpy-mgmt-material-purchase-popup",
|
|
sellPopupid = "cmpy-mgmt-material-sell-popup";
|
|
var div = createElement("div", {
|
|
class:"cmpy-mgmt-warehouse-material-div",
|
|
});
|
|
|
|
var totalGain = mat.buy + mat.prd + mat.imp - mat.sll - mat.totalExp;
|
|
|
|
//If Market Research upgrades are unlocked, add competition and demand info
|
|
var cmpAndDmdText = "";
|
|
if (company.unlockUpgrades[2] === 1) {
|
|
cmpAndDmdText += "<br>Competition: " + formatNumber(mat.cmp, 3);
|
|
}
|
|
if (company.unlockUpgrades[3] === 1) {
|
|
cmpAndDmdText += "<br>Demand: " + formatNumber(mat.dmd, 3);
|
|
}
|
|
var innerTxt = "<p class='tooltip'>" + mat.name + ": " + formatNumber(mat.qty, 3) +
|
|
"(" + formatNumber(totalGain, 3) + "/s)" +
|
|
"<span class='tooltiptext'>Buy: " + formatNumber(mat.buy, 3) +
|
|
"/s<br>Prod: " + formatNumber(mat.prd, 3) + "/s<br>Sell: " + formatNumber(mat.sll, 3) +
|
|
"/s<br>Export: " + formatNumber(mat.totalExp, 3) + "/s<br>Import: " +
|
|
formatNumber(mat.imp, 3) + "/s" + cmpAndDmdText + "</span></p><br>" +
|
|
"<p class='tooltip'>MP: $" + formatNumber(mat.bCost, 2) +
|
|
"<span class='tooltiptext'>Market Price: The price you would pay if " +
|
|
"you were to buy this material on the market</span></p><br>" +
|
|
"<p class='tooltip'>Quality: " + formatNumber(mat.qlt, 2) +
|
|
"<span class='tooltiptext'>The quality of your material. Higher quality " +
|
|
"will lead to more sales</span></p>";
|
|
|
|
div.appendChild(createElement("p", {
|
|
innerHTML: innerTxt,
|
|
id: "cmpy-mgmt-warehouse-" + matName + "-text", display:"inline-block",
|
|
}));
|
|
|
|
var buttonPanel = createElement("div", {
|
|
display:"inline-block",
|
|
});
|
|
div.appendChild(buttonPanel);
|
|
|
|
//Button to set purchase amount
|
|
var tutorial = industry.newInd && Object.keys(industry.reqMats).includes(mat.name) &&
|
|
mat.buy === 0 && mat.imp === 0;
|
|
var buyButtonParams = {
|
|
innerText: "Buy (" + formatNumber(mat.buy, 3) + ")", display:"inline-block",
|
|
class: tutorial ? "a-link-button flashing-button" : "a-link-button",
|
|
clickListener:()=>{
|
|
var txt = createElement("p", {
|
|
innerHTML: "Enter the amount of " + mat.name + " you would like " +
|
|
"to purchase per second. This material's cost changes constantly"
|
|
});
|
|
var confirmBtn;
|
|
var input = createElement("input", {
|
|
type:"number", value:mat.buy ? mat.buy : null, placeholder: "Purchase amount",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
confirmBtn = createElement("a", {
|
|
innerText:"Confirm", class:"a-link-button",
|
|
clickListener:()=>{
|
|
if (isNaN(input.value)) {
|
|
dialogBoxCreate("Invalid amount");
|
|
} else {
|
|
mat.buy = parseFloat(input.value);
|
|
if (isNaN(mat.buy)) {mat.buy = 0;}
|
|
removeElementById(purchasePopupId);
|
|
this.createUI(parentRefs);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
var clearButton = createElement("a", {
|
|
innerText:"Clear Purchase", class:"a-link-button",
|
|
clickListener:()=>{
|
|
mat.buy = 0;
|
|
removeElementById(purchasePopupId);
|
|
this.createUI(parentRefs);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
innerText:"Cancel", class:"a-link-button",
|
|
clickListener:()=>{
|
|
removeElementById(purchasePopupId);
|
|
}
|
|
});
|
|
createPopup(purchasePopupId, [txt, input, confirmBtn, clearButton, cancelBtn]);
|
|
input.focus();
|
|
}
|
|
};
|
|
if (tutorial) {
|
|
buyButtonParams.tooltip = "Purchase your required materials to get production started!";
|
|
}
|
|
buttonPanel.appendChild(createElement("a", buyButtonParams));
|
|
|
|
//Button to manage exports
|
|
if (company.unlockUpgrades[0] === 1) { //Export unlock upgrade
|
|
function createExportPopup() {
|
|
var popupId = "cmpy-mgmt-export-popup";
|
|
var 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
|
|
var citySelector = createElement("select");
|
|
var industrySelector = createElement("select", {
|
|
changeListener:()=>{
|
|
var industryName = industrySelector.options[industrySelector.selectedIndex].value;
|
|
for (var foo = 0; foo < company.divisions.length; ++foo) {
|
|
if (company.divisions[foo].name == industryName) {
|
|
clearSelector(citySelector);
|
|
var selectedIndustry = company.divisions[foo];
|
|
for (var cityName in company.divisions[foo].warehouses) {
|
|
if (company.divisions[foo].warehouses[cityName] instanceof Warehouse) {
|
|
citySelector.add(createElement("option", {
|
|
value:cityName, text:cityName,
|
|
}));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
for (var i = 0; i < company.divisions.length; ++i) {
|
|
industrySelector.add(createElement("option", {
|
|
text:company.divisions[i].name, value:company.divisions[i].name,
|
|
})); //End create element option
|
|
} //End for
|
|
|
|
var currIndustry = industrySelector.options[industrySelector.selectedIndex].value;
|
|
for (var i = 0; i < company.divisions.length; ++i) {
|
|
if (company.divisions[i].name == currIndustry) {
|
|
for (var cityName in company.divisions[i].warehouses) {
|
|
if (company.divisions[i].warehouses.hasOwnProperty(cityName) &&
|
|
company.divisions[i].warehouses[cityName] instanceof Warehouse) {
|
|
citySelector.add(createElement("option", {
|
|
value:cityName, text:cityName,
|
|
}));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Select amount to export
|
|
var exportAmount = createElement("input", {
|
|
placeholder:"Export amount / s"
|
|
});
|
|
|
|
var exportBtn = createElement("a", {
|
|
class:"a-link-button", display:"inline-block", innerText:"Export",
|
|
clickListener:()=>{
|
|
var industryName = industrySelector.options[industrySelector.selectedIndex].text,
|
|
cityName = citySelector.options[citySelector.selectedIndex].text,
|
|
amt = exportAmount.value;
|
|
//Sanitize amt
|
|
var sanitizedAmt = amt.replace(/\s+/g, '');
|
|
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, '');
|
|
var 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)) {
|
|
dialogBoxCreate("Invalid amount entered for export");
|
|
return;
|
|
}
|
|
var exportObj = {ind:industryName, city:cityName, amt:sanitizedAmt};
|
|
mat.exp.push(exportObj);
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", display:"inline-block", innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
var 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."
|
|
});
|
|
var 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);
|
|
createExportPopup();
|
|
}
|
|
}));
|
|
})(i, mat, currExports);
|
|
}
|
|
createPopup(popupId, [exportTxt, industrySelector, citySelector, exportAmount,
|
|
exportBtn, cancelBtn, currExportsText].concat(currExports));
|
|
}
|
|
buttonPanel.appendChild(createElement("a", {
|
|
innerText:"Export", display:"inline-block", class:"a-link-button",
|
|
clickListener:()=>{createExportPopup();}
|
|
}));
|
|
}
|
|
|
|
buttonPanel.appendChild(createElement("br", {})); // Force line break
|
|
|
|
//Button to set sell amount
|
|
var innerTextString;
|
|
if (mat.sllman[0]) {
|
|
innerTextString = (mat.sllman[1] === -1 ? "Sell (" + formatNumber(mat.sll, 3) + "/MAX)" :
|
|
"Sell (" + formatNumber(mat.sll, 3) + "/" + formatNumber(mat.sllman[1], 3) + ")");
|
|
if (mat.sCost) {
|
|
if (isString(mat.sCost)) {
|
|
var sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
|
innerTextString += " @ $" + formatNumber(eval(sCost), 2);
|
|
} else {
|
|
innerTextString += " @ $" + formatNumber(mat.sCost, 2);
|
|
}
|
|
}
|
|
} else {
|
|
innerTextString = "Sell (0.000/0.000)";
|
|
}
|
|
|
|
buttonPanel.appendChild(createElement("a", {
|
|
innerText: innerTextString, display:"inline-block", class:"a-link-button",
|
|
clickListener:()=>{
|
|
var txt = createElement("p", {
|
|
innerHTML: "Enter the maximum amount of " + mat.name + " you would like " +
|
|
"to sell per second, as well as the price at which you would " +
|
|
"like to sell at.<br><br>" +
|
|
"If the sell amount is set to 0, then the material will not be sold. If the sell price " +
|
|
"if set to 0, then the material will be discarded<br><br>" +
|
|
"Setting the sell amount to 'MAX' will result in you always selling the " +
|
|
"maximum possible amount of the material.<br><br>" +
|
|
"When setting the sell amount, you can use the 'PROD' variable to designate a dynamically " +
|
|
"changing amount that depends on your production. For example, if you set the sell amount " +
|
|
"to 'PROD-5' then you will always sell 5 less of the material than you produce.<br><br>" +
|
|
"When setting the sell price, you can use the 'MP' variable to designate a dynamically " +
|
|
"changing price that depends on the market price. For example, if you set the sell price " +
|
|
"to 'MP+10' then it will always be sold at $10 above the market price.",
|
|
});
|
|
var br = createElement("br", {});
|
|
var confirmBtn;
|
|
var inputQty = createElement("input", {
|
|
type:"text", marginTop:"4px",
|
|
value: mat.sllman[1] ? mat.sllman[1] : null, placeholder: "Sell amount",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
var inputPx = createElement("input", {
|
|
type:"text", marginTop:"4px",
|
|
value: mat.sCost ? mat.sCost : null, placeholder: "Sell price",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
confirmBtn = createElement("a", {
|
|
innerText:"Confirm", class:"a-link-button", margin:"6px",
|
|
clickListener:()=>{
|
|
//Parse price
|
|
var cost = inputPx.value.replace(/\s+/g, '');
|
|
cost = cost.replace(/[^-()\d/*+.MP]/g, ''); //Sanitize cost
|
|
var temp = cost.replace(/MP/g, mat.bCost);
|
|
try {
|
|
temp = eval(temp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
|
return false;
|
|
}
|
|
|
|
if (temp == null || isNaN(temp)) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field");
|
|
return false;
|
|
}
|
|
|
|
if (cost.includes("MP")) {
|
|
mat.sCost = cost; //Dynamically evaluated
|
|
} else {
|
|
mat.sCost = temp;
|
|
}
|
|
|
|
//Parse quantity
|
|
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {
|
|
var qty = inputQty.value.replace(/\s+/g, '');
|
|
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
|
var temp = qty.replace(/MAX/g, 1);
|
|
temp = temp.replace(/PROD/g, 1);
|
|
try {
|
|
temp = eval(temp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
|
return false;
|
|
}
|
|
|
|
if (temp == null || isNaN(temp)) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field");
|
|
return false;
|
|
}
|
|
|
|
mat.sllman[0] = true;
|
|
mat.sllman[1] = qty; //Use sanitized input
|
|
} else if (isNaN(inputQty.value)) {
|
|
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric or 'MAX'");
|
|
return false;
|
|
} else {
|
|
var qty = parseFloat(inputQty.value);
|
|
if (isNaN(qty)) {qty = 0;}
|
|
if (qty === 0) {
|
|
mat.sllman[0] = false;
|
|
mat.sllman[1] = 0;
|
|
} else {
|
|
mat.sllman[0] = true;
|
|
mat.sllman[1] = qty;
|
|
}
|
|
}
|
|
|
|
this.createUI(parentRefs);
|
|
removeElementById(sellPopupid);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
innerText:"Cancel", class:"a-link-button", margin: "6px",
|
|
clickListener:()=>{
|
|
removeElementById(sellPopupid);
|
|
}
|
|
});
|
|
createPopup(sellPopupid, [txt, br, inputQty, inputPx, confirmBtn, cancelBtn]);
|
|
inputQty.focus();
|
|
}
|
|
}));
|
|
|
|
return div;
|
|
}
|
|
|
|
Warehouse.prototype.createProductUI = function(product, parentRefs) {
|
|
var company = parentRefs.company, industry = parentRefs.industry,
|
|
city = currentCityUi;
|
|
var div = createElement("div", {
|
|
class:"cmpy-mgmt-warehouse-product-div"
|
|
});
|
|
|
|
//Products being designed TODO
|
|
if (!product.fin) {
|
|
div.appendChild(createElement("p", {
|
|
innerHTML: "Designing " + product.name + "...<br>" +
|
|
formatNumber(product.prog, 2) + "% complete",
|
|
}));
|
|
return div;
|
|
}
|
|
|
|
//Completed products
|
|
var cmpAndDmdText = "";
|
|
if (company.unlockUpgrades[2] === 1) {
|
|
cmpAndDmdText += "<br>Competition: " + formatNumber(product.cmp, 3);
|
|
}
|
|
if (company.unlockUpgrades[3] === 1) {
|
|
cmpAndDmdText += "<br>Demand: " + formatNumber(product.dmd, 3);
|
|
}
|
|
var totalGain = product.data[city][1] - product.data[city][2]; //Production - sale
|
|
div.appendChild(createElement("p", {
|
|
innerHTML: "<p class='tooltip'>" + product.name + ": " + formatNumber(product.data[city][0], 3) + //Quantity
|
|
"(" + formatNumber(totalGain, 3) + "/s)" +
|
|
"<span class='tooltiptext'>Prod: " + formatNumber(product.data[city][1], 3) + "/s<br>" +
|
|
"Sell: " + formatNumber(product.data[city][2], 3) + "/s</span></p><br>" +
|
|
"<p class='tooltip'>Rating: " + formatNumber(product.rat, 3) +
|
|
"<span class='tooltiptext'>Quality: " + formatNumber(product.qlt, 3) + "<br>" +
|
|
"Performance: " + formatNumber(product.per, 3) + "<br>" +
|
|
"Durability: " + formatNumber(product.dur, 3) + "<br>" +
|
|
"Reliability: " + formatNumber(product.rel, 3) + "<br>" +
|
|
"Aesthetics: " + formatNumber(product.aes, 3) + "<br>" +
|
|
"Features: " + formatNumber(product.fea, 3) +
|
|
cmpAndDmdText + "</span></p><br>" +
|
|
"<p class='tooltip'>Est. Production Cost: " + numeral(product.pCost / ProductProductionCostRatio).format("$0.000a") +
|
|
"<span class='tooltiptext'>An estimate of the material cost it takes to create this Product.</span></p><br>" +
|
|
"<p class='tooltip'>Est. Market Price: " + numeral(product.pCost + product.rat / product.mku).format("$0.000a") +
|
|
"<span class='tooltiptext'>An estimate of how much consumers are willing to pay for this product. " +
|
|
"Setting the sale price above this may result in less sales. Setting the sale price below this may result " +
|
|
"in more sales.</span></p>"
|
|
}));
|
|
var buttonPanel = createElement("div", {
|
|
display:"inline-block",
|
|
});
|
|
div.appendChild(buttonPanel);
|
|
|
|
//Sell button
|
|
var sellInnerTextString = (product.sllman[city][1] === -1 ? "Sell (" + formatNumber(product.data[city][2], 3) + "/MAX)" :
|
|
"Sell (" + formatNumber(product.data[city][2], 3) + "/" + formatNumber(product.sllman[city][1], 3) + ")");
|
|
if (product.sCost) {
|
|
if (isString(product.sCost)) {
|
|
sellInnerTextString += (" @ " + product.sCost);
|
|
} else {
|
|
sellInnerTextString += (" @ " + numeral(product.sCost).format("$0.000a"));
|
|
}
|
|
}
|
|
div.appendChild(createElement("a", {
|
|
innerText:sellInnerTextString, class:"a-link-button", display:"inline-block",margin:"6px",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-sell-product-popup";
|
|
var txt = createElement("p", {
|
|
innerHTML:"Enter the maximum amount of " + product.name + " you would like " +
|
|
"to sell per second, as well as the price at which you would like to " +
|
|
"sell it at.<br><br>" +
|
|
"If the sell amount is set to 0, then the product will not be sold. If the " +
|
|
"sell price is set to 0, then the product will be discarded.<br><br>" +
|
|
"Setting the sell amount to 'MAX' will result in you always selling the " +
|
|
"maximum possible amount of the material.<br><br>" +
|
|
"When setting the sell amount, you can use the 'PROD' variable to designate a " +
|
|
"dynamically changing amount that depends on your production. For example, " +
|
|
"if you set the sell amount to 'PROD-1' then you will always sell 1 less of " +
|
|
"the material than you produce.<br><br>" +
|
|
"When setting the sell price, you can use the 'MP' variable to set a " +
|
|
"dynamically changing price that depends on the Product's estimated " +
|
|
"market price. For example, if you set it to 'MP*5' then it " +
|
|
"will always be sold at five times the estimated market price.",
|
|
});
|
|
var confirmBtn;
|
|
var inputQty = createElement("input", {
|
|
type:"text", value:product.sllman[city][1] ? product.sllman[city][1] : null, placeholder: "Sell amount",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
var inputPx = createElement("input", {
|
|
type:"text", value: product.sCost ? product.sCost : null, placeholder: "Sell price",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
confirmBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Confirm",
|
|
clickListener:()=>{
|
|
//Parse price
|
|
if (inputPx.value.includes("MP")) {
|
|
//Dynamically evaluated quantity. First test to make sure its valid
|
|
//Sanitize input, then replace dynamic variables with arbitrary numbers
|
|
var price = inputPx.value.replace(/\s+/g, '');
|
|
price = price.replace(/[^-()\d/*+.MP]/g, '');
|
|
var temp = price.replace(/MP/g, 1);
|
|
try {
|
|
temp = eval(temp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Invalid value or expression for sell quantity field: " + e);
|
|
return false;
|
|
}
|
|
if (temp == null || isNaN(temp)) {
|
|
dialogBoxCreate("Invalid value or expression for sell quantity field.");
|
|
return false;
|
|
}
|
|
product.sCost = price; //Use sanitized price
|
|
} else {
|
|
var cost = parseFloat(inputPx.value);
|
|
if (isNaN(cost)) {
|
|
dialogBoxCreate("Invalid value for sell price field");
|
|
return false;
|
|
}
|
|
product.sCost = cost;
|
|
}
|
|
|
|
//Parse quantity
|
|
if (inputQty.value.includes("MAX") || inputQty.value.includes("PROD")) {
|
|
//Dynamically evaluated quantity. First test to make sure its valid
|
|
var qty = inputQty.value.replace(/\s+/g, '');
|
|
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, '');
|
|
var temp = qty.replace(/MAX/g, 1);
|
|
temp = temp.replace(/PROD/g, 1);
|
|
try {
|
|
temp = eval(temp);
|
|
} catch(e) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field: " + e);
|
|
return false;
|
|
}
|
|
|
|
if (temp == null || isNaN(temp)) {
|
|
dialogBoxCreate("Invalid value or expression for sell price field");
|
|
return false;
|
|
}
|
|
product.sllman[city][0] = true;
|
|
product.sllman[city][1] = qty; //Use sanitized input
|
|
} else if (isNaN(inputQty.value)) {
|
|
dialogBoxCreate("Invalid value for sell quantity field! Must be numeric");
|
|
return false;
|
|
} else {
|
|
var qty = parseFloat(inputQty.value);
|
|
if (isNaN(qty)) {qty = 0;}
|
|
if (qty === 0) {
|
|
product.sllman[city][0] = false;
|
|
} else {
|
|
product.sllman[city][0] = true;
|
|
product.sllman[city][1] = qty;
|
|
}
|
|
}
|
|
this.createUI(parentRefs);
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, inputQty, inputPx, confirmBtn, cancelBtn]);
|
|
inputQty.focus();
|
|
}
|
|
}));
|
|
div.appendChild(createElement("br",{})); //force line break
|
|
|
|
//Limit production button
|
|
var limitProductionInnerText = "Limit Production";
|
|
if (product.prdman[city][0]) {
|
|
limitProductionInnerText += " (" + formatNumber(product.prdman[city][1], 3) + ")";
|
|
}
|
|
div.appendChild(createElement("a", {
|
|
class:"a-link-button", innerText:limitProductionInnerText,display:"inline-block",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-limit-product-production-popup";
|
|
var 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."
|
|
});
|
|
var confirmBtn;
|
|
var input = createElement("input", {
|
|
type:"number", placeholder:"Limit",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
confirmBtn = createElement("a", {
|
|
class:"a-link-button", display:"inline-block", innerText:"Limit production", margin:'6px',
|
|
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);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", display:"inline-block", innerText:"Cancel", margin:"6px",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, input, confirmBtn, cancelBtn]);
|
|
}
|
|
}));
|
|
|
|
//Discontinue button
|
|
div.appendChild(createElement("a", {
|
|
class:'a-link-button', display:"inline-block",innerText:"Discontinue",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-discontinue-product-popup";
|
|
var txt = createElement("p", {
|
|
innerText:"Are you sure you want to do this? Discontinuing a product " +
|
|
"removes it completely and permanently. You will no longer " +
|
|
"produce this product and all of its existing stock will be " +
|
|
"removed and left unsold",
|
|
});
|
|
var confirmBtn = createElement("a", {
|
|
class:"a-link-button",innerText:"Discontinue",
|
|
clickListener:()=>{
|
|
industry.discontinueProduct(product, parentRefs);
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, confirmBtn, cancelBtn]);
|
|
}
|
|
}));
|
|
return div;
|
|
}
|
|
|
|
Warehouse.prototype.toJSON = function() {
|
|
return Generic_toJSON("Warehouse", this);
|
|
}
|
|
|
|
Warehouse.fromJSON = function(value) {
|
|
return Generic_fromJSON(Warehouse, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Warehouse = Warehouse;
|
|
|
|
//Corporation Unlock Upgrades
|
|
//Upgrades for entire corporation, unlocks features, either you have it or you dont
|
|
//The structure is [index in Corporation feature upgrades array, price ]
|
|
var CorporationUnlockUpgrades = {
|
|
//Lets you export goods
|
|
"0": [0, 20e9, "Export",
|
|
"Develop infrastructure to export your materials to your other facilities. " +
|
|
"This allows you to move materials around between different divisions and cities."],
|
|
|
|
//Lets you buy exactly however many required materials you need for production
|
|
"1": [1, 50e9, "Smart Supply", "Use advanced AI to anticipate your supply needs. " +
|
|
"This allows you to purchase exactly however many materials you need for production."],
|
|
|
|
//Displays each material/product's demand
|
|
"2": [2, 5e9, "Market Research - Demand",
|
|
"Mine and analyze market data to determine the demand of all resources. " +
|
|
"The demand attribute, which affects sales, will be displayed for every material and product."],
|
|
|
|
//Display's each material/product's competition
|
|
"3": [3, 5e9, "Market Data - Competition",
|
|
"Mine and analyze market data to determine how much competition there is on the market " +
|
|
"for all resources. The competition attribute, which affects sales, will be displayed for " +
|
|
"for every material and product."],
|
|
"4": [4, 10e9, "VeChain",
|
|
"Use AI and blockchain technology to identify where you can improve your supply chain systems. " +
|
|
"This upgrade will allow you to view a wide array of useful statistics about your " +
|
|
"Corporation."]
|
|
}
|
|
|
|
//Corporation Upgrades
|
|
//Upgrades for entire corporation, levelable upgrades
|
|
//The structure is [index in Corporation upgrades array, base price, price mult, benefit mult (additive),
|
|
// name, desc]
|
|
var CorporationUpgrades = {
|
|
//Smart factories, increases production
|
|
"0": [0, 2e9, 1.07, 0.03,
|
|
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
|
|
"of factories. Each level of this upgrade increases your global production by 3% (additive)."],
|
|
|
|
//Smart warehouses, increases storage size
|
|
"1": [1, 2e9, 1.07, .1,
|
|
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
|
|
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
|
|
|
|
//Advertise through dreams, passive popularity/ awareness gain
|
|
"2": [2, 8e9, 1.09, .001,
|
|
"DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " +
|
|
"to consumers through their dreams. Each level of this upgrade provides a passive " +
|
|
"increase in awareness of all of your companies (divisions) by 0.004 / market cycle," +
|
|
"and in popularity by 0.001 / market cycle. A market cycle is approximately " +
|
|
"20 seconds."],
|
|
|
|
//Makes advertising more effective
|
|
"3": [3, 4e9, 1.12, 0.005,
|
|
"Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " +
|
|
"firm. Each level of this upgrades increases the effectiveness of your " +
|
|
"advertising by 0.5% (additive)."],
|
|
|
|
//Augmentation for employees, increases cre
|
|
"4": [4, 1e9, 1.06, 0.1,
|
|
"Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " +
|
|
"Injector augmentation for your employees. Each level of this upgrade " +
|
|
"globally increases the creativity of your employees by 10% (additive)."],
|
|
|
|
//Augmentation for employees, increases cha
|
|
"5": [5, 1e9, 1.06, 0.1,
|
|
"Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " +
|
|
"Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."],
|
|
|
|
//Augmentation for employees, increases int
|
|
"6": [6, 1e9, 1.06, 0.1,
|
|
"Neural Accelerators", "Purchase the Neural Accelerator augmentation for your employees. " +
|
|
"Each level of this upgrade globally increases the intelligence of your employees " +
|
|
"by 10% (additive)."],
|
|
|
|
//Augmentation for employees, increases eff
|
|
"7": [7, 1e9, 1.06, 0.1,
|
|
"FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " +
|
|
"of this upgrade globally increases the efficiency of your employees by 10% (additive)."],
|
|
|
|
//Improves sales of materials/products
|
|
"8": [8, 1e9, 1.08, 0.01,
|
|
"ABC SalesBots", "Always Be Closing. Purchase these robotic salesmen to increase the amount of " +
|
|
"materials and products you sell. Each level of this upgrade globally increases your sales " +
|
|
"by 1% (additive)."],
|
|
|
|
//Improves scientific research rate
|
|
"9": [9, 5e9, 1.07, 0.05,
|
|
"Project Insight", "Purchase 'Project Insight', a R&D service provided by the secretive " +
|
|
"Fulcrum Technologies. Each level of this upgrade globally increases the amount of " +
|
|
"Scientific Research you produce by 5% (additive)."],
|
|
}
|
|
|
|
function Corporation(params={}) {
|
|
this.name = params.name ? params.name : "The Corporation";
|
|
|
|
//A division/business sector is represented by the object:
|
|
this.divisions = [];
|
|
|
|
//Financial stats
|
|
this.funds = new Decimal(150e9);
|
|
this.revenue = new Decimal(0);
|
|
this.expenses = new Decimal(0);
|
|
this.fundingRound = 0;
|
|
this.public = false; //Publicly traded
|
|
this.numShares = TOTALSHARES;
|
|
this.issuedShares = 0;
|
|
this.sharePrice = 0;
|
|
this.storedCycles = 0;
|
|
|
|
var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length,
|
|
numUpgrades = Object.keys(CorporationUpgrades).length;
|
|
|
|
this.unlockUpgrades = Array(numUnlockUpgrades).fill(0);
|
|
this.upgrades = Array(numUpgrades).fill(0);
|
|
this.upgradeMultipliers = Array(numUpgrades).fill(1);
|
|
|
|
this.state = new CorporationState();
|
|
}
|
|
|
|
Corporation.prototype.getState = function() {
|
|
return this.state.getState();
|
|
}
|
|
|
|
Corporation.prototype.storeCycles = function(numCycles=1) {
|
|
this.storedCycles += numCycles;
|
|
}
|
|
|
|
Corporation.prototype.process = function() {
|
|
var corp = this;
|
|
if (this.storedCycles >= CyclesPerIndustryStateCycle) {
|
|
var state = this.getState(), marketCycles=1;
|
|
this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle);
|
|
|
|
//At the start of a new cycle, calculate profits from previous cycle
|
|
if (state === "START") {
|
|
this.revenue = new Decimal(0);
|
|
this.expenses = new Decimal(0);
|
|
this.divisions.forEach((ind)=>{
|
|
this.revenue = this.revenue.plus(ind.lastCycleRevenue);
|
|
this.expenses = this.expenses.plus(ind.lastCycleExpenses);
|
|
});
|
|
var profit = this.revenue.minus(this.expenses);
|
|
var cycleProfit = profit.times(marketCycles * SecsPerMarketCycle);
|
|
if (isNaN(this.funds)) {
|
|
dialogBoxCreate("There was an error calculating your Corporations funds and they got reset to 0. " +
|
|
"This is a bug. Please report to game developer.<br><br>" +
|
|
"(Your funds have been set to $150b for the inconvenience)");
|
|
this.funds = new Decimal(150e9);
|
|
}
|
|
this.funds = this.funds.plus(cycleProfit);
|
|
this.updateSharePrice();
|
|
}
|
|
|
|
this.divisions.forEach(function(ind) {
|
|
ind.process(marketCycles, state, corp);
|
|
});
|
|
|
|
|
|
this.state.nextState();
|
|
|
|
if (Engine.currentPage === Engine.Page.Corporation) {this.updateUIContent();}
|
|
}
|
|
}
|
|
|
|
Corporation.prototype.determineValuation = function() {
|
|
var val, profit = (this.revenue.minus(this.expenses)).toNumber();
|
|
if (this.public) {
|
|
val = this.funds.toNumber() + (profit * 85e3);
|
|
val *= (Math.pow(1.1, this.divisions.length));
|
|
val = Math.max(val, 0);
|
|
} else {
|
|
val = 10e9 + Math.max(this.funds.toNumber(), 0) / 3; //Base valuation
|
|
if (profit > 0) {
|
|
val += (profit * 320e3);
|
|
val *= (Math.pow(1.1, this.divisions.length));
|
|
} else {
|
|
val = 10e9 * Math.pow(1.1, this.divisions.length);
|
|
}
|
|
val -= (val % 1e6); //Round down to nearest millionth
|
|
}
|
|
return val * BitNodeMultipliers.CorporationValuation;
|
|
}
|
|
|
|
Corporation.prototype.getInvestment = function() {
|
|
var val = this.determineValuation(), percShares;
|
|
switch (this.fundingRound) {
|
|
case 0: //Seed
|
|
percShares = 0.10;
|
|
break;
|
|
case 1: //Series A
|
|
percShares = 0.35;
|
|
break;
|
|
case 2: //Series B
|
|
percShares = 0.25;
|
|
break;
|
|
case 3: //Series C
|
|
percShares = 0.20;
|
|
break;
|
|
case 4:
|
|
return;
|
|
}
|
|
var funding = val * percShares * 4,
|
|
investShares = Math.floor(TOTALSHARES * percShares),
|
|
yesBtn = yesNoBoxGetYesButton(),
|
|
noBtn = yesNoBoxGetNoButton();
|
|
yesBtn.innerHTML = "Accept";
|
|
noBtn.innerHML = "Reject";
|
|
yesBtn.addEventListener("click", ()=>{
|
|
++this.fundingRound;
|
|
this.funds = this.funds.plus(funding);
|
|
this.numShares -= investShares;
|
|
this.displayCorporationOverviewContent();
|
|
return yesNoBoxClose();
|
|
});
|
|
noBtn.addEventListener("click", ()=>{
|
|
return yesNoBoxClose();
|
|
});
|
|
yesNoBoxCreate("An investment firm has offered you " + numeral(funding).format('$0.000a') +
|
|
" in funding in exchange for a " + numeral(percShares*100).format("0.000a") +
|
|
"% stake in the company (" + numeral(investShares).format('0.000a') + " shares).<br><br>" +
|
|
"Do you accept or reject this offer?");
|
|
}
|
|
|
|
Corporation.prototype.goPublic = function() {
|
|
var goPublicPopupId = "cmpy-mgmt-go-public-popup";
|
|
var initialSharePrice = this.determineValuation() / (TOTALSHARES);
|
|
var txt = createElement("p", {
|
|
innerHTML: "Enter the number of shares you would like to issue " +
|
|
"for your IPO. These shares will be publicly sold " +
|
|
"and you will no longer own them. Your Corporation will receive " +
|
|
numeral(initialSharePrice).format('$0.000a') + " per share " +
|
|
"(the IPO money will be deposited directly into your Corporation's funds).<br><br>" +
|
|
"Furthermore, issuing more shares now will help drive up " +
|
|
"your company's stock price in the future.<br><br>" +
|
|
"You have a total of " + numeral(this.numShares).format("0.000a") + " of shares that you can issue.",
|
|
});
|
|
var yesBtn;
|
|
var input = createElement("input", {
|
|
type:"number",
|
|
placeholder: "Shares to issue",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {yesBtn.click();}
|
|
}
|
|
});
|
|
var br = createElement("br", {});
|
|
yesBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Go Public",
|
|
clickListener:()=>{
|
|
var numShares = Math.round(input.value);
|
|
var initialSharePrice = this.determineValuation() / (TOTALSHARES);
|
|
if (isNaN(numShares)) {
|
|
dialogBoxCreate("Invalid value for number of issued shares");
|
|
return false;
|
|
}
|
|
if (numShares > this.numShares) {
|
|
dialogBoxCreate("Error: You don't have that many shares to issue!");
|
|
return false;
|
|
}
|
|
this.public = true;
|
|
this.sharePrice = initialSharePrice;
|
|
this.issuedShares = numShares;
|
|
this.numShares -= numShares;
|
|
this.funds = this.funds.plus(numShares * initialSharePrice);
|
|
this.displayCorporationOverviewContent();
|
|
removeElementById(goPublicPopupId);
|
|
return false;
|
|
}
|
|
});
|
|
var noBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(goPublicPopupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(goPublicPopupId, [txt, br, input, yesBtn, noBtn]);
|
|
}
|
|
|
|
Corporation.prototype.updateSharePrice = function() {
|
|
var targetPrice = this.determineValuation() / (TOTALSHARES - this.issuedShares);
|
|
if (this.sharePrice <= targetPrice) {
|
|
this.sharePrice *= (1 + (Math.random() * 0.01));
|
|
} else {
|
|
this.sharePrice *= (1 - (Math.random() * 0.01));
|
|
}
|
|
if (this.sharePrice <= 0.01) {this.sharePrice = 0.01;}
|
|
}
|
|
|
|
//One time upgrades that unlock new features
|
|
Corporation.prototype.unlock = function(upgrade) {
|
|
var upgN = upgrade[0], price = upgrade[1];
|
|
while (this.unlockUpgrades.length <= upgN) {
|
|
this.unlockUpgrades.push(0);
|
|
}
|
|
if (this.funds.lt(price)) {
|
|
dialogBoxCreate("You don't have enough funds to unlock this!");
|
|
return;
|
|
}
|
|
this.unlockUpgrades[upgN] = 1;
|
|
this.funds = this.funds.minus(price);
|
|
}
|
|
|
|
//Levelable upgrades
|
|
Corporation.prototype.upgrade = function(upgrade) {
|
|
var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2],
|
|
upgradeAmt = upgrade[3]; //Amount by which the upgrade multiplier gets increased (additive)
|
|
while (this.upgrades.length <= upgN) {this.upgrades.push(0);}
|
|
while (this.upgradeMultipliers.length <= upgN) {this.upgradeMultipliers.push(1);}
|
|
var totalCost = basePrice * Math.pow(priceMult, this.upgrades[upgN]);
|
|
if (this.funds.lt(totalCost)) {
|
|
dialogBoxCreate("You don't have enough funds to purchase this!");
|
|
return;
|
|
}
|
|
++this.upgrades[upgN];
|
|
this.funds = this.funds.minus(totalCost);
|
|
|
|
//Increase upgrade multiplier
|
|
this.upgradeMultipliers[upgN] = 1 + (this.upgrades[upgN] * upgradeAmt);
|
|
|
|
//If storage size is being updated, update values in Warehouse objects
|
|
if (upgN === 1) {
|
|
for (var i = 0; i < this.divisions.length; ++i) {
|
|
var industry = this.divisions[i];
|
|
for (var city in industry.warehouses) {
|
|
if (industry.warehouses.hasOwnProperty(city) && industry.warehouses[city] instanceof Warehouse) {
|
|
industry.warehouses[city].updateSize(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.updateCorporationOverviewContent();
|
|
}
|
|
|
|
Corporation.prototype.getProductionMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[0];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getStorageMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[1];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getDreamSenseGain = function() {
|
|
var gain = this.upgradeMultipliers[2] - 1;
|
|
return gain <= 0 ? 0 : gain;
|
|
}
|
|
|
|
Corporation.prototype.getAdvertisingMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[3];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getEmployeeCreMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[4];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getEmployeeChaMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[5];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getEmployeeIntMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[6];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getEmployeeEffMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[7];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getSalesMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[8];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
Corporation.prototype.getScientificResearchMultiplier = function() {
|
|
var mult = this.upgradeMultipliers[9];
|
|
if (isNaN(mult) || mult < 1) {return 1;} else {return mult;}
|
|
}
|
|
|
|
//Keep 'global' variables for DOM elements so we don't have to search
|
|
//through the DOM tree repeatedly when updating UI
|
|
var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel,
|
|
currentCityUi,
|
|
corporationUnlockUpgrades, corporationUpgrades,
|
|
|
|
//Industry Overview Panel
|
|
industryOverviewPanel, industryOverviewText,
|
|
|
|
//Industry Employee Panel
|
|
industryEmployeePanel, industryEmployeeText, industryEmployeeHireButton, industryEmployeeAutohireButton,
|
|
industryEmployeeManagementUI, industryEmployeeInfo, industryIndividualEmployeeInfo,
|
|
industryOfficeUpgradeSizeButton,
|
|
|
|
//Industry Warehouse Panel
|
|
industryWarehousePanel, industrySmartSupplyCheckbox, industryWarehouseStorageText,
|
|
industryWarehouseUpgradeSizeButton, industryWarehouseStateText,
|
|
industryWarehouseMaterials, industryWarehouseProducts,
|
|
headerTabs, cityTabs;
|
|
Corporation.prototype.createUI = function() {
|
|
companyManagementDiv = createElement("div", {
|
|
id:"cmpy-mgmt-container",
|
|
position:"fixed",
|
|
class:"generic-menupage-container"
|
|
});
|
|
companyManagementHeaderTabs = createElement("div", {id:"cmpy-mgmt-header-tabs"});
|
|
companyManagementDiv.appendChild(companyManagementHeaderTabs);
|
|
|
|
//Create division/industry tabs at the top
|
|
this.updateUIHeaderTabs();
|
|
|
|
//Create the 'panel' that will have the actual content in the UI
|
|
companyManagementPanel = createElement("div", {id:"cmpy-mgmt-panel"});
|
|
companyManagementDiv.appendChild(companyManagementPanel);
|
|
document.getElementById("entire-game-container").appendChild(companyManagementDiv);
|
|
|
|
this.displayCorporationOverviewContent();
|
|
}
|
|
|
|
Corporation.prototype.updateUIHeaderTabs = function() {
|
|
if (companyManagementHeaderTabs) {
|
|
removeChildrenFromElement(companyManagementHeaderTabs);
|
|
} else {
|
|
console.log("ERROR: Header tabs div has not yet been created when Corporation.updateUIHeaderTabs() is called");
|
|
return;
|
|
}
|
|
|
|
//Corporation overview tabs
|
|
var cmpyOverviewHdrTab = createElement("button", {
|
|
id:"cmpy-mgmt-company-tab",
|
|
class:"cmpy-mgmt-header-tab",
|
|
innerText:this.name,
|
|
checked:true,
|
|
clickListener:()=>{
|
|
this.selectHeaderTab(cmpyOverviewHdrTab);
|
|
this.displayCorporationOverviewContent();
|
|
return false;
|
|
}
|
|
});
|
|
companyManagementHeaderTabs.appendChild(cmpyOverviewHdrTab);
|
|
|
|
//Tabs for each division
|
|
for (var i = 0; i < this.divisions.length; ++i) {
|
|
this.createDivisionUIHeaderTab(this.divisions[i]);
|
|
}
|
|
|
|
//Create a tab to expand into a new industry
|
|
companyManagementHeaderTabs.appendChild(createElement("button", {
|
|
id:'cmpy-mgmt-expand-industry-tab',
|
|
class:"cmpy-mgmt-header-tab",
|
|
innerText:"Expand into new Industry",
|
|
clickListener: ()=>{
|
|
if (document.getElementById("cmpy-mgmt-expand-industry-popup") != null) {return;}
|
|
|
|
var container = createElement("div", {
|
|
class:"popup-box-container",
|
|
id:"cmpy-mgmt-expand-industry-popup",
|
|
});
|
|
var content = createElement("div", {class:"popup-box-content"});
|
|
var txt = createElement("p", {
|
|
innerHTML: "Create a new division to expand into a new industry:",
|
|
});
|
|
var selector = createElement("select", {
|
|
class:"cmpy-mgmt-industry-select"
|
|
});
|
|
var industryDescription = createElement("p", {});
|
|
var yesBtn;
|
|
var nameInput = createElement("input", {
|
|
type:"text",
|
|
id:"cmpy-mgmt-expand-industry-name-input",
|
|
color:"white",
|
|
backgroundColor:"black",
|
|
display:"block",
|
|
maxLength: 30,
|
|
pattern:"[a-zA-Z0-9-_]",
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {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: ()=>{
|
|
var ind = selector.options[selector.selectedIndex].value,
|
|
newDivisionName = nameInput.value;
|
|
|
|
for (var i = 0; i < this.divisions.length; ++i) {
|
|
if (this.divisions[i].name === newDivisionName) {
|
|
dialogBoxCreate("This name is already in use!");
|
|
return false;
|
|
}
|
|
}
|
|
if (this.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.funds = this.funds.minus(IndustryStartingCosts[ind]);
|
|
var newInd = new Industry({
|
|
name:newDivisionName,
|
|
type:ind,
|
|
});
|
|
this.divisions.push(newInd);
|
|
this.updateUIHeaderTabs();
|
|
this.selectHeaderTab(headerTabs[headerTabs.length-2]);
|
|
removeElementById("cmpy-mgmt-expand-industry-popup");
|
|
this.displayDivisionContent(newInd, Locations.Sector12);
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
var noBtn = createElement("span", {
|
|
class:"popup-box-button",
|
|
innerText:"Cancel",
|
|
clickListener: function() {
|
|
removeElementById("cmpy-mgmt-expand-industry-popup");
|
|
return false;
|
|
}
|
|
});
|
|
|
|
//Make an object to keep track of what industries you're already in
|
|
var ownedIndustries = {}
|
|
for (var i = 0; i < this.divisions.length; ++i) {
|
|
ownedIndustries[this.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
|
|
content.appendChild(txt);
|
|
content.appendChild(selector);
|
|
content.appendChild(industryDescription);
|
|
content.appendChild(nameLabel);
|
|
content.appendChild(nameInput);
|
|
content.appendChild(noBtn);
|
|
content.appendChild(yesBtn);
|
|
container.appendChild(content);
|
|
document.getElementById("entire-game-container").appendChild(container);
|
|
container.style.display = "block";
|
|
return false;
|
|
}
|
|
}));
|
|
|
|
headerTabs = companyManagementDiv.getElementsByClassName("cmpy-mgmt-header-tab");
|
|
}
|
|
|
|
//Updates UI to display which header tab is selected
|
|
Corporation.prototype.selectHeaderTab = function(currentTab) {
|
|
if (currentTab == null) {return;}
|
|
for (var i = 0; i < headerTabs.length; ++i) {
|
|
headerTabs[i].className = "cmpy-mgmt-header-tab";
|
|
}
|
|
currentTab.className = "cmpy-mgmt-header-tab current";
|
|
}
|
|
|
|
Corporation.prototype.createDivisionUIHeaderTab = function(division) {
|
|
var tabId = "cmpy-mgmt-" + division.name + "-tab";
|
|
var tab = createElement("button", {
|
|
id:tabId,
|
|
class:"cmpy-mgmt-header-tab",
|
|
innerText:division.name,
|
|
clickListener:()=>{
|
|
this.selectHeaderTab(tab);
|
|
this.displayDivisionContent(division, Locations.Sector12);
|
|
return false;
|
|
}
|
|
});
|
|
companyManagementHeaderTabs.appendChild(tab);
|
|
}
|
|
|
|
Corporation.prototype.clearUIPanel = function() {
|
|
while(companyManagementPanel.firstChild) {
|
|
companyManagementPanel.removeChild(companyManagementPanel.firstChild);
|
|
}
|
|
}
|
|
|
|
Corporation.prototype.updateUIContent = function() {
|
|
//Check which of the header tab buttons is checked
|
|
if (headerTabs == null) {
|
|
console.log("ERROR: headerTabs is null in Corporation.updateUIContent()");
|
|
return;
|
|
}
|
|
for (var i = 0; i < headerTabs.length; ++i) {
|
|
if (headerTabs[i].classList.contains("current")) {
|
|
if (i === 0) {
|
|
//Corporation overview
|
|
this.updateCorporationOverviewContent();
|
|
} else {
|
|
//Division
|
|
this.updateDivisionContent(this.divisions[i-1]);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Corporation.prototype.displayCorporationOverviewContent = function() {
|
|
this.clearUIPanel();
|
|
companyManagementPanel.appendChild(createElement("p", {
|
|
id:"cmpy-mgmt-overview-text",
|
|
}));
|
|
if (headerTabs && headerTabs.length >= 1) {
|
|
this.selectHeaderTab(headerTabs[0]);
|
|
}
|
|
|
|
//Check if player has Corporation Handbook
|
|
var homeComp = Player.getHomeComputer(), hasHandbook = false,
|
|
handbookFn = "corporation-management-handbook.lit";
|
|
for (var i = 0; i < homeComp.messages.length; ++i) {
|
|
if (isString(homeComp.messages[i]) && homeComp.messages[i] === handbookFn) {
|
|
hasHandbook = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
companyManagementPanel.appendChild(createElement("a", {
|
|
class:"a-link-button", innerText:"Getting Started Guide", display:"inline-block",
|
|
tooltip:"Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " +
|
|
"This is a .lit file that guides you through the beginning of setting up a Corporation and " +
|
|
"provides some tips/pointers for helping you get started with managing it.",
|
|
clickListener:()=>{
|
|
if (!hasHandbook) {homeComp.messages.push(handbookFn);}
|
|
showLiterature(handbookFn);
|
|
return false;
|
|
}
|
|
}));
|
|
|
|
//Investors
|
|
if (this.public) {
|
|
//Sell share buttons
|
|
var sellShares = createElement("a", {
|
|
class:"a-link-button", innerText:"Sell Shares", display:"inline-block",
|
|
tooltip:"Sell your shares in the company. This is the only way to " +
|
|
"profit from your business venture.",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-sell-shares-popup";
|
|
var currentStockPrice = this.sharePrice;
|
|
var txt = createElement("p", {
|
|
innerHTML: "Enter the number of shares you would like to sell. The money from " +
|
|
"selling your shares will go directly to you (NOT your Corporation). " +
|
|
"The current price of your " +
|
|
"company's stock is " + numeral(currentStockPrice).format("$0.000a"),
|
|
});
|
|
var profitIndicator = createElement("p", {});
|
|
var input = createElement("input", {
|
|
type:"number", placeholder:"Shares to sell", margin:"5px",
|
|
inputListener: ()=> {
|
|
var numShares = Math.round(input.value);
|
|
if (isNaN(numShares) || numShares <= 0) {
|
|
profitIndicator.innerText = "ERROR: Invalid value entered for number of shares to sell"
|
|
} else if (numShares > this.numShares) {
|
|
profitIndicator.innerText = "You don't have this many shares to sell!";
|
|
} else {
|
|
profitIndicator.innerText = "Sell " + numShares + " shares for a total of " +
|
|
numeral(numShares * currentStockPrice).format('$0.000a');
|
|
}
|
|
}
|
|
});
|
|
var confirmBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Sell shares", display:"inline-block",
|
|
clickListener:()=>{
|
|
var shares = Math.round(input.value);
|
|
if (isNaN(shares) || shares <= 0) {
|
|
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
|
} else if (shares > this.numShares) {
|
|
dialogBoxCreate("ERROR: You don't have this many shares to sell");
|
|
} else {
|
|
this.numShares -= shares;
|
|
if (isNaN(this.issuedShares)) {
|
|
console.log("ERROR: Corporation issuedShares is NaN: " + this.issuedShares);
|
|
console.log("Converting to number now");
|
|
var res = parseInt(this.issuedShares);
|
|
if (isNaN(res)) {
|
|
this.issuedShares = 0;
|
|
} else {
|
|
this.issuedShares = res;
|
|
}
|
|
}
|
|
this.issuedShares += shares;
|
|
Player.gainMoney(shares * this.sharePrice);
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Cancel", display:"inline-block",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, profitIndicator, input, confirmBtn, cancelBtn]);
|
|
}
|
|
});
|
|
|
|
//Buyback shares button
|
|
var buybackShares = createElement("a", {
|
|
class:"a-link-button", innerText:"Buyback shares", display:"inline-block",
|
|
tooltip:"Buy back shares you that previously issued or sold at market price.",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-buyback-shares-popup";
|
|
var currentStockPrice = this.sharePrice;
|
|
var txt = createElement("p", {
|
|
innerHTML: "Enter the number of shares you would like to buy back at market price. To purchase " +
|
|
"these shares, you must use your own money (NOT your Corporation's funds). " +
|
|
"The current price of your " +
|
|
"company's stock is " + numeral(currentStockPrice).format("$0.000a") +
|
|
". Your company currently has " + formatNumber(this.issuedShares, 3) + " outstanding stock shares",
|
|
});
|
|
var costIndicator = createElement("p", {});
|
|
var input = createElement("input", {
|
|
type:"number", placeholder:"Shares to buyback", margin:"5px",
|
|
inputListener: ()=> {
|
|
var numShares = Math.round(input.value);
|
|
//TODO add conditional for if player doesn't have enough money
|
|
if (isNaN(numShares) || numShares <= 0) {
|
|
costIndicator.innerText = "ERROR: Invalid value entered for number of shares to buyback"
|
|
} else if (numShares > this.issuedShares) {
|
|
costIndicator.innerText = "There are not this many shares available to buy back. " +
|
|
"There are only " + this.issuedShares + " outstanding shares.";
|
|
} else {
|
|
console.log("here");
|
|
costIndicator.innerText = "Purchase " + numShares + " shares for a total of " +
|
|
numeral(numShares * currentStockPrice).format('$0.000a');
|
|
}
|
|
}
|
|
});
|
|
var confirmBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Buy shares", display:"inline-block",
|
|
clickListener:()=>{
|
|
var shares = Math.round(input.value);
|
|
var tempStockPrice = this.sharePrice;
|
|
if (isNaN(shares) || shares <= 0) {
|
|
dialogBoxCreate("ERROR: Invalid value for number of shares");
|
|
} else if (shares > this.issuedShares) {
|
|
dialogBoxCreate("ERROR: There are not this many oustanding shares to buy back");
|
|
} else if (shares * tempStockPrice > Player.money) {
|
|
dialogBoxCreate("ERROR: You do not have enough money to purchase this many shares (you need " +
|
|
numeral(shares * tempStockPrice).format("$0.000a") + ")");
|
|
} else {
|
|
this.numShares += shares;
|
|
if (isNaN(this.issuedShares)) {
|
|
console.log("ERROR: Corporation issuedShares is NaN: " + this.issuedShares);
|
|
console.log("Converting to number now");
|
|
var res = parseInt(this.issuedShares);
|
|
if (isNaN(res)) {
|
|
this.issuedShares = 0;
|
|
} else {
|
|
this.issuedShares = res;
|
|
}
|
|
}
|
|
this.issuedShares -= shares;
|
|
Player.loseMoney(shares * tempStockPrice);
|
|
//TODO REMOVE from Player money
|
|
removeElementById(popupId);
|
|
}
|
|
return false;
|
|
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Cancel",
|
|
display:"inline-block",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, costIndicator, input, confirmBtn, cancelBtn]);
|
|
}
|
|
});
|
|
|
|
companyManagementPanel.appendChild(sellShares);
|
|
companyManagementPanel.appendChild(buybackShares);
|
|
|
|
//If your Corporation is big enough, buy faction influence through bribes
|
|
var canBribe = this.determineValuation() >= BribeThreshold;
|
|
var bribeFactions = createElement("a", {
|
|
class: canBribe ? "a-link-button" : "a-link-button-inactive",
|
|
innerText:"Bribe Factions", display:"inline-block",
|
|
tooltip:canBribe
|
|
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
|
|
: "Your Corporation is not powerful enough to bribe Faction leaders",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-bribe-factions-popup";
|
|
var txt = createElement("p", {
|
|
innerText:"You can use Corporation funds or stock shares to bribe Faction Leaders in exchange for faction reputation"
|
|
});
|
|
var factionSelector = createElement("select", {margin:"3px"});
|
|
for (var i = 0; i < Player.factions.length; ++i) {
|
|
var facName = Player.factions[i];
|
|
factionSelector.add(createElement("option", {
|
|
text:facName, value:facName
|
|
}));
|
|
}
|
|
var repGainText = createElement("p");
|
|
var stockSharesInput;
|
|
var moneyInput = createElement("input", {
|
|
type:"number", placeholder:"Corporation funds", margin:"5px",
|
|
inputListener:()=>{
|
|
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
|
|
var stockPrice = this.sharePrice;
|
|
var stockShares = stockSharesInput.value == null || stockSharesInput.value == "" ? 0 : Math.round(parseFloat(stockSharesInput.value));
|
|
if (isNaN(money) || isNaN(stockShares) || money < 0 || stockShares < 0) {
|
|
repGainText.innerText = "ERROR: Invalid value(s) entered";
|
|
} else if (this.funds.lt(money)) {
|
|
repGainText.innerText = "ERROR: You do not have this much money to bribe with";
|
|
} else if (this.stockShares > this.numShares) {
|
|
repGainText.innerText = "ERROR: You do not have this many shares to bribe with";
|
|
} else {
|
|
|
|
var totalAmount = Number(money) + (stockShares * stockPrice);
|
|
var repGain = totalAmount / BribeToRepRatio;
|
|
repGainText.innerText = "You will gain " + formatNumber(repGain, 0) +
|
|
" reputation with " +
|
|
factionSelector.options[factionSelector.selectedIndex].value +
|
|
" with this bribe";
|
|
}
|
|
}
|
|
});
|
|
stockSharesInput = createElement("input", {
|
|
type:"number", placeholder:"Stock Shares", margin: "5px",
|
|
inputListener:()=>{
|
|
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
|
|
var stockPrice = this.sharePrice;
|
|
var stockShares = stockSharesInput.value == null || stockSharesInput.value == "" ? 0 : Math.round(stockSharesInput.value);
|
|
if (isNaN(money) || isNaN(stockShares) || money < 0 || stockShares < 0) {
|
|
repGainText.innerText = "ERROR: Invalid value(s) entered";
|
|
} else if (this.funds.lt(money)) {
|
|
repGainText.innerText = "ERROR: You do not have this much money to bribe with";
|
|
} else if (this.stockShares > this.numShares) {
|
|
repGainText.innerText = "ERROR: You do not have this many shares to bribe with";
|
|
} else {
|
|
var totalAmount = money + (stockShares * stockPrice);
|
|
var repGain = totalAmount / BribeToRepRatio;
|
|
console.log("repGain: " + repGain);
|
|
repGainText.innerText = "You will gain " + formatNumber(repGain, 0) +
|
|
" reputation with " +
|
|
factionSelector.options[factionSelector.selectedIndex].value +
|
|
" with this bribe";
|
|
}
|
|
}
|
|
});
|
|
var confirmButton = createElement("a", {
|
|
class:"a-link-button", innerText:"Bribe", display:"inline-block",
|
|
clickListener:()=>{
|
|
var money = moneyInput.value == null || moneyInput.value == "" ? 0 : parseFloat(moneyInput.value);
|
|
var stockPrice = this.sharePrice;
|
|
var stockShares = stockSharesInput.value == null || stockSharesInput.value == ""? 0 : Math.round(parseFloat(stockSharesInput.value));
|
|
var fac = Factions[factionSelector.options[factionSelector.selectedIndex].value];
|
|
if (fac == null) {
|
|
dialogBoxCreate("ERROR: You must select a faction to bribe");
|
|
return false;
|
|
}
|
|
if (isNaN(money) || isNaN(stockShares) || money < 0 || stockShares < 0) {
|
|
dialogBoxCreate("ERROR: Invalid value(s) entered");
|
|
} else if (this.funds.lt(money)) {
|
|
dialogBoxCreate("ERROR: You do not have this much money to bribe with");
|
|
} else if (stockShares > this.numShares) {
|
|
dialogBoxCreate("ERROR: You do not have this many shares to bribe with");
|
|
} else {
|
|
var totalAmount = money + (stockShares * stockPrice);
|
|
var repGain = totalAmount / BribeToRepRatio;
|
|
dialogBoxCreate("You gained " + formatNumber(repGain, 0) +
|
|
" reputation with " + fac.name + " by bribing them.");
|
|
fac.playerReputation += repGain;
|
|
this.funds = this.funds.minus(money);
|
|
this.numShares -= stockShares;
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
var cancelButton = createElement("a", {
|
|
class:"a-link-button", innerText:"Cancel", display:"inline-block",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
createPopup(popupId, [txt, factionSelector, repGainText,
|
|
moneyInput, stockSharesInput, confirmButton, cancelButton]);
|
|
}
|
|
});
|
|
companyManagementPanel.appendChild(bribeFactions);
|
|
} else {
|
|
var findInvestors = createElement("a", {
|
|
class: this.fundingRound >= 4 ? "a-link-button-inactive" : "a-link-button tooltip",
|
|
innerText: "Find Investors",
|
|
display:"inline-block",
|
|
clickListener:()=>{
|
|
this.getInvestment();
|
|
}
|
|
});
|
|
if (this.fundingRound < 4) {
|
|
var findInvestorsTooltip = createElement("span", {
|
|
class:"tooltiptext",
|
|
innerText:"Search for private investors who will give you startup funding in exchange " +
|
|
"for equity (stock shares) in your company"
|
|
});
|
|
findInvestors.appendChild(findInvestorsTooltip);
|
|
}
|
|
|
|
var goPublic = createElement("a", {
|
|
class:"a-link-button tooltip",
|
|
innerText:"Go Public",
|
|
display:"inline-block",
|
|
clickListener:()=>{
|
|
this.goPublic();
|
|
return false;
|
|
}
|
|
});
|
|
var goPublicTooltip = createElement("span", {
|
|
class:"tooltiptext",
|
|
innerText: "Become a publicly traded and owned entity. Going public involves " +
|
|
"issuing shares for an IPO. Once you are a public company, " +
|
|
"your shares will be traded on the stock market."
|
|
});
|
|
goPublic.appendChild(goPublicTooltip);
|
|
|
|
companyManagementPanel.appendChild(findInvestors);
|
|
companyManagementPanel.appendChild(goPublic);
|
|
}
|
|
|
|
//Update overview text
|
|
this.updateCorporationOverviewContent();
|
|
|
|
//Don't show upgrades if player hasn't opened any divisions
|
|
if (this.divisions.length <= 0) {return; }
|
|
//Corporation Upgrades
|
|
var upgradeContainer = createElement("div", {
|
|
class:"cmpy-mgmt-upgrade-container",
|
|
});
|
|
upgradeContainer.appendChild(createElement("h1", {
|
|
innerText:"Unlocks", margin:"6px", padding:"6px",
|
|
}));
|
|
|
|
//Unlock upgrades
|
|
var corp = this;
|
|
var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length,
|
|
numUpgrades = Object.keys(CorporationUpgrades).length;
|
|
if (this.unlockUpgrades == null || this.upgrades == null) { //Backwards compatibility
|
|
this.unlockUpgrades = Array(numUnlockUpgrades).fill(0);
|
|
this.upgrades = Array(numUpgrades).fill(0);
|
|
}
|
|
while (this.unlockUpgrades.length < numUnlockUpgrades) {this.unlockUpgrades.push(0);}
|
|
while (this.upgrades.length < numUpgrades) {this.upgrades.push(0);}
|
|
while (this.upgradeMultipliers < numUpgrades) {this.upgradeMultipliers.push(1);}
|
|
|
|
for (var i = 0; i < numUnlockUpgrades; ++i) {
|
|
(function(i, corp) {
|
|
if (corp.unlockUpgrades[i] === 0) {
|
|
var upgrade = CorporationUnlockUpgrades[i.toString()];
|
|
if (upgrade == null) {
|
|
console.log("ERROR: Could not find upgrade index " + i);
|
|
return;
|
|
}
|
|
|
|
upgradeContainer.appendChild(createElement("div", {
|
|
class:"cmpy-mgmt-upgrade-div", width:"45%",
|
|
innerHTML:upgrade[2] + " - " + numeral(upgrade[1]).format("$0.000a"),
|
|
tooltip: upgrade[3],
|
|
clickListener:()=>{
|
|
if (corp.funds.lt(upgrade[1])) {
|
|
dialogBoxCreate("Insufficient funds");
|
|
} else {
|
|
corp.unlock(upgrade);
|
|
corp.displayCorporationOverviewContent();
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
})(i, corp);
|
|
}
|
|
|
|
//Levelable upgrades
|
|
upgradeContainer.appendChild(createElement("h1", {
|
|
innerText:"Upgrades", margin:"6px", padding:"6px",
|
|
}));
|
|
|
|
for (var i = 0; i < numUpgrades; ++i) {
|
|
(function(i, corp) {
|
|
var upgrade = CorporationUpgrades[i.toString()];
|
|
if (upgrade == null) {
|
|
console.log("ERROR: Could not find levelable upgrade index " + i);
|
|
return;
|
|
}
|
|
|
|
var baseCost = upgrade[1], priceMult = upgrade[2];
|
|
var cost = baseCost * Math.pow(priceMult, corp.upgrades[i]);
|
|
upgradeContainer.appendChild(createElement("div", {
|
|
class:"cmpy-mgmt-upgrade-div", width:"45%",
|
|
innerHTML:upgrade[4] + " - " + numeral(cost).format("$0.000a"),
|
|
tooltip:upgrade[5],
|
|
clickListener:()=>{
|
|
if (corp.funds.lt(cost)) {
|
|
dialogBoxCreate("Insufficient funds");
|
|
} else {
|
|
corp.upgrade(upgrade);
|
|
corp.displayCorporationOverviewContent();
|
|
}
|
|
}
|
|
}));
|
|
})(i, corp);
|
|
}
|
|
|
|
companyManagementPanel.appendChild(upgradeContainer);
|
|
}
|
|
|
|
Corporation.prototype.updateCorporationOverviewContent = function() {
|
|
var p = document.getElementById("cmpy-mgmt-overview-text");
|
|
if (p == null) {
|
|
console.log("WARNING: Could not find overview text elemtn in updateCorporationOverviewContent()");
|
|
return;
|
|
}
|
|
var totalFunds = this.funds,
|
|
totalRevenue = new Decimal(0),
|
|
totalExpenses = new Decimal(0);
|
|
|
|
var profit = this.revenue.minus(this.expenses).toNumber(),
|
|
profitStr = profit >= 0 ? numeral(profit).format("$0.000a") : "-" + numeral(-1 * profit).format("$0.000a");
|
|
|
|
var txt = "Total Funds: " + numeral(totalFunds.toNumber()).format('$0.000a') + "<br>" +
|
|
"Total Revenue: " + numeral(this.revenue.toNumber()).format("$0.000a") + " / s<br>" +
|
|
"Total Expenses: " + numeral(this.expenses.toNumber()).format("$0.000a") + "/ s<br>" +
|
|
"Total Profits: " + profitStr + " / s<br>" +
|
|
"Publicly Traded: " + (this.public ? "Yes" : "No") + "<br>" +
|
|
"Owned Stock Shares: " + numeral(this.numShares).format('0.000a') + "<br>" +
|
|
"Stock Price: " + (this.public ? "$" + formatNumber(this.sharePrice, 2) : "N/A") + "<br><br>";
|
|
|
|
var prodMult = this.getProductionMultiplier(),
|
|
storageMult = this.getStorageMultiplier(),
|
|
advMult = this.getAdvertisingMultiplier(),
|
|
empCreMult = this.getEmployeeCreMultiplier(),
|
|
empChaMult = this.getEmployeeChaMultiplier(),
|
|
empIntMult = this.getEmployeeIntMultiplier(),
|
|
empEffMult = this.getEmployeeEffMultiplier(),
|
|
salesMult = this.getSalesMultiplier(),
|
|
sciResMult = this.getScientificResearchMultiplier();
|
|
if (prodMult > 1) {txt += "Production Multiplier: " + formatNumber(prodMult, 3) + "<br>";}
|
|
if (storageMult > 1) {txt += "Storage Multiplier: " + formatNumber(storageMult, 3) + "<br>";}
|
|
if (advMult > 1) {txt += "Advertising Multiplier: " + formatNumber(advMult, 3) + "<br>";}
|
|
if (empCreMult > 1) {txt += "Empl. Creativity Multiplier: " + formatNumber(empCreMult, 3) + "<br>";}
|
|
if (empChaMult > 1) {txt += "Empl. Charisma Multiplier: " + formatNumber(empChaMult, 3) + "<br>";}
|
|
if (empIntMult > 1) {txt += "Empl. Intelligence Multiplier: " + formatNumber(empIntMult, 3) + "<br>";}
|
|
if (empEffMult > 1) {txt += "Empl. Efficiency Multiplier: " + formatNumber(empEffMult, 3) + "<br>";}
|
|
if (salesMult > 1) {txt += "Sales Multiplier: " + formatNumber(salesMult, 3) + "<br>";}
|
|
if (sciResMult > 1) {txt += "Scientific Research Multiplier: " + formatNumber(sciResMult, 3) + "<br>";}
|
|
p.innerHTML = txt;
|
|
}
|
|
|
|
Corporation.prototype.displayDivisionContent = function(division, city) {
|
|
this.clearUIPanel();
|
|
currentCityUi = city;
|
|
|
|
//Add the city tabs on the left
|
|
for (var cityName in division.offices) {
|
|
if (division.offices[cityName] instanceof OfficeSpace) {
|
|
this.createCityUITab(cityName, division);
|
|
}
|
|
}
|
|
cityTabs = companyManagementPanel.getElementsByClassName("cmpy-mgmt-city-tab");
|
|
if (cityTabs.length > 0) {
|
|
this.selectCityTab(document.getElementById("cmpy-mgmt-city-" + city + "-tab"), city);
|
|
}
|
|
|
|
//Expand into new City button
|
|
companyManagementPanel.appendChild(createElement("button", {
|
|
class:"cmpy-mgmt-city-tab", innerText:"Expand into new City", display:"inline-block",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-expand-city-popup";
|
|
var text = createElement("p", {
|
|
innerText: "Would you like to expand into a new city by opening an office? " +
|
|
"This would cost " + numeral(OfficeInitialCost).format('$0.000a'),
|
|
});
|
|
var citySelector = createElement("select", {margin:"5px"});
|
|
for (var cityName in division.offices) {
|
|
if (division.offices.hasOwnProperty(cityName)) {
|
|
if (!(division.offices[cityName] instanceof OfficeSpace)) {
|
|
citySelector.add(createElement("option", {
|
|
text: cityName,
|
|
value: cityName
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
var confirmBtn = createElement("a", {
|
|
innerText:"Confirm", class:"a-link-button", display:"inline-block", margin:"3px",
|
|
clickListener:()=>{
|
|
var city = citySelector.options[citySelector.selectedIndex].value;
|
|
if (this.funds.lt(OfficeInitialCost)) {
|
|
dialogBoxCreate("You don't have enough company funds to open a new office!");
|
|
} else {
|
|
this.funds = this.funds.minus(OfficeInitialCost);
|
|
dialogBoxCreate("Opened a new office in " + city + "!");
|
|
division.offices[city] = new OfficeSpace({
|
|
loc:city,
|
|
size:OfficeInitialSize,
|
|
});
|
|
this.displayDivisionContent(division, city);
|
|
}
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
innerText:"Cancel", class:"a-link-button", display:"inline-block", margin:"3px",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
})
|
|
createPopup(popupId, [text, citySelector, confirmBtn, cancelBtn]);
|
|
return false;
|
|
}
|
|
}));
|
|
companyManagementPanel.appendChild(createElement("br", {})); // Force line break
|
|
|
|
//Get office object
|
|
var office = division.offices[currentCityUi];
|
|
if (!(office instanceof OfficeSpace)) {
|
|
console.log("ERROR: Current city for UI does not have an office space");
|
|
return;
|
|
}
|
|
|
|
//Left and right panels
|
|
var leftPanel = createElement("div", {class:"cmpy-mgmt-industry-left-panel"});
|
|
var rightPanel = createElement("div", {class:"cmpy-mgmt-industry-right-panel"});
|
|
companyManagementPanel.appendChild(leftPanel);
|
|
companyManagementPanel.appendChild(rightPanel);
|
|
|
|
//Different sections (Overview, Employee/Office, and Warehouse)
|
|
industryOverviewPanel = createElement("div", {
|
|
id:"cmpy-mgmt-industry-overview-panel", class:"cmpy-mgmt-industry-overview-panel"
|
|
});
|
|
leftPanel.appendChild(industryOverviewPanel);
|
|
|
|
industryEmployeePanel = createElement("div", {
|
|
id:"cmpy-mgmt-employee-panel", class:"cmpy-mgmt-employee-panel"
|
|
});
|
|
leftPanel.appendChild(industryEmployeePanel);
|
|
|
|
industryWarehousePanel = createElement("div", {
|
|
id:"cmpy-mgmt-warehouse-panel", class:"cmpy-mgmt-warehouse-panel"
|
|
});
|
|
rightPanel.appendChild(industryWarehousePanel);
|
|
|
|
//Industry overview text
|
|
industryOverviewText = createElement("p", {});
|
|
industryOverviewPanel.appendChild(industryOverviewText);
|
|
industryOverviewPanel.appendChild(createElement("br", {}));
|
|
|
|
//Industry overview Purchases & Upgrades
|
|
var numUpgrades = Object.keys(IndustryUpgrades).length;
|
|
while (division.upgrades.length < numUpgrades) {division.upgrades.push(0);} //Backwards compatibility
|
|
|
|
var industryOverviewUpgrades = createElement("div", {});
|
|
industryOverviewUpgrades.appendChild(createElement("u", {
|
|
innerText:"Purchases & Upgrades", margin:"2px", padding:"2px",
|
|
fontSize:"14px",
|
|
}));
|
|
industryOverviewUpgrades.appendChild(createElement("br", {}));
|
|
for (var i = 0; i < numUpgrades; ++i) {
|
|
(function(i, corp, division, office) {
|
|
var upgrade = IndustryUpgrades[i.toString()];
|
|
if (upgrade == null) {
|
|
console.log("ERROR: Could not find levelable upgrade index: " + i);
|
|
return;
|
|
}
|
|
|
|
var baseCost = upgrade[1], priceMult = upgrade[2], cost = 0;
|
|
switch(i) {
|
|
case 0: //Coffee, cost is static per employee
|
|
cost = office.employees.length * baseCost;
|
|
break;
|
|
default:
|
|
cost = baseCost * Math.pow(priceMult, division.upgrades[i]);
|
|
break;
|
|
}
|
|
industryOverviewUpgrades.appendChild(createElement("div", {
|
|
class:"cmpy-mgmt-upgrade-div", display:"inline-block",
|
|
innerHTML:upgrade[4] + ' - ' + numeral(cost).format("$0.000a"),
|
|
tooltip:upgrade[5],
|
|
clickListener:()=>{
|
|
if (corp.funds.lt(cost)) {
|
|
dialogBoxCreate("Insufficient funds");
|
|
} else {
|
|
corp.funds = corp.funds.minus(cost);
|
|
division.upgrade(upgrade, {
|
|
corporation:corp,
|
|
office:office,
|
|
});
|
|
corp.displayDivisionContent(division, city);
|
|
}
|
|
}
|
|
}));
|
|
industryOverviewUpgrades.appendChild(createElement("br", {}));
|
|
|
|
})(i, this, division, office);
|
|
}
|
|
|
|
|
|
industryOverviewPanel.appendChild(industryOverviewUpgrades);
|
|
|
|
//Industry Overview 'Create Product' button if applicable
|
|
if (division.makesProducts) {
|
|
//Get the text on the button based on Industry type
|
|
var createProductButtonText, createProductPopupText;
|
|
switch(division.type) {
|
|
case Industries.Food:
|
|
createProductButtonText = "Build Restaurant";
|
|
createProductPopupText = "Build and manage a new restaurant!"
|
|
break;
|
|
case Industries.Tobacco:
|
|
createProductButtonText = "Create Product";
|
|
createProductPopupText = "Create a new tobacco product!";
|
|
break;
|
|
case Industries.Pharmaceutical:
|
|
createProductButtonText = "Create Drug";
|
|
createProductPopupText = "Design and develop a new pharmaceutical drug!";
|
|
break;
|
|
case Industries.Computer:
|
|
case "Computer":
|
|
createProductButtonText = "Create Product";
|
|
createProductPopupText = "Design and manufacture a new computer hardware product!";
|
|
break;
|
|
case Industries.Robotics:
|
|
createProductButtonText = "Design Robot";
|
|
createProductPopupText = "Design and create a new robot or robotic system!";
|
|
break;
|
|
case Industries.Software:
|
|
createProductButtonText = "Develop Software";
|
|
createProductPopupText = "Develop a new piece of software!";
|
|
break;
|
|
case Industries.HealthCare:
|
|
createProductButtonText = "Build Hospital";
|
|
createProductPopupText = "Build and manage a new hospital!";
|
|
break;
|
|
case Industries.RealEstate:
|
|
createProductButtonText = "Develop Property";
|
|
createProductPopupText = "Develop a new piece of real estate property!";
|
|
break;
|
|
default:
|
|
createProductButtonText = "Create Product";
|
|
return "";
|
|
}
|
|
createProductPopupText += "<br><br>To begin developing a product, " +
|
|
"first choose the city in which it will be designed. The stats of your employees " +
|
|
"in the selected city affect the properties of the finished product, such as its " +
|
|
"quality, performance, and durability.<br><br>" +
|
|
"You can also choose to invest money in the design and marketing of " +
|
|
"the product. Investing money in its design will result in a superior product. " +
|
|
"Investing money in marketing the product will help the product's sales.";
|
|
|
|
//Create the button
|
|
industryOverviewPanel.appendChild(createElement("a", {
|
|
class:"a-link-button", innerText:createProductButtonText, margin:"6px", display:"inline-block",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-create-product-popup";
|
|
var txt = createElement("p", {
|
|
innerHTML:createProductPopupText,
|
|
});
|
|
var designCity = createElement("select", {});
|
|
for (var cityName in division.offices) {
|
|
if (division.offices[cityName] instanceof OfficeSpace) {
|
|
designCity.add(createElement("option", {
|
|
value:cityName,
|
|
text:cityName
|
|
}));
|
|
}
|
|
}
|
|
var foo = "Product Name";
|
|
if (division.type === Industries.Food) {
|
|
foo = "Restaurant Name";
|
|
} else if (division.type === Industries.Healthcare) {
|
|
foo = "Hospital Name";
|
|
} else if (division.type === Industries.RealEstate) {
|
|
foo = "Property Name";
|
|
}
|
|
var productNameInput = createElement("input", {
|
|
placeholder:foo,
|
|
});
|
|
var lineBreak1 = createElement("br",{});
|
|
var designInvestInput = createElement("input", {
|
|
type:"number",
|
|
placeholder:"Design investment"
|
|
});
|
|
var marketingInvestInput = createElement("input", {
|
|
type:"number",
|
|
placeholder:"Marketing investment"
|
|
});
|
|
var confirmBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Develop Product",
|
|
clickListener:()=>{
|
|
if (designInvestInput.value == null) {designInvestInput.value = 0;}
|
|
if (marketingInvestInput.value == null) {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.funds.lt(designInvest + marketingInvest)) {
|
|
dialogBoxCreate("You don't have enough company funds to make this large of an investment");
|
|
} else {
|
|
var product = new Product({
|
|
name:productNameInput.value.replace(/[<>]/g, ''), //Sanitize for HTMl elements
|
|
createCity:designCity.options[designCity.selectedIndex].value,
|
|
designCost: designInvest,
|
|
advCost: marketingInvest,
|
|
});
|
|
this.funds = this.funds.minus(designInvest + marketingInvest);
|
|
division.products[product.name] = product;
|
|
removeElementById(popupId);
|
|
}
|
|
//this.updateUIContent();
|
|
this.displayDivisionContent(division, city);
|
|
return false;
|
|
}
|
|
})
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
})
|
|
createPopup(popupId, [txt, designCity, productNameInput, lineBreak1,
|
|
designInvestInput, marketingInvestInput, confirmBtn, cancelBtn]);
|
|
}
|
|
}));
|
|
}
|
|
|
|
//Employee and Office Panel
|
|
industryEmployeeText = createElement("p", {
|
|
id: "cmpy-mgmt-employee-p",
|
|
display:"block",
|
|
innerHTML: "<h1>Office Space</h1><br>" +
|
|
"Type: " + office.tier + "<br>" +
|
|
"Comfort: " + office.comf + "<br>" +
|
|
"Beauty: " + office.beau + "<br>" +
|
|
"Size: " + office.employees.length + " / " + office.size + " employees",
|
|
});
|
|
industryEmployeePanel.appendChild(industryEmployeeText);
|
|
|
|
//Hire Employee button
|
|
if (office.employees.length === 0) {
|
|
industryEmployeeHireButton = createElement("a", {
|
|
class:"a-link-button",display:"inline-block",
|
|
innerText:"Hire Employee", fontSize:"13px",
|
|
tooltip:"You'll need to hire some employees to get your operations started! " +
|
|
"It's recommended to have at least one employee in every position",
|
|
clickListener:()=>{
|
|
office.findEmployees({corporation:this, division:division});
|
|
return false;
|
|
}
|
|
});
|
|
//industryEmployeeHireButton.classList.add("flashing-button");
|
|
} else {
|
|
industryEmployeeHireButton = createElement("a", {
|
|
class:"a-link-button",display:"inline-block",
|
|
innerText:"Hire Employee", fontSize:"13px",
|
|
clickListener:()=>{
|
|
office.findEmployees({corporation:this, division:division});
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
industryEmployeePanel.appendChild(industryEmployeeHireButton);
|
|
|
|
//Autohire Employee button
|
|
industryEmployeeAutohireButton = createElement("a", {
|
|
class:"a-link-button", display:"inline-block",
|
|
innerText:"Autohire Employee", fontSize:"13px",
|
|
tooltip:"Automatically hires an employee and gives him/her a random name",
|
|
clickListener:()=>{
|
|
office.hireRandomEmployee({corporation:this, division:division});
|
|
return false;
|
|
}
|
|
});
|
|
industryEmployeePanel.appendChild(industryEmployeeAutohireButton);
|
|
|
|
//Upgrade Office Size button
|
|
industryEmployeePanel.appendChild(createElement("br", {}));
|
|
industryOfficeUpgradeSizeButton = createElement("a", {
|
|
class:"a-link-button", innerText:"Upgrade size",
|
|
display:"inline-block", margin:"6px", fontSize:"13px",
|
|
tooltip:"Upgrade the office's size so that it can hold more employees!",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-upgrade-office-size-popup";
|
|
var initialPriceMult = Math.round(office.size / OfficeInitialSize);
|
|
var upgradeCost = OfficeInitialCost * Math.pow(1.07, initialPriceMult);
|
|
|
|
//Calculate cost to upgrade size by 15 employees
|
|
var mult = 0;
|
|
for (var i = 0; i < 5; ++i) {
|
|
mult += (Math.pow(1.07, initialPriceMult + i));
|
|
}
|
|
var upgradeCost15 = OfficeInitialCost * mult;
|
|
|
|
//Calculate max upgrade size and cost
|
|
var maxMult = (this.funds.dividedBy(OfficeInitialCost)).toNumber();
|
|
var maxNum = 1;
|
|
mult = Math.pow(1.07, initialPriceMult);
|
|
while(maxNum < 50) { //Hard cap of 50x (extra 150 employees)
|
|
if (mult >= maxMult) {break;}
|
|
var multIncrease = Math.pow(1.07, initialPriceMult + maxNum);
|
|
if (mult + multIncrease > maxMult) {
|
|
break;
|
|
} else {
|
|
mult += multIncrease;
|
|
}
|
|
++maxNum;
|
|
}
|
|
|
|
var upgradeCostMax = OfficeInitialCost * mult;
|
|
|
|
var text = createElement("p", {
|
|
innerText:"Increase the size of your office space to fit additional employees!"
|
|
});
|
|
var text2 = createElement("p", {innerText: "Upgrade size: "});
|
|
|
|
var confirmBtn = createElement("a", {
|
|
class: this.funds.lt(upgradeCost) ? "a-link-button-inactive" : "a-link-button",
|
|
display:"inline-block", margin:"4px", innerText:"by 3",
|
|
tooltip:numeral(upgradeCost).format("$0.000a"),
|
|
clickListener:()=>{
|
|
if (this.funds.lt(upgradeCost)) {
|
|
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
|
|
} else {
|
|
office.size += OfficeInitialSize;
|
|
this.funds = this.funds.minus(upgradeCost);
|
|
dialogBoxCreate("Office space increased! It can now hold " + office.size + " employees");
|
|
this.updateUIContent();
|
|
}
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var confirmBtn15 = createElement("a", {
|
|
class: this.funds.lt(upgradeCost15) ? "a-link-button-inactive" : "a-link-button",
|
|
display:"inline-block", margin:"4px", innerText:"by 15",
|
|
tooltip:numeral(upgradeCost15).format("$0.000a"),
|
|
clickListener:()=>{
|
|
if (this.funds.lt(upgradeCost15)) {
|
|
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
|
|
} else {
|
|
office.size += (OfficeInitialSize * 5);
|
|
this.funds = this.funds.minus(upgradeCost15);
|
|
dialogBoxCreate("Office space increased! It can now hold " + office.size + " employees");
|
|
this.updateUIContent();
|
|
}
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var confirmBtnMax = createElement("a", {
|
|
class:this.funds.lt(upgradeCostMax) ? "a-link-button-inactive" : "a-link-button",
|
|
display:"inline-block", margin:"4px", innerText:"by MAX (" + maxNum*OfficeInitialSize + ")",
|
|
tooltip:numeral(upgradeCostMax).format("$0.000a"),
|
|
clickListener:()=>{
|
|
if (this.funds.lt(upgradeCostMax)) {
|
|
dialogBoxCreate("You don't have enough company funds to purchase this upgrade!");
|
|
} else {
|
|
office.size += (OfficeInitialSize * maxNum);
|
|
this.funds = this.funds.minus(upgradeCostMax);
|
|
dialogBoxCreate("Office space increased! It can now hold " + office.size + " employees");
|
|
this.updateUIContent();
|
|
}
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button", innerText:"Cancel", display:"inline-block", margin:"4px",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
})
|
|
createPopup(popupId, [text, text2, confirmBtn, confirmBtn15, confirmBtnMax, cancelBtn]);
|
|
return false;
|
|
}
|
|
});
|
|
industryEmployeePanel.appendChild(industryOfficeUpgradeSizeButton);
|
|
|
|
//Throw Office Party
|
|
industryEmployeePanel.appendChild(createElement("a", {
|
|
class:"a-link-button", display:"inline-block", innerText:"Throw Party",
|
|
fontSize:"13px",
|
|
tooltip:"Throw an office party to increase your employee's morale and happiness",
|
|
clickListener:()=>{
|
|
var popupId = "cmpy-mgmt-throw-office-party-popup";
|
|
var txt = createElement("p", {
|
|
innerText:"Enter the amount of money you would like to spend PER EMPLOYEE " +
|
|
"on this office party"
|
|
});
|
|
var totalCostTxt = createElement("p", {
|
|
innerText:"Throwing this party will cost a total of $0"
|
|
});
|
|
var confirmBtn;
|
|
var input = createElement("input", {
|
|
type:"number", margin:"5px", placeholder:"$ / employee",
|
|
inputListener:()=>{
|
|
if (isNaN(input.value) || input.value < 0) {
|
|
totalCostTxt.innerText = "Invalid value entered!"
|
|
} else {
|
|
var totalCost = input.value * office.employees.length;
|
|
totalCostTxt.innerText = "Throwing this party will cost a total of " + numeral(totalCost).format('$0.000a');
|
|
}
|
|
},
|
|
onkeyup:(e)=>{
|
|
e.preventDefault();
|
|
if (e.keyCode === 13) {confirmBtn.click();}
|
|
}
|
|
});
|
|
confirmBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
display:"inline-block",
|
|
innerText:"Throw Party",
|
|
clickListener:()=>{
|
|
if (isNaN(input.value) || input.value < 0) {
|
|
dialogBoxCreate("Invalid value entered");
|
|
} else {
|
|
var totalCost = input.value * office.employees.length;
|
|
if (this.funds.lt(totalCost)) {
|
|
dialogBoxCreate("You don't have enough company funds to throw this party!");
|
|
} else {
|
|
this.funds = this.funds.minus(totalCost);
|
|
var mult;
|
|
for (var fooit = 0; fooit < office.employees.length; ++fooit) {
|
|
mult = office.employees[fooit].throwParty(input.value);
|
|
}
|
|
dialogBoxCreate("You threw a party for the office! The morale and happiness " +
|
|
"of each employee increased by " + formatNumber((mult-1) * 100, 2) + "%.");
|
|
removeElementById(popupId);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
var cancelBtn = createElement("a", {
|
|
class:"a-link-button",
|
|
display:"inline-block",
|
|
innerText:"Cancel",
|
|
clickListener:()=>{
|
|
removeElementById(popupId);
|
|
return false;
|
|
}
|
|
});
|
|
createPopup(popupId, [txt, totalCostTxt, input, confirmBtn, cancelBtn]);
|
|
}
|
|
}));
|
|
|
|
industryEmployeeManagementUI = createElement("div", {});
|
|
industryEmployeeInfo = createElement("p", {margin:"4px", padding:"4px"});
|
|
if (empManualAssignmentModeActive) {
|
|
//Employees manually assigned
|
|
industryEmployeeManagementUI.appendChild(createElement("a", {
|
|
class:"a-link-button", display:"inline-block", margin:"4px",
|
|
innerText:"Switch to Auto Mode",
|
|
tooltip:"Switch to Automatic Assignment Mode, which will automatically " +
|
|
"assign employees to your selected jobs. You simply have to select " +
|
|
"the number of assignments for each job",
|
|
clickListener:()=>{
|
|
empManualAssignmentModeActive = false;
|
|
this.displayDivisionContent(division, city);
|
|
}
|
|
}));
|
|
industryEmployeeManagementUI.appendChild(createElement("br", {}));
|
|
|
|
industryIndividualEmployeeInfo = createElement("div", {margin:"4px", padding:"4px"});
|
|
var selector = createElement("select", {
|
|
color: "white", backgroundColor:"black", margin:"4px", padding:"4px",
|
|
changeListener:()=>{
|
|
var name = selector.options[selector.selectedIndex].text;
|
|
for (var i = 0; i < office.employees.length; ++i) {
|
|
if (office.employees[i].name === name) {
|
|
removeChildrenFromElement(industryIndividualEmployeeInfo);
|
|
office.employees[i].createUI(industryIndividualEmployeeInfo, this);
|
|
return;
|
|
}
|
|
}
|
|
console.log("ERROR: Employee in selector could not be found");
|
|
}
|
|
});
|
|
|
|
for (var i = 0; i < office.employees.length; ++i) {
|
|
selector.add(createElement("option", {text:office.employees[i].name}));
|
|
}
|
|
|
|
selector.selectedIndex = -1;
|
|
|
|
industryEmployeeManagementUI.appendChild(industryEmployeeInfo);
|
|
industryEmployeeManagementUI.appendChild(selector);
|
|
industryEmployeeManagementUI.appendChild(industryIndividualEmployeeInfo);
|
|
} else {
|
|
//Player only manages the number of each occupation, not who gets what job
|
|
industryEmployeeManagementUI.appendChild(createElement("a", {
|
|
class:"a-link-button", display:"inline-block", margin:"4px",
|
|
innerText:"Switch to Manual Mode",
|
|
tooltip:"Switch to Manual Assignment Mode, which allows you to " +
|
|
"specify which employees should get which jobs",
|
|
clickListener:()=>{
|
|
empManualAssignmentModeActive = true;
|
|
this.displayDivisionContent(division, city);
|
|
}
|
|
}));
|
|
industryEmployeeManagementUI.appendChild(createElement("br", {}));
|
|
|
|
var opCount = 0, engCount = 0, busCount = 0,
|
|
mgmtCount = 0, rndCount = 0, unassignedCount = 0,
|
|
trainingCount = 0;
|
|
for (var i = 0; i < office.employees.length; ++i) {
|
|
switch (office.employees[i].pos) {
|
|
case EmployeePositions.Operations:
|
|
++opCount; break;
|
|
case EmployeePositions.Engineer:
|
|
++engCount; break;
|
|
case EmployeePositions.Business:
|
|
++busCount; break;
|
|
case EmployeePositions.Management:
|
|
++mgmtCount; break;
|
|
case EmployeePositions.RandD:
|
|
++rndCount; break;
|
|
case EmployeePositions.Unassigned:
|
|
++unassignedCount; break;
|
|
case EmployeePositions.Training:
|
|
++trainingCount; break;
|
|
default:
|
|
console.log("ERROR: Unrecognized employee position: " + office.employees[i].pos);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Unassigned employee count display
|
|
industryEmployeeManagementUI.appendChild(createElement("p", {
|
|
display:"inline-block",
|
|
innerText:"Unassigned Employees: " + unassignedCount,
|
|
}));
|
|
industryEmployeeManagementUI.appendChild(createElement("br", {}));
|
|
|
|
//General display of employee information (avg morale, avg energy, etc.)
|
|
industryEmployeeManagementUI.appendChild(industryEmployeeInfo);
|
|
industryEmployeeManagementUI.appendChild(createElement("br", {}));
|
|
|
|
var positions = [EmployeePositions.Operations, EmployeePositions.Engineer,
|
|
EmployeePositions.Business, EmployeePositions.Management,
|
|
EmployeePositions.RandD, EmployeePositions.Training];
|
|
var descriptions = ["Manages supply chain operations. Improves production.", //Operations
|
|
"Develops and maintains products and production systems. Improves production.", //Engineer
|
|
"Handles sales and finances. Improves sales.", //Business
|
|
"Leads and oversees employees and office operations. Improves production.", //Management
|
|
"Research new innovative ways to improve the company. Generates Scientific Research", //RandD
|
|
"Set employee to training, which will increase some of their stats. Employees in training do not affect any company operations."] //Training
|
|
var counts = [opCount, engCount, busCount, mgmtCount, rndCount, trainingCount];
|
|
for (var i = 0; i < positions.length; ++i) {
|
|
(function(corp, i) {
|
|
var info = createElement("h2", {
|
|
display:"inline-block", width:"40%", fontSize:"15px",
|
|
innerText: positions[i] + "(" + counts[i] + ")",
|
|
tooltipleft: descriptions[i]
|
|
});
|
|
var plusBtn = createElement("a", {
|
|
class: unassignedCount > 0 ? "a-link-button" : "a-link-button-inactive",
|
|
display:"inline-block", innerText:"+",
|
|
clickListener:()=>{
|
|
office.assignEmployeeToJob(positions[i]);
|
|
corp.displayDivisionContent(division, city);
|
|
}
|
|
});
|
|
var minusBtn = createElement("a", {
|
|
class: counts[i] > 0 ? "a-link-button" : "a-link-button-inactive",
|
|
display:"inline-block", innerText:"-",
|
|
clickListener:()=>{
|
|
office.unassignEmployeeFromJob(positions[i]);
|
|
corp.displayDivisionContent(division, city);
|
|
}
|
|
});
|
|
var newline = createElement("br", {});
|
|
industryEmployeeManagementUI.appendChild(info);
|
|
industryEmployeeManagementUI.appendChild(plusBtn);
|
|
industryEmployeeManagementUI.appendChild(minusBtn);
|
|
industryEmployeeManagementUI.appendChild(newline);
|
|
})(this, i);
|
|
}
|
|
}
|
|
industryEmployeePanel.appendChild(industryEmployeeManagementUI);
|
|
|
|
//Warehouse Panel
|
|
var warehouse = division.warehouses[currentCityUi];
|
|
if (warehouse instanceof Warehouse) {
|
|
warehouse.createUI({industry:division, company: this});
|
|
} else {
|
|
industryWarehousePanel.appendChild(createElement("a", {
|
|
innerText:"Purchase Warehouse ($5b)",
|
|
class: "a-link-button",
|
|
clickListener:()=>{
|
|
if (this.funds.lt(WarehouseInitialCost)) {
|
|
dialogBoxCreate("You do not have enough funds to do this!");
|
|
} else {
|
|
division.warehouses[currentCityUi] = new Warehouse({
|
|
loc:currentCityUi,
|
|
size:WarehouseInitialSize,
|
|
});
|
|
this.funds = this.funds.minus(WarehouseInitialCost);
|
|
this.displayDivisionContent(division, currentCityUi);
|
|
}
|
|
return false;
|
|
}
|
|
}));
|
|
}
|
|
this.updateDivisionContent(division);
|
|
}
|
|
|
|
Corporation.prototype.updateDivisionContent = function(division) {
|
|
if (!(division instanceof Industry)) {
|
|
console.log("ERROR: Invalid 'division' argument in Corporation.updateDivisionContent");
|
|
return;
|
|
}
|
|
var vechain = (this.unlockUpgrades[4] === 1);
|
|
//Industry Overview Text
|
|
var profit = division.lastCycleRevenue.minus(division.lastCycleExpenses).toNumber(),
|
|
profitStr = profit >= 0 ? numeral(profit).format("$0.000a") : "-" + numeral(-1 * profit).format("$0.000a");
|
|
var advertisingInfo = "";
|
|
if (vechain) {
|
|
var advertisingFactors = division.getAdvertisingFactors();
|
|
var awarenessFac = advertisingFactors[1];
|
|
var popularityFac = advertisingFactors[2];
|
|
var ratioFac = advertisingFactors[3];
|
|
var totalAdvertisingFac = advertisingFactors[0];
|
|
advertisingInfo =
|
|
"<p class='tooltip'>Advertising Multiplier: x" + formatNumber(totalAdvertisingFac, 3) +
|
|
"<span class='tooltiptext' style='font-size:12px'>Total multiplier for this industry's sales due to its awareness and popularity<br>" +
|
|
"Awareness Bonus: x" + formatNumber(Math.pow(awarenessFac, 0.85), 3) + "<br>" +
|
|
"Popularity Bonus: x" + formatNumber(Math.pow(popularityFac, 0.85), 3) + "<br>" +
|
|
"Ratio Multiplier: x" + formatNumber(Math.pow(ratioFac, 0.85), 3) + "</span></p><br>"
|
|
|
|
}
|
|
|
|
removeChildrenFromElement(industryOverviewText);
|
|
industryOverviewText.appendChild(createElement("p", {
|
|
innerHTML:"Industry: " + division.type + " (Corp Funds: " + numeral(this.funds.toNumber()).format("$0.000a") + ")<br><br>" +
|
|
"Awareness: " + formatNumber(division.awareness, 3) + "<br>" +
|
|
"Popularity: " + formatNumber(division.popularity, 3) + "<br>" +
|
|
advertisingInfo + "<br>" +
|
|
"Revenue: " + numeral(division.lastCycleRevenue.toNumber()).format("$0.000a") + " / s<br>" +
|
|
"Expenses: " + numeral(division.lastCycleExpenses.toNumber()).format("$0.000a") + " /s<br>" +
|
|
"Profit: " + profitStr + " / s<br><br>"
|
|
}));
|
|
industryOverviewText.appendChild(createElement("p", {
|
|
marginTop:"2px",
|
|
innerText:"Production Multiplier: " + formatNumber(division.prodMult, 2),
|
|
tooltip:"Production gain from owning production-boosting materials " +
|
|
"such as hardware, Robots, AI Cores, and Real Estate"
|
|
}));
|
|
industryOverviewText.appendChild(createElement("div", {
|
|
innerText:"?", class:"help-tip",
|
|
clickListener:()=>{
|
|
dialogBoxCreate("Owning Hardware, Robots, AI Cores, and Real Estate " +
|
|
"can boost your Industry's production. The effect these " +
|
|
"materials have on your production varies between Industries. " +
|
|
"For example, Real Estate may be very effective for some Industries, " +
|
|
"but ineffective for others.<br><br>" +
|
|
"This division's production multiplier is calculated by summing " +
|
|
"the individual production multiplier of each of its office locations. " +
|
|
"This production multiplier is applied to each office. Therefore, it is " +
|
|
"beneficial to expand into new cities as this can greatly increase the " +
|
|
"production multiplier of your entire Division.");
|
|
}
|
|
}));
|
|
industryOverviewText.appendChild(createElement("br"));
|
|
industryOverviewText.appendChild(createElement("p", {
|
|
display:"inline-block",
|
|
innerText:"Scientific Research: " + formatNumber(division.sciResearch.qty, 3),
|
|
tooltip:"Scientific Research increases the quality of the materials and " +
|
|
"products that you produce."
|
|
}));
|
|
|
|
//Office and Employee List
|
|
var office = division.offices[currentCityUi];
|
|
industryEmployeeText.innerHTML =
|
|
"<h1>Office Space</h1><br>" +
|
|
"Type: " + office.tier + "<br>" +
|
|
"Comfort: " + office.comf + "<br>" +
|
|
"Beauty: " + office.beau + "<br>" +
|
|
"Size: " + office.employees.length + " / " + office.size + " employees";
|
|
if (office.employees.length >= office.size) {
|
|
industryEmployeeHireButton.className = "a-link-button-inactive";
|
|
industryEmployeeAutohireButton.className = "a-link-button-inactive tooltip";
|
|
} else if (office.employees.length === 0) {
|
|
industryEmployeeHireButton.className = "a-link-button tooltip flashing-button";
|
|
industryEmployeeAutohireButton.className = "a-link-button tooltip";
|
|
} else {
|
|
industryEmployeeHireButton.className = "a-link-button";
|
|
industryEmployeeAutohireButton.className = "a-link-button tooltip";
|
|
}
|
|
|
|
//Employee Overview stats
|
|
//Calculate average morale, happiness, and energy
|
|
var totalMorale = 0, totalHappiness = 0, totalEnergy = 0,
|
|
avgMorale = 0, avgHappiness = 0, avgEnergy = 0;
|
|
for (var i = 0; i < office.employees.length; ++i) {
|
|
totalMorale += office.employees[i].mor;
|
|
totalHappiness += office.employees[i].hap;
|
|
totalEnergy += office.employees[i].ene;
|
|
}
|
|
if (office.employees.length > 0) {
|
|
avgMorale = totalMorale / office.employees.length;
|
|
avgHappiness = totalHappiness / office.employees.length;
|
|
avgEnergy = totalEnergy / office.employees.length;
|
|
}
|
|
industryEmployeeInfo.innerHTML =
|
|
"Avg Employee Morale: " + formatNumber(avgMorale, 3) + "<br>" +
|
|
"Avg Employee Happiness: " + formatNumber(avgHappiness, 3) + "<br>" +
|
|
"Avg Employee Energy: " + formatNumber(avgEnergy, 3);
|
|
if (vechain) { //VeChain - Statistics
|
|
industryEmployeeInfo.appendChild(createElement("br", {}));
|
|
industryEmployeeInfo.appendChild(createElement("p", {
|
|
innerText:"Material Production: " + formatNumber(division.getOfficeProductivity(office), 3),
|
|
tooltip: "The base amount of material this office can produce. Does not include " +
|
|
"production multipliers from upgrades and materials. This value is based off " +
|
|
"the productivity of your Operations, Engineering, and Management employees"
|
|
}));
|
|
industryEmployeeInfo.appendChild(createElement("br", {}));
|
|
industryEmployeeInfo.appendChild(createElement("p", {
|
|
innerText:"Product Production: " + formatNumber(division.getOfficeProductivity(office, {forProduct:true}), 3),
|
|
tooltip: "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 " +
|
|
"the productivity of your Operations, Engineering, and Management employees"
|
|
}));
|
|
industryEmployeeInfo.appendChild(createElement("br", {}));
|
|
industryEmployeeInfo.appendChild(createElement("p", {
|
|
innerText: "Business Multiplier: x" + formatNumber(division.getBusinessFactor(office), 3),
|
|
tooltip: "The effect this office's 'Business' employees has on boosting sales"
|
|
}));
|
|
}
|
|
|
|
//Warehouse
|
|
var warehouse = division.warehouses[currentCityUi];
|
|
if (warehouse instanceof Warehouse) {
|
|
warehouse.updateUI({industry:division, company:this});
|
|
}
|
|
}
|
|
|
|
Corporation.prototype.createCityUITab = function(city, division) {
|
|
var tab = createElement("button", {
|
|
id:"cmpy-mgmt-city-" + city + "-tab",
|
|
class:"cmpy-mgmt-city-tab",
|
|
innerText:city,
|
|
clickListener:()=>{
|
|
this.selectCityTab(tab, city);
|
|
this.displayDivisionContent(division, city);
|
|
return false;
|
|
}
|
|
});
|
|
companyManagementPanel.appendChild(tab);
|
|
}
|
|
|
|
Corporation.prototype.selectCityTab = function(activeTab, city) {
|
|
if (activeTab == null) {
|
|
activeTab = document.getElementById("cmpy-mgmt-city-" + city + "-tab");
|
|
if (activeTab == null) {return;}
|
|
}
|
|
for (var i = 0; i < cityTabs.length; ++i) {
|
|
cityTabs[i].className = "cmpy-mgmt-city-tab";
|
|
}
|
|
activeTab.className = "cmpy-mgmt-city-tab current";
|
|
}
|
|
|
|
Corporation.prototype.clearUI = function() {
|
|
//Delete everything
|
|
if (companyManagementDiv != null) {removeElementById(companyManagementDiv.id);}
|
|
|
|
//Reset global DOM variables
|
|
companyManagementDiv = null;
|
|
companyManagementPanel = null;
|
|
currentCityUi = null;
|
|
|
|
corporationUnlockUpgrades = null;
|
|
corporationUpgrades = null;
|
|
|
|
industryOverviewPanel = null;
|
|
industryOverviewText = null;
|
|
|
|
industryEmployeePanel = null;
|
|
industryEmployeeText = null;
|
|
industryEmployeeHireButton = null;
|
|
industryEmployeeAutohireButton = null;
|
|
industryEmployeeManagementUI = null;
|
|
industryEmployeeInfo = null;
|
|
industryIndividualEmployeeInfo = null;
|
|
|
|
industryOfficeUpgradeSizeButton = null;
|
|
|
|
industryWarehousePanel = null;
|
|
industrySmartSupplyCheckbox = null;
|
|
industryWarehouseStorageText = null;
|
|
industryWarehouseUpgradeSizeButton = null;
|
|
industryWarehouseStateText = null;
|
|
industryWarehouseMaterials = null;
|
|
industryWarehouseProducts = null;
|
|
|
|
companyManagementHeaderTabs = null;
|
|
headerTabs = null;
|
|
cityTabs = null;
|
|
|
|
document.getElementById("character-overview-wrapper").style.visibility = "visible";
|
|
}
|
|
|
|
Corporation.prototype.toJSON = function() {
|
|
return Generic_toJSON("Corporation", this);
|
|
}
|
|
|
|
Corporation.fromJSON = function(value) {
|
|
return Generic_fromJSON(Corporation, value.data);
|
|
}
|
|
|
|
Reviver.constructors.Corporation = Corporation;
|
|
|
|
export {Corporation};
|