mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 09:33:49 +01:00
more convertion
This commit is contained in:
parent
3d2aeb63a0
commit
4b53d6ecf7
@ -12,6 +12,8 @@ import { MaterialSizes } from "./MaterialSizes";
|
||||
import { Product } from "./Product";
|
||||
import { ResearchMap } from "./ResearchMap";
|
||||
import { Warehouse } from "./Warehouse";
|
||||
import { Employee } from "./Employee";
|
||||
import { OfficeSpace } from "./OfficeSpace";
|
||||
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { showLiterature } from "../Literature/LiteratureHelpers";
|
||||
@ -1453,167 +1455,6 @@ Industry.fromJSON = function(value) {
|
||||
|
||||
Reviver.constructors.Industry = Industry;
|
||||
|
||||
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.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.cyclesUntilRaise = CyclesPerEmployeeRaise;
|
||||
|
||||
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.003 * marketCycles,
|
||||
det = gain * Math.random();
|
||||
this.exp += gain;
|
||||
|
||||
// Employee salaries slowly go up over time
|
||||
this.cyclesUntilRaise -= marketCycles;
|
||||
if (this.cyclesUntilRaise <= 0) {
|
||||
this.salary += EmployeeRaiseAmount;
|
||||
this.cyclesUntilRaise += CyclesPerEmployeeRaise;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
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, industry) {
|
||||
var effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
|
||||
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
|
||||
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
|
||||
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.getEmployeeEffMultiplier();
|
||||
const prodBase = this.mor * this.hap * this.ene * 1e-6;
|
||||
let 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.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, industry) {
|
||||
var effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
|
||||
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
|
||||
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
|
||||
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.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>" +
|
||||
"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: " + numeralWrapper.format(this.sal, "$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.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",
|
||||
@ -1621,298 +1462,6 @@ var OfficeSpaceTiers = {
|
||||
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;
|
||||
|
||||
// Min/max energy of employees
|
||||
this.minEne = 0;
|
||||
this.maxEne = 100;
|
||||
|
||||
// Min/max Happiness of office
|
||||
this.minHap = 0;
|
||||
this.maxHap = 100;
|
||||
|
||||
// Maximum Morale of office
|
||||
this.maxMor = 100;
|
||||
|
||||
this.employees = [];
|
||||
this.employeeProd = {
|
||||
[EmployeePositions.Operations]: 0,
|
||||
[EmployeePositions.Engineer]: 0,
|
||||
[EmployeePositions.Business]: 0,
|
||||
[EmployeePositions.Management]: 0,
|
||||
[EmployeePositions.RandD]: 0,
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
|
||||
OfficeSpace.prototype.atCapacity = function() {
|
||||
return (this.employees.length) >= this.size;
|
||||
}
|
||||
|
||||
OfficeSpace.prototype.process = function(marketCycles=1, parentRefs) {
|
||||
var industry = parentRefs.industry;
|
||||
|
||||
// HRBuddy AutoRecruitment and training
|
||||
if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) {
|
||||
const emp = this.hireRandomEmployee();
|
||||
if (industry.hasResearch("HRBuddy-Training")) {
|
||||
emp.pos = EmployeePositions.Training;
|
||||
}
|
||||
}
|
||||
|
||||
// Process Office properties
|
||||
this.maxEne = 100;
|
||||
this.maxHap = 100;
|
||||
this.maxMor = 100;
|
||||
if (industry.hasResearch("Go-Juice")) {
|
||||
this.maxEne += 10;
|
||||
}
|
||||
if (industry.hasResearch("JoyWire")) {
|
||||
this.maxHap += 10;
|
||||
}
|
||||
if (industry.hasResearch("Sti.mu")) {
|
||||
this.maxMor += 10;
|
||||
}
|
||||
|
||||
// Calculate changes in Morale/Happiness/Energy for Employees
|
||||
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);
|
||||
}
|
||||
|
||||
const hasAutobrew = industry.hasResearch("AutoBrew");
|
||||
const hasAutoparty = industry.hasResearch("AutoPartyManager");
|
||||
|
||||
var salaryPaid = 0;
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
const emp = this.employees[i];
|
||||
if (hasAutoparty) {
|
||||
emp.mor = this.maxMor;
|
||||
emp.hap = this.maxHap;
|
||||
} else {
|
||||
emp.mor *= perfMult;
|
||||
emp.hap *= perfMult;
|
||||
emp.mor = Math.min(emp.mor, this.maxMor);
|
||||
emp.hap = Math.min(emp.hap, this.maxHap);
|
||||
}
|
||||
|
||||
if (hasAutobrew) {
|
||||
emp.ene = this.maxEne;
|
||||
} else {
|
||||
emp.ene *= perfMult;
|
||||
emp.ene = Math.min(emp.ene, this.maxEne);
|
||||
}
|
||||
|
||||
const salary = emp.process(marketCycles, this);
|
||||
salaryPaid += salary;
|
||||
}
|
||||
|
||||
this.calculateEmployeeProductivity(parentRefs);
|
||||
return salaryPaid;
|
||||
}
|
||||
|
||||
OfficeSpace.prototype.calculateEmployeeProductivity = function(parentRefs) {
|
||||
var company = parentRefs.corporation, industry = parentRefs.industry;
|
||||
|
||||
//Reset
|
||||
for (const name in this.employeeProd) {
|
||||
this.employeeProd[name] = 0;
|
||||
}
|
||||
|
||||
var total = 0;
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
const employee = this.employees[i];
|
||||
const prod = employee.calculateProductivity(company, industry);
|
||||
this.employeeProd[employee.pos] += prod;
|
||||
total += prod;
|
||||
}
|
||||
this.employeeProd["total"] = total;
|
||||
}
|
||||
|
||||
//Takes care of UI as well
|
||||
OfficeSpace.prototype.findEmployees = function(parentRefs) {
|
||||
if (this.atCapacity()) { return; }
|
||||
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 = EmployeeSalaryMultiplier * (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: " + numeralWrapper.format(employee.sal, '$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;
|
||||
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.rerender();
|
||||
return yesNoTxtInpBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", () => {
|
||||
return yesNoTxtInpBoxClose();
|
||||
});
|
||||
yesNoTxtInpBoxCreate("Give your employee a nickname!");
|
||||
}
|
||||
|
||||
OfficeSpace.prototype.hireRandomEmployee = function() {
|
||||
if (this.atCapacity()) { return; }
|
||||
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 = EmployeeSalaryMultiplier * (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 (let i = 0; i < this.employees.length; ++i) {
|
||||
if (this.employees[i].name === name) {
|
||||
return this.hireRandomEmployee();
|
||||
}
|
||||
}
|
||||
emp.name = name;
|
||||
this.employees.push(emp);
|
||||
|
||||
return emp;
|
||||
}
|
||||
|
||||
//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 Corporation(params={}) {
|
||||
this.name = params.name ? params.name : "The Corporation";
|
||||
|
||||
@ -2398,4 +1947,4 @@ Corporation.fromJSON = function(value) {
|
||||
|
||||
Reviver.constructors.Corporation = Corporation;
|
||||
|
||||
export {Corporation, Industry, OfficeSpace, Warehouse};
|
||||
export {Corporation, Industry, Warehouse};
|
||||
|
194
src/Corporation/Employee.ts
Normal file
194
src/Corporation/Employee.ts
Normal file
@ -0,0 +1,194 @@
|
||||
import { CorporationConstants } from "./data/Constants";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||
import { EmployeePositions } from "./EmployeePositions";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||
|
||||
interface IParams {
|
||||
name?: string;
|
||||
morale?: number;
|
||||
happiness?: number;
|
||||
energy?: number;
|
||||
intelligence?: number;
|
||||
charisma?: number;
|
||||
experience?: number;
|
||||
creativity?: number;
|
||||
efficiency?: number;
|
||||
salary?: number;
|
||||
loc?: string;
|
||||
}
|
||||
|
||||
export class Employee {
|
||||
name: string;
|
||||
mor: number;
|
||||
hap: number;
|
||||
ene: number;
|
||||
int: number;
|
||||
cha: number;
|
||||
exp: number;
|
||||
cre: number;
|
||||
eff: number;
|
||||
sal: number;
|
||||
pro = 0;
|
||||
cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise;
|
||||
loc: string;
|
||||
pos: string;
|
||||
|
||||
constructor(params: IParams = {}) {
|
||||
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.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.loc = params.loc ? params.loc : "";
|
||||
this.pos = EmployeePositions.Unassigned;
|
||||
}
|
||||
|
||||
//Returns the amount the employee needs to be paid
|
||||
process(marketCycles = 1, office: any) {
|
||||
const gain = 0.003 * marketCycles,
|
||||
det = gain * Math.random();
|
||||
this.exp += gain;
|
||||
|
||||
// Employee salaries slowly go up over time
|
||||
this.cyclesUntilRaise -= marketCycles;
|
||||
if (this.cyclesUntilRaise <= 0) {
|
||||
this.sal += CorporationConstants.EmployeeRaiseAmount;
|
||||
this.cyclesUntilRaise += CorporationConstants.CyclesPerEmployeeRaise;
|
||||
}
|
||||
|
||||
//Training
|
||||
const 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;
|
||||
}
|
||||
|
||||
this.ene -= det;
|
||||
this.hap -= det;
|
||||
|
||||
if (this.ene < office.minEne) {this.ene = office.minEne;}
|
||||
if (this.hap < office.minHap) {this.hap = office.minHap;}
|
||||
const salary = this.sal * marketCycles * CorporationConstants.SecsPerMarketCycle;
|
||||
return salary;
|
||||
}
|
||||
|
||||
calculateProductivity(corporation: any, industry: any): number {
|
||||
const effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
|
||||
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
|
||||
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
|
||||
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.getEmployeeEffMultiplier();
|
||||
const prodBase = this.mor * this.hap * this.ene * 1e-6;
|
||||
let prodMult = 0;
|
||||
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.error(`Invalid employee position: ${this.pos}`);
|
||||
break;
|
||||
}
|
||||
return prodBase * prodMult;
|
||||
}
|
||||
|
||||
//Process benefits from having an office party thrown
|
||||
throwParty(money: number) {
|
||||
const 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
|
||||
createUI(panel: any, corporation: any, industry: any) {
|
||||
const effCre = this.cre * corporation.getEmployeeCreMultiplier() * industry.getEmployeeCreMultiplier(),
|
||||
effCha = this.cha * corporation.getEmployeeChaMultiplier() * industry.getEmployeeChaMultiplier(),
|
||||
effInt = this.int * corporation.getEmployeeIntMultiplier() * industry.getEmployeeIntMultiplier(),
|
||||
effEff = this.eff * corporation.getEmployeeEffMultiplier() * industry.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>" +
|
||||
"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: " + numeralWrapper.format(this.sal, "$0.000a") + "/ s<br>",
|
||||
}));
|
||||
|
||||
//Selector for employee position
|
||||
const selector = createElement("select", {}) as HTMLSelectElement;
|
||||
for (const key in EmployeePositions) {
|
||||
if (EmployeePositions.hasOwnProperty(key)) {
|
||||
selector.add(createElement("option", {
|
||||
text: EmployeePositions[key],
|
||||
value: EmployeePositions[key],
|
||||
}) as HTMLOptionElement);
|
||||
}
|
||||
}
|
||||
|
||||
selector.addEventListener("change", () => {
|
||||
this.pos = selector.options[selector.selectedIndex].value;
|
||||
});
|
||||
|
||||
//Set initial value of selector
|
||||
for (let i = 0; i < selector.length; ++i) {
|
||||
if (selector.options[i].value === this.pos) {
|
||||
selector.selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
panel.appendChild(selector);
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Employee", this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): Employee {
|
||||
return Generic_fromJSON(Employee, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.Employee = Employee;
|
@ -3,5 +3,5 @@ import { IMap } from "../types";
|
||||
|
||||
export interface IDivision {
|
||||
name: string;
|
||||
offices: IMap<IOfficeSpace>;
|
||||
offices: IMap<IOfficeSpace | number>;
|
||||
}
|
||||
|
323
src/Corporation/OfficeSpace.ts
Normal file
323
src/Corporation/OfficeSpace.ts
Normal file
@ -0,0 +1,323 @@
|
||||
import { EmployeePositions } from "./EmployeePositions";
|
||||
import { CorporationConstants } from "./data/Constants";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
import { formatNumber, generateRandomString } from "../../utils/StringHelperFunctions";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
import { yesNoBoxCreate,
|
||||
yesNoTxtInpBoxCreate,
|
||||
yesNoBoxGetYesButton,
|
||||
yesNoBoxGetNoButton,
|
||||
yesNoTxtInpBoxGetYesButton,
|
||||
yesNoTxtInpBoxGetNoButton,
|
||||
yesNoTxtInpBoxGetInput,
|
||||
yesNoBoxClose,
|
||||
yesNoTxtInpBoxClose } from "../../utils/YesNoBox";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { createPopup } from "../../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../../utils/uiHelpers/removeElementById";
|
||||
import { createElement } from "../../utils/uiHelpers/createElement";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
import { Employee } from "./Employee";
|
||||
|
||||
interface IParams {
|
||||
loc?: string;
|
||||
cost?: number;
|
||||
size?: number;
|
||||
comfort?: number;
|
||||
beauty?: number;
|
||||
}
|
||||
|
||||
export class OfficeSpace {
|
||||
loc: string;
|
||||
cost: number;
|
||||
size: number;
|
||||
comf: number;
|
||||
beau: number;
|
||||
tier = "Basic";
|
||||
minEne = 0;
|
||||
maxEne = 100;
|
||||
minHap = 0;
|
||||
maxHap = 100;
|
||||
maxMor = 100;
|
||||
employees: any[] = [];
|
||||
employeeProd: {[key: string]: number} = {
|
||||
[EmployeePositions.Operations]: 0,
|
||||
[EmployeePositions.Engineer]: 0,
|
||||
[EmployeePositions.Business]: 0,
|
||||
[EmployeePositions.Management]: 0,
|
||||
[EmployeePositions.RandD]: 0,
|
||||
total: 0,
|
||||
};
|
||||
|
||||
constructor(params: IParams = {}) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
atCapacity(): boolean {
|
||||
return (this.employees.length) >= this.size;
|
||||
}
|
||||
|
||||
process(marketCycles = 1, parentRefs: any): number {
|
||||
const industry = parentRefs.industry;
|
||||
|
||||
// HRBuddy AutoRecruitment and training
|
||||
if (industry.hasResearch("HRBuddy-Recruitment") && !this.atCapacity()) {
|
||||
const emp = this.hireRandomEmployee();
|
||||
if (industry.hasResearch("HRBuddy-Training") && emp !== undefined) {
|
||||
emp.pos = EmployeePositions.Training;
|
||||
}
|
||||
}
|
||||
|
||||
// Process Office properties
|
||||
this.maxEne = 100;
|
||||
this.maxHap = 100;
|
||||
this.maxMor = 100;
|
||||
if (industry.hasResearch("Go-Juice")) {
|
||||
this.maxEne += 10;
|
||||
}
|
||||
if (industry.hasResearch("JoyWire")) {
|
||||
this.maxHap += 10;
|
||||
}
|
||||
if (industry.hasResearch("Sti.mu")) {
|
||||
this.maxMor += 10;
|
||||
}
|
||||
|
||||
// Calculate changes in Morale/Happiness/Energy for Employees
|
||||
let 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);
|
||||
}
|
||||
|
||||
const hasAutobrew = industry.hasResearch("AutoBrew");
|
||||
const hasAutoparty = industry.hasResearch("AutoPartyManager");
|
||||
|
||||
let salaryPaid = 0;
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
const emp = this.employees[i];
|
||||
if (hasAutoparty) {
|
||||
emp.mor = this.maxMor;
|
||||
emp.hap = this.maxHap;
|
||||
} else {
|
||||
emp.mor *= perfMult;
|
||||
emp.hap *= perfMult;
|
||||
emp.mor = Math.min(emp.mor, this.maxMor);
|
||||
emp.hap = Math.min(emp.hap, this.maxHap);
|
||||
}
|
||||
|
||||
if (hasAutobrew) {
|
||||
emp.ene = this.maxEne;
|
||||
} else {
|
||||
emp.ene *= perfMult;
|
||||
emp.ene = Math.min(emp.ene, this.maxEne);
|
||||
}
|
||||
|
||||
const salary = emp.process(marketCycles, this);
|
||||
salaryPaid += salary;
|
||||
}
|
||||
|
||||
this.calculateEmployeeProductivity(parentRefs);
|
||||
return salaryPaid;
|
||||
}
|
||||
|
||||
calculateEmployeeProductivity(parentRefs: any) {
|
||||
const company = parentRefs.corporation, industry = parentRefs.industry;
|
||||
|
||||
//Reset
|
||||
for (const name in this.employeeProd) {
|
||||
this.employeeProd[name] = 0;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
const employee = this.employees[i];
|
||||
const prod = employee.calculateProductivity(company, industry);
|
||||
this.employeeProd[employee.pos] += prod;
|
||||
total += prod;
|
||||
}
|
||||
this.employeeProd.total = total;
|
||||
}
|
||||
|
||||
//Takes care of UI as well
|
||||
findEmployees(parentRefs: any) {
|
||||
if (this.atCapacity()) { return; }
|
||||
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) {return;}
|
||||
|
||||
//Generate three random employees (meh, decent, amazing)
|
||||
const mult1 = getRandomInt(25, 50)/100,
|
||||
mult2 = getRandomInt(51, 75)/100,
|
||||
mult3 = getRandomInt(76, 100)/100;
|
||||
const int = getRandomInt(50, 100),
|
||||
cha = getRandomInt(50, 100),
|
||||
exp = getRandomInt(50, 100),
|
||||
cre = getRandomInt(50, 100),
|
||||
eff = getRandomInt(50, 100),
|
||||
sal = CorporationConstants.EmployeeSalaryMultiplier * (int + cha + exp + cre + eff);
|
||||
|
||||
const emp1 = new Employee({
|
||||
intelligence: int * mult1,
|
||||
charisma: cha * mult1,
|
||||
experience: exp * mult1,
|
||||
creativity: cre * mult1,
|
||||
efficiency: eff * mult1,
|
||||
salary: sal * mult1,
|
||||
});
|
||||
|
||||
const emp2 = new Employee({
|
||||
intelligence: int * mult2,
|
||||
charisma: cha * mult2,
|
||||
experience: exp * mult2,
|
||||
creativity: cre * mult2,
|
||||
efficiency: eff * mult2,
|
||||
salary: sal * mult2,
|
||||
});
|
||||
|
||||
const emp3 = new Employee({
|
||||
intelligence: int * mult3,
|
||||
charisma: cha * mult3,
|
||||
experience: exp * mult3,
|
||||
creativity: cre * mult3,
|
||||
efficiency: eff * mult3,
|
||||
salary: sal * mult3,
|
||||
});
|
||||
|
||||
const text = createElement("h1", {
|
||||
innerHTML: "Select one of the following candidates for hire:",
|
||||
});
|
||||
|
||||
const createEmpDiv = function(employee: any, office: any) {
|
||||
const 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: " + numeralWrapper.format(employee.sal, '$0.000a') + " \ s<br>",
|
||||
clickListener: () => {
|
||||
office.hireEmployee(employee, parentRefs);
|
||||
removeElementById("cmpy-mgmt-hire-employee-popup");
|
||||
return false;
|
||||
},
|
||||
});
|
||||
return div;
|
||||
};
|
||||
|
||||
const cancelBtn = createElement("a", {
|
||||
class:"a-link-button",
|
||||
innerText:"Cancel",
|
||||
float:"right",
|
||||
clickListener:() => {
|
||||
removeElementById("cmpy-mgmt-hire-employee-popup");
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
const elems = [text,
|
||||
createEmpDiv(emp1, this),
|
||||
createEmpDiv(emp2, this),
|
||||
createEmpDiv(emp3, this),
|
||||
cancelBtn];
|
||||
|
||||
createPopup("cmpy-mgmt-hire-employee-popup", elems);
|
||||
}
|
||||
|
||||
hireEmployee(employee: Employee, parentRefs: any) {
|
||||
const company = parentRefs.corporation;
|
||||
const yesBtn = yesNoTxtInpBoxGetYesButton(),
|
||||
noBtn = yesNoTxtInpBoxGetNoButton();
|
||||
yesBtn.innerHTML = "Hire";
|
||||
noBtn.innerHTML = "Cancel";
|
||||
yesBtn.addEventListener("click", () => {
|
||||
const name = yesNoTxtInpBoxGetInput();
|
||||
for (let 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.rerender();
|
||||
return yesNoTxtInpBoxClose();
|
||||
});
|
||||
noBtn.addEventListener("click", () => {
|
||||
return yesNoTxtInpBoxClose();
|
||||
});
|
||||
yesNoTxtInpBoxCreate("Give your employee a nickname!");
|
||||
}
|
||||
|
||||
hireRandomEmployee(): Employee | undefined {
|
||||
if (this.atCapacity()) return;
|
||||
if (document.getElementById("cmpy-mgmt-hire-employee-popup") != null) return;
|
||||
|
||||
//Generate three random employees (meh, decent, amazing)
|
||||
const mult = getRandomInt(76, 100)/100;
|
||||
const int = getRandomInt(50, 100),
|
||||
cha = getRandomInt(50, 100),
|
||||
exp = getRandomInt(50, 100),
|
||||
cre = getRandomInt(50, 100),
|
||||
eff = getRandomInt(50, 100),
|
||||
sal = CorporationConstants.EmployeeSalaryMultiplier * (int + cha + exp + cre + eff);
|
||||
|
||||
const emp = new Employee({
|
||||
intelligence: int * mult,
|
||||
charisma: cha * mult,
|
||||
experience: exp * mult,
|
||||
creativity: cre * mult,
|
||||
efficiency: eff * mult,
|
||||
salary: sal * mult,
|
||||
});
|
||||
|
||||
const name = generateRandomString(7);
|
||||
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
if (this.employees[i].name === name) {
|
||||
return this.hireRandomEmployee();
|
||||
}
|
||||
}
|
||||
emp.name = name;
|
||||
this.employees.push(emp);
|
||||
|
||||
return emp;
|
||||
}
|
||||
|
||||
//Finds the first unassigned employee and assigns its to the specified job
|
||||
assignEmployeeToJob(job: any): boolean {
|
||||
for (let 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
|
||||
unassignEmployeeFromJob(job: any): boolean {
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
if (this.employees[i].pos === job) {
|
||||
this.employees[i].pos = EmployeePositions.Unassigned;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("OfficeSpace", this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static fromJSON(value: any): OfficeSpace {
|
||||
return Generic_fromJSON(OfficeSpace, value.data);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.OfficeSpace = OfficeSpace;
|
60
src/Corporation/data/Constants.ts
Normal file
60
src/Corporation/data/Constants.ts
Normal file
@ -0,0 +1,60 @@
|
||||
const CyclesPerMarketCycle = 50;
|
||||
const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
|
||||
export const CorporationConstants: {
|
||||
INITIALSHARES: number;
|
||||
SHARESPERPRICEUPDATE: number;
|
||||
IssueNewSharesCooldown: number;
|
||||
SellSharesCooldown: number;
|
||||
CyclesPerMarketCycle: number;
|
||||
CyclesPerIndustryStateCycle: number;
|
||||
SecsPerMarketCycle: number;
|
||||
Cities: string[];
|
||||
WarehouseInitialCost: number;
|
||||
WarehouseInitialSize: number;
|
||||
WarehouseUpgradeBaseCost: number;
|
||||
OfficeInitialCost: number;
|
||||
OfficeInitialSize: number;
|
||||
OfficeUpgradeBaseCost: number;
|
||||
BribeThreshold: number;
|
||||
BribeToRepRatio: number;
|
||||
ProductProductionCostRatio: number;
|
||||
DividendMaxPercentage: number;
|
||||
EmployeeSalaryMultiplier: number;
|
||||
CyclesPerEmployeeRaise: number;
|
||||
EmployeeRaiseAmount: number;
|
||||
BaseMaxProducts: number;
|
||||
AllCorporationStates: string[];
|
||||
} = {
|
||||
INITIALSHARES: 1e9, //Total number of shares you have at your company
|
||||
SHARESPERPRICEUPDATE: 1e6, //When selling large number of shares, price is dynamically updated for every batch of this amount
|
||||
IssueNewSharesCooldown: 216e3, // 12 Hour in terms of game cycles
|
||||
SellSharesCooldown: 18e3, // 1 Hour in terms of game cycles
|
||||
|
||||
CyclesPerMarketCycle: CyclesPerMarketCycle,
|
||||
CyclesPerIndustryStateCycle: CyclesPerMarketCycle / AllCorporationStates.length,
|
||||
SecsPerMarketCycle: CyclesPerMarketCycle / 5,
|
||||
|
||||
Cities: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"],
|
||||
|
||||
WarehouseInitialCost: 5e9, //Initial purchase cost of warehouse
|
||||
WarehouseInitialSize: 100,
|
||||
WarehouseUpgradeBaseCost: 1e9,
|
||||
|
||||
OfficeInitialCost: 4e9,
|
||||
OfficeInitialSize: 3,
|
||||
OfficeUpgradeBaseCost: 1e9,
|
||||
|
||||
BribeThreshold: 100e12, //Money needed to be able to bribe for faction rep
|
||||
BribeToRepRatio: 1e9, //Bribe Value divided by this = rep gain
|
||||
|
||||
ProductProductionCostRatio: 5, //Ratio of material cost of a product to its production cost
|
||||
|
||||
DividendMaxPercentage: 50,
|
||||
|
||||
EmployeeSalaryMultiplier: 3, // Employee stats multiplied by this to determine initial salary
|
||||
CyclesPerEmployeeRaise: 400, // All employees get a raise every X market cycles
|
||||
EmployeeRaiseAmount: 50, // Employee salary increases by this (additive)
|
||||
|
||||
BaseMaxProducts: 3, // Initial value for maximum number of products allowed
|
||||
AllCorporationStates: AllCorporationStates,
|
||||
};
|
@ -2,35 +2,42 @@
|
||||
// These allow player to navigate between different cities for each industry
|
||||
import React from "react";
|
||||
import { CityTab } from "./CityTab";
|
||||
import { ExpandNewCityPopup } from "./ExpandNewCityPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { IDivision } from "../IDivision";
|
||||
|
||||
interface IProps {
|
||||
eventHandler: any;
|
||||
routing: any;
|
||||
onClicks: {[key: string]: () => void};
|
||||
city: string; // currentCity
|
||||
cityStateSetter: any;
|
||||
cityStateSetter: (city: string) => void;
|
||||
corp: any;
|
||||
}
|
||||
|
||||
export function CityTabs(props: IProps): React.ReactElement {
|
||||
const division = props.routing.currentDivision;
|
||||
|
||||
const tabs = [];
|
||||
|
||||
// Tabs for each city
|
||||
for (const cityName in props.onClicks) {
|
||||
tabs.push(
|
||||
<CityTab current={props.city === cityName} key={cityName} name={cityName} onClick={props.onClicks[cityName]} />
|
||||
);
|
||||
function openExpandNewCityModal() {
|
||||
const popupId = "cmpy-mgmt-expand-city-popup";
|
||||
createPopup(popupId, ExpandNewCityPopup, {
|
||||
popupId: popupId,
|
||||
corp: props.corp,
|
||||
division: division as IDivision,
|
||||
cityStateSetter: props.cityStateSetter,
|
||||
});
|
||||
}
|
||||
|
||||
tabs.push(
|
||||
return <>
|
||||
{
|
||||
Object.keys(props.onClicks).map((cityName: string) => <CityTab current={props.city === cityName} key={cityName} name={cityName} onClick={props.onClicks[cityName]} />,
|
||||
)
|
||||
}
|
||||
<CityTab
|
||||
current={false}
|
||||
key={"Expand into new City"}
|
||||
name={"Expand into new City"}
|
||||
onClick={() => props.eventHandler.createNewCityPopup(division, props.cityStateSetter)}
|
||||
current={false}
|
||||
key={"Expand into new City"}
|
||||
name={"Expand into new City"}
|
||||
onClick={openExpandNewCityModal}
|
||||
/>
|
||||
);
|
||||
|
||||
return <>{tabs}</>;
|
||||
</>;
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
import { CorporationRouting } from "./Routing";
|
||||
import { Corporation,
|
||||
Industry,
|
||||
OfficeSpace,
|
||||
Warehouse,
|
||||
DividendMaxPercentage,
|
||||
IssueNewSharesCooldown,
|
||||
@ -12,6 +11,7 @@ import { Corporation,
|
||||
WarehouseInitialCost,
|
||||
WarehouseInitialSize,
|
||||
BribeToRepRatio } from "../Corporation";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
|
||||
import { Industries,
|
||||
IndustryStartingCosts,
|
||||
|
51
src/Corporation/ui/ExpandNewCityPopup.tsx
Normal file
51
src/Corporation/ui/ExpandNewCityPopup.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import React, { useRef } from "react";
|
||||
import { IDivision } from "../IDivision";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
|
||||
interface IProps {
|
||||
popupId: string;
|
||||
corp: any;
|
||||
division: IDivision;
|
||||
cityStateSetter: (city: string) => void;
|
||||
}
|
||||
|
||||
export function ExpandNewCityPopup(props: IProps): React.ReactElement {
|
||||
const dropdown = useRef<HTMLSelectElement>(null);
|
||||
|
||||
function expand(): void {
|
||||
if(dropdown.current === null) return;
|
||||
const city = dropdown.current.value;
|
||||
if (props.corp.funds.lt(CorporationConstants.OfficeInitialCost)) {
|
||||
dialogBoxCreate("You don't have enough company funds to open a new office!");
|
||||
} else {
|
||||
props.corp.funds = props.corp.funds.minus(CorporationConstants.OfficeInitialCost);
|
||||
dialogBoxCreate(`Opened a new office in ${city}!`);
|
||||
props.division.offices[city] = new OfficeSpace({
|
||||
loc: city,
|
||||
size: CorporationConstants.OfficeInitialSize,
|
||||
});
|
||||
}
|
||||
|
||||
props.cityStateSetter(city);
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
return (<>
|
||||
<p>
|
||||
Would you like to expand into a new city by opening an office?
|
||||
This would cost {numeralWrapper.format(CorporationConstants.OfficeInitialCost, '$0.000a')}
|
||||
</p>
|
||||
<select ref={dropdown} className="dropdown" style={{margin:"5px"}}>
|
||||
{
|
||||
Object.keys(props.division.offices)
|
||||
.filter((cityName: string) => props.division.offices[cityName] === 0)
|
||||
.map((cityName: string) => <option key={cityName} value={cityName}>{cityName}</option>,
|
||||
)
|
||||
}
|
||||
</select>
|
||||
<button className="std-button" style={{display:"inline-block"}} onClick={expand}>Confirm</button>
|
||||
</>);
|
||||
}
|
@ -26,8 +26,7 @@ export function HeaderTabs(props: IProps): React.ReactElement {
|
||||
text={props.corp.name}
|
||||
/>
|
||||
{
|
||||
props.corp.divisions.map((division: IDivision) =>
|
||||
<HeaderTab
|
||||
props.corp.divisions.map((division: IDivision) => <HeaderTab
|
||||
current={props.routing.isOn(division.name)}
|
||||
key={division.name}
|
||||
onClick={() => {
|
||||
|
@ -25,7 +25,12 @@ export class Industry extends BaseReactComponent {
|
||||
</div>
|
||||
|
||||
<div className={"cmpy-mgmt-industry-right-panel"}>
|
||||
<IndustryWarehouse {...this.props} />
|
||||
<IndustryWarehouse
|
||||
corp={this.props.corp}
|
||||
routing={this.props.routing}
|
||||
currentCity={this.props.currentCity}
|
||||
eventHandler={this.props.eventHandler}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -3,7 +3,7 @@
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { OfficeSpace } from "../Corporation";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { EmployeePositions } from "../EmployeePositions";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
@ -3,7 +3,7 @@
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { OfficeSpace } from "../Corporation";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Industries } from "../IndustryData";
|
||||
import { IndustryUpgrades } from "../IndustryUpgrades";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
@ -1,12 +1,9 @@
|
||||
// React Component for displaying an Industry's warehouse information
|
||||
// (right-side panel in the Industry UI)
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { OfficeSpace,
|
||||
WarehouseInitialCost,
|
||||
WarehouseUpgradeBaseCost,
|
||||
ProductProductionCostRatio } from "../Corporation";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
import { Material } from "../Material";
|
||||
import { Product } from "../Product";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
@ -15,8 +12,16 @@ import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { isString } from "../../../utils/helpers/isString";
|
||||
|
||||
interface IProductProps {
|
||||
corp: any;
|
||||
division: any;
|
||||
city: string;
|
||||
product: any;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Product type
|
||||
function ProductComponent(props) {
|
||||
function ProductComponent(props: IProductProps) {
|
||||
const corp = props.corp;
|
||||
const division = props.division;
|
||||
const city = props.city;
|
||||
@ -146,7 +151,7 @@ function ProductComponent(props) {
|
||||
</span>
|
||||
</p><br />
|
||||
<p className={"tooltip"}>
|
||||
Est. Production Cost: {numeralWrapper.formatMoney(product.pCost / ProductProductionCostRatio)}
|
||||
Est. Production Cost: {numeralWrapper.formatMoney(product.pCost / CorporationConstants.ProductProductionCostRatio)}
|
||||
<span className={"tooltiptext"}>
|
||||
An estimate of the material cost it takes to create this Product.
|
||||
</span>
|
||||
@ -181,8 +186,17 @@ function ProductComponent(props) {
|
||||
)
|
||||
}
|
||||
|
||||
interface IMaterialProps {
|
||||
corp: any;
|
||||
division: any;
|
||||
warehouse: any;
|
||||
city: string;
|
||||
mat: any;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
// Creates the UI for a single Material type
|
||||
function MaterialComponent(props) {
|
||||
function MaterialComponent(props: any) {
|
||||
const corp = props.corp;
|
||||
const division = props.division;
|
||||
const warehouse = props.warehouse;
|
||||
@ -230,7 +244,7 @@ function MaterialComponent(props) {
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(mat.bCost + markupLimit);
|
||||
} else if (mat.sCost) {
|
||||
if (isString(mat.sCost)) {
|
||||
var sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
||||
const sCost = mat.sCost.replace(/MP/g, mat.bCost);
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(eval(sCost));
|
||||
} else {
|
||||
sellButtonText += " @ " + numeralWrapper.formatMoney(mat.sCost);
|
||||
@ -320,10 +334,17 @@ function MaterialComponent(props) {
|
||||
)
|
||||
}
|
||||
|
||||
export class IndustryWarehouse extends BaseReactComponent {
|
||||
interface IProps {
|
||||
corp: any;
|
||||
routing: any;
|
||||
currentCity: string;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
export function IndustryWarehouse(props: IProps) {
|
||||
// Returns a boolean indicating whether the given material is relevant for the
|
||||
// current industry.
|
||||
isRelevantMaterial(matName, division) {
|
||||
function isRelevantMaterial(matName: string, division: any): boolean {
|
||||
// Materials that affect Production multiplier
|
||||
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"];
|
||||
|
||||
@ -334,10 +355,10 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
renderWarehouseUI() {
|
||||
const corp = this.corp();
|
||||
const division = this.routing().currentDivision; // Validated in render()
|
||||
const warehouse = division.warehouses[this.props.currentCity]; // Validated in render()
|
||||
function renderWarehouseUI() {
|
||||
const corp = props.corp;
|
||||
const division = props.routing.currentDivision; // Validated in render()
|
||||
const warehouse = division.warehouses[props.currentCity]; // Validated in render()
|
||||
|
||||
// General Storage information at the top
|
||||
const sizeUsageStyle = {
|
||||
@ -346,7 +367,7 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
}
|
||||
|
||||
// Upgrade Warehouse size button
|
||||
const sizeUpgradeCost = WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
|
||||
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
|
||||
const canAffordUpgrade = (corp.funds.gt(sizeUpgradeCost));
|
||||
const upgradeWarehouseClass = canAffordUpgrade ? "std-button" : "a-link-button-inactive";
|
||||
const upgradeWarehouseOnClick = () => {
|
||||
@ -416,7 +437,7 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
|
||||
// Smart Supply Checkbox
|
||||
const smartSupplyCheckboxId = "cmpy-mgmt-smart-supply-checkbox";
|
||||
const smartSupplyOnChange = (e) => {
|
||||
const smartSupplyOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
warehouse.smartSupplyEnabled = e.target.checked;
|
||||
corp.rerender();
|
||||
}
|
||||
@ -426,12 +447,12 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
for (const matName in warehouse.materials) {
|
||||
if (warehouse.materials[matName] instanceof Material) {
|
||||
// Only create UI for materials that are relevant for the industry
|
||||
if (this.isRelevantMaterial(matName, division)) {
|
||||
if (isRelevantMaterial(matName, division)) {
|
||||
mats.push(<MaterialComponent
|
||||
city={this.props.currentCity}
|
||||
city={props.currentCity}
|
||||
corp={corp}
|
||||
division={division}
|
||||
eventHandler={this.eventHandler()}
|
||||
eventHandler={props.eventHandler}
|
||||
key={matName}
|
||||
mat={warehouse.materials[matName]}
|
||||
warehouse={warehouse} />);
|
||||
@ -445,13 +466,13 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
for (const productName in division.products) {
|
||||
if (division.products[productName] instanceof Product) {
|
||||
products.push(<ProductComponent
|
||||
city={this.props.currentCity}
|
||||
city={props.currentCity}
|
||||
corp={corp}
|
||||
division={division}
|
||||
eventHandler={this.eventHandler()}
|
||||
eventHandler={props.eventHandler}
|
||||
key={productName}
|
||||
product={division.products[productName]}
|
||||
warehouse={warehouse} />);
|
||||
/>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -500,25 +521,21 @@ export class IndustryWarehouse extends BaseReactComponent {
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const division = this.routing().currentDivision;
|
||||
if (division == null) {
|
||||
throw new Error(`Routing does not hold reference to the current Industry`);
|
||||
}
|
||||
const warehouse = division.warehouses[this.props.currentCity];
|
||||
const division = props.routing.currentDivision;
|
||||
if (division == null) {
|
||||
throw new Error(`Routing does not hold reference to the current Industry`);
|
||||
}
|
||||
const warehouse = division.warehouses[props.currentCity];
|
||||
|
||||
const newWarehouseOnClick = this.eventHandler().purchaseWarehouse.bind(this.eventHandler(), division, this.props.currentCity);
|
||||
|
||||
if (warehouse instanceof Warehouse) {
|
||||
return this.renderWarehouseUI();
|
||||
} else {
|
||||
return (
|
||||
<div className={"cmpy-mgmt-warehouse-panel"}>
|
||||
<button className={"std-button"} onClick={newWarehouseOnClick}>
|
||||
Purchase Warehouse ({numeralWrapper.formatMoney(WarehouseInitialCost)})
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (warehouse instanceof Warehouse) {
|
||||
return renderWarehouseUI();
|
||||
} else {
|
||||
return (
|
||||
<div className={"cmpy-mgmt-warehouse-panel"}>
|
||||
<button className={"std-button"} onClick={() => props.eventHandler.purchaseWarehouse(division, props.currentCity)}>
|
||||
Purchase Warehouse ({numeralWrapper.formatMoney(CorporationConstants.WarehouseInitialCost)})
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// React components for the levelable upgrade buttons on the overview panel
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
export class LevelableUpgrade extends BaseReactComponent {
|
||||
render() {
|
||||
const data = this.props.upgradeData;
|
||||
const level = this.props.upgradeLevel;
|
||||
|
||||
const baseCost = data[1];
|
||||
const priceMult = data[2];
|
||||
const cost = baseCost * Math.pow(priceMult, level);
|
||||
|
||||
const text = `${data[4]} - ${numeralWrapper.formatMoney(cost)}`
|
||||
const tooltip = data[5];
|
||||
const onClick = () => {
|
||||
const corp = this.corp();
|
||||
if (corp.funds.lt(cost)) {
|
||||
dialogBoxCreate("Insufficient funds");
|
||||
} else {
|
||||
corp.upgrade(data);
|
||||
corp.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
|
||||
{text}
|
||||
<span className={"tooltiptext"}>{tooltip}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
39
src/Corporation/ui/LevelableUpgrade.tsx
Normal file
39
src/Corporation/ui/LevelableUpgrade.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
// React components for the levelable upgrade buttons on the overview panel
|
||||
import React from "react";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
interface IProps {
|
||||
upgradeData: number[];
|
||||
upgradeLevel: number;
|
||||
corp: any;
|
||||
}
|
||||
|
||||
export function LevelableUpgrade(props: IProps): React.ReactElement {
|
||||
const data = props.upgradeData;
|
||||
const level = props.upgradeLevel;
|
||||
|
||||
const baseCost = data[1];
|
||||
const priceMult = data[2];
|
||||
const cost = baseCost * Math.pow(priceMult, level);
|
||||
|
||||
const text = `${data[4]} - ${numeralWrapper.formatMoney(cost)}`
|
||||
const tooltip = data[5];
|
||||
function onClick() {
|
||||
const corp = props.corp;
|
||||
if (corp.funds.lt(cost)) {
|
||||
dialogBoxCreate("Insufficient funds");
|
||||
} else {
|
||||
corp.upgrade(data);
|
||||
corp.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
|
||||
{text}
|
||||
<span className={"tooltiptext"}>{tooltip}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -8,7 +8,7 @@ import { CityTabs } from "./CityTabs";
|
||||
import { Industry } from "./Industry";
|
||||
import { Overview } from "./Overview";
|
||||
|
||||
import { OfficeSpace } from "../Corporation";
|
||||
import { OfficeSpace } from "../OfficeSpace";
|
||||
|
||||
import { CityName } from "../../Locations/data/CityNames";
|
||||
|
||||
@ -80,6 +80,7 @@ export class MainPanel extends BaseReactComponent {
|
||||
const cityTabs = (
|
||||
<CityTabs
|
||||
{...this.props}
|
||||
corp={this.props.corp}
|
||||
city={this.state.city}
|
||||
onClicks={onClicks}
|
||||
cityStateSetter={this.changeCityState.bind(this)}
|
||||
|
@ -1,10 +1,9 @@
|
||||
// React Component for displaying Corporation Overview info
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
import { LevelableUpgrade } from "./LevelableUpgrade";
|
||||
import { UnlockUpgrade } from "./UnlockUpgrade";
|
||||
|
||||
import { BribeThreshold } from "../Corporation";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { CorporationUnlockUpgrades } from "../data/CorporationUnlockUpgrades";
|
||||
import { CorporationUpgrades } from "../data/CorporationUpgrades";
|
||||
|
||||
@ -12,9 +11,14 @@ import { CONSTANTS } from "../../Constants";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
|
||||
export class Overview extends BaseReactComponent {
|
||||
interface IProps {
|
||||
corp: any;
|
||||
eventHandler: any;
|
||||
}
|
||||
|
||||
export function Overview(props: IProps): React.ReactElement {
|
||||
// Generic Function for Creating a button
|
||||
createButton(props) {
|
||||
function createButton(props: any) {
|
||||
let className = props.class ? props.class : "std-button";
|
||||
const displayStyle = props.display ? props.display : "block";
|
||||
const hasTooltip = (props.tooltip != null);
|
||||
@ -23,7 +27,7 @@ export class Overview extends BaseReactComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<a className={className} onClick={props.onClick} style={{display: {displayStyle}}}>
|
||||
<a className={className} onClick={props.onClick} style={{display: displayStyle}}>
|
||||
{props.text}
|
||||
{
|
||||
hasTooltip &&
|
||||
@ -33,59 +37,58 @@ export class Overview extends BaseReactComponent {
|
||||
}
|
||||
</a>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Returns a string with general information about Corporation
|
||||
getOverviewText() {
|
||||
function getOverviewText() {
|
||||
// Formatted text for profit
|
||||
var profit = this.corp().revenue.minus(this.corp().expenses).toNumber(),
|
||||
const profit = props.corp.revenue.minus(props.corp.expenses).toNumber(),
|
||||
profitStr = profit >= 0 ? numeralWrapper.formatMoney(profit) : "-" + numeralWrapper.format(-1 * profit, "$0.000a");
|
||||
|
||||
// Formatted text for dividend information, if applicable
|
||||
let dividendStr = "";
|
||||
if (this.corp().dividendPercentage > 0 && profit > 0) {
|
||||
const totalDividends = (this.corp().dividendPercentage / 100) * profit;
|
||||
if (props.corp.dividendPercentage > 0 && profit > 0) {
|
||||
const totalDividends = (props.corp.dividendPercentage / 100) * profit;
|
||||
const retainedEarnings = profit - totalDividends;
|
||||
const dividendsPerShare = totalDividends / this.corp().totalShares;
|
||||
const playerEarnings = this.corp().numShares * dividendsPerShare;
|
||||
const dividendsPerShare = totalDividends / props.corp.totalShares;
|
||||
const playerEarnings = props.corp.numShares * dividendsPerShare;
|
||||
|
||||
dividendStr = `Retained Profits (after dividends): ${numeralWrapper.format(retainedEarnings, "$0.000a")} / s<br><br>` +
|
||||
`Dividend Percentage: ${numeralWrapper.format(this.corp().dividendPercentage / 100, "0%")}<br>` +
|
||||
`Dividend Percentage: ${numeralWrapper.format(props.corp.dividendPercentage / 100, "0%")}<br>` +
|
||||
`Dividends per share: ${numeralWrapper.format(dividendsPerShare, "$0.000a")} / s<br>` +
|
||||
`Your earnings as a shareholder (Pre-Tax): ${numeralWrapper.format(playerEarnings, "$0.000a")} / s<br>` +
|
||||
`Dividend Tax Rate: ${this.corp().dividendTaxPercentage}%<br>` +
|
||||
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (this.corp().dividendTaxPercentage / 100)), "$0.000a")} / s<br><br>`;
|
||||
`Dividend Tax Rate: ${props.corp.dividendTaxPercentage}%<br>` +
|
||||
`Your earnings as a shareholder (Post-Tax): ${numeralWrapper.format(playerEarnings * (1 - (props.corp.dividendTaxPercentage / 100)), "$0.000a")} / s<br><br>`;
|
||||
}
|
||||
|
||||
let txt = "Total Funds: " + numeralWrapper.format(this.corp().funds.toNumber(), '$0.000a') + "<br>" +
|
||||
"Total Revenue: " + numeralWrapper.format(this.corp().revenue.toNumber(), "$0.000a") + " / s<br>" +
|
||||
"Total Expenses: " + numeralWrapper.format(this.corp().expenses.toNumber(), "$0.000a") + " / s<br>" +
|
||||
let txt = "Total Funds: " + numeralWrapper.format(props.corp.funds.toNumber(), '$0.000a') + "<br>" +
|
||||
"Total Revenue: " + numeralWrapper.format(props.corp.revenue.toNumber(), "$0.000a") + " / s<br>" +
|
||||
"Total Expenses: " + numeralWrapper.format(props.corp.expenses.toNumber(), "$0.000a") + " / s<br>" +
|
||||
"Total Profits: " + profitStr + " / s<br>" +
|
||||
dividendStr +
|
||||
"Publicly Traded: " + (this.corp().public ? "Yes" : "No") + "<br>" +
|
||||
"Owned Stock Shares: " + numeralWrapper.format(this.corp().numShares, '0.000a') + "<br>" +
|
||||
"Stock Price: " + (this.corp().public ? numeralWrapper.formatMoney(this.corp().sharePrice) : "N/A") + "<br>" +
|
||||
"<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(this.corp().totalShares, "0.000a") +
|
||||
"Publicly Traded: " + (props.corp.public ? "Yes" : "No") + "<br>" +
|
||||
"Owned Stock Shares: " + numeralWrapper.format(props.corp.numShares, '0.000a') + "<br>" +
|
||||
"Stock Price: " + (props.corp.public ? numeralWrapper.formatMoney(props.corp.sharePrice) : "N/A") + "<br>" +
|
||||
"<p class='tooltip'>Total Stock Shares: " + numeralWrapper.format(props.corp.totalShares, "0.000a") +
|
||||
"<span class='tooltiptext'>" +
|
||||
`Outstanding Shares: ${numeralWrapper.format(this.corp().issuedShares, "0.000a")}<br>` +
|
||||
`Private Shares: ${numeralWrapper.format(this.corp().totalShares - this.corp().issuedShares - this.corp().numShares, "0.000a")}` +
|
||||
`Outstanding Shares: ${numeralWrapper.format(props.corp.issuedShares, "0.000a")}<br>` +
|
||||
`Private Shares: ${numeralWrapper.format(props.corp.totalShares - props.corp.issuedShares - props.corp.numShares, "0.000a")}` +
|
||||
"</span></p><br><br>";
|
||||
|
||||
const storedTime = this.corp().storedCycles * CONSTANTS.MilliPerCycle;
|
||||
const storedTime = props.corp.storedCycles * CONSTANTS.MilliPerCycle;
|
||||
if (storedTime > 15000) {
|
||||
txt += `Bonus time: ${convertTimeMsToTimeElapsedString(storedTime)}<br><br>`;
|
||||
}
|
||||
|
||||
let prodMult = this.corp().getProductionMultiplier(),
|
||||
storageMult = this.corp().getStorageMultiplier(),
|
||||
advMult = this.corp().getAdvertisingMultiplier(),
|
||||
empCreMult = this.corp().getEmployeeCreMultiplier(),
|
||||
empChaMult = this.corp().getEmployeeChaMultiplier(),
|
||||
empIntMult = this.corp().getEmployeeIntMultiplier(),
|
||||
empEffMult = this.corp().getEmployeeEffMultiplier(),
|
||||
salesMult = this.corp().getSalesMultiplier(),
|
||||
sciResMult = this.corp().getScientificResearchMultiplier();
|
||||
const prodMult = props.corp.getProductionMultiplier(),
|
||||
storageMult = props.corp.getStorageMultiplier(),
|
||||
advMult = props.corp.getAdvertisingMultiplier(),
|
||||
empCreMult = props.corp.getEmployeeCreMultiplier(),
|
||||
empChaMult = props.corp.getEmployeeChaMultiplier(),
|
||||
empIntMult = props.corp.getEmployeeIntMultiplier(),
|
||||
empEffMult = props.corp.getEmployeeEffMultiplier(),
|
||||
salesMult = props.corp.getSalesMultiplier(),
|
||||
sciResMult = props.corp.getScientificResearchMultiplier();
|
||||
if (prodMult > 1) {txt += "Production Multiplier: " + numeralWrapper.format(prodMult, "0.000") + "<br>";}
|
||||
if (storageMult > 1) {txt += "Storage Multiplier: " + numeralWrapper.format(storageMult, "0.000") + "<br>";}
|
||||
if (advMult > 1) {txt += "Advertising Multiplier: " + numeralWrapper.format(advMult, "0.000") + "<br>";}
|
||||
@ -101,11 +104,11 @@ export class Overview extends BaseReactComponent {
|
||||
|
||||
// Render the buttons that lie below the overview text.
|
||||
// These are mainly for things such as managing finances/stock
|
||||
renderButtons() {
|
||||
function renderButtons() {
|
||||
// Create a "Getting Started Guide" button that lets player view the
|
||||
// handbook and adds it to the players home computer
|
||||
const getStarterGuideOnClick = this.corp().getStarterGuide.bind(this.corp());
|
||||
const getStarterGuideBtn = this.createButton({
|
||||
const getStarterGuideOnClick = props.corp.getStarterGuide.bind(props.corp);
|
||||
const getStarterGuideBtn = createButton({
|
||||
class: "a-link-button",
|
||||
display: "inline-block",
|
||||
onClick: getStarterGuideOnClick,
|
||||
@ -117,13 +120,12 @@ export class Overview extends BaseReactComponent {
|
||||
|
||||
// Create a "Bribe Factions" button if your Corporation is powerful enough.
|
||||
// This occurs regardless of whether you're public or private
|
||||
const canBribe = (this.corp().determineValuation() >= BribeThreshold);
|
||||
const bribeFactionsOnClick = this.eventHandler().createBribeFactionsPopup.bind(this.eventHandler());
|
||||
const canBribe = (props.corp.determineValuation() >= CorporationConstants.BribeThreshold);
|
||||
const bribeFactionsClass = (canBribe ? "a-link-button" : "a-link-button-inactive");
|
||||
const bribeFactionsBtn = this.createButton({
|
||||
const bribeFactionsBtn = createButton({
|
||||
class: bribeFactionsClass,
|
||||
display: "inline-block",
|
||||
onClick: bribeFactionsOnClick,
|
||||
onClick: props.eventHandler.createBribeFactionsPopup,
|
||||
text: "Bribe Factions",
|
||||
tooltip: (canBribe
|
||||
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
|
||||
@ -136,34 +138,36 @@ export class Overview extends BaseReactComponent {
|
||||
getStarterGuide: getStarterGuideBtn,
|
||||
};
|
||||
|
||||
if (this.corp().public) {
|
||||
return this.renderPublicButtons(generalBtns);
|
||||
if (props.corp.public) {
|
||||
return renderPublicButtons(generalBtns);
|
||||
} else {
|
||||
return this.renderPrivateButtons(generalBtns);
|
||||
return renderPrivateButtons(generalBtns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Render the buttons for when your Corporation is still private
|
||||
renderPrivateButtons(generalBtns) {
|
||||
const fundingAvailable = (this.corp().fundingRound < 4);
|
||||
function renderPrivateButtons(generalBtns: any) {
|
||||
const fundingAvailable = (props.corp.fundingRound < 4);
|
||||
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
|
||||
const findInvestorsTooltip = fundingAvailable ? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company" : null;
|
||||
|
||||
const findInvestorsOnClick = this.corp().getInvestment.bind(this.corp());
|
||||
const goPublicOnClick = this.corp().goPublic.bind(this.corp());
|
||||
const findInvestorsOnClick = props.corp.getInvestment.bind(props.corp);
|
||||
const goPublicOnClick = props.corp.goPublic.bind(props.corp);
|
||||
|
||||
const findInvestorsBtn = this.createButton({
|
||||
const findInvestorsBtn = createButton({
|
||||
class: findInvestorsClassName,
|
||||
onClick: findInvestorsOnClick,
|
||||
style: "inline-block",
|
||||
text: "Find Investors",
|
||||
tooltip: findInvestorsTooltip,
|
||||
display: "inline-block",
|
||||
});
|
||||
const goPublicBtn = this.createButton({
|
||||
const goPublicBtn = createButton({
|
||||
class: "std-button",
|
||||
onClick: goPublicOnClick,
|
||||
style: "inline-block",
|
||||
display: "inline-block",
|
||||
text: "Go Public",
|
||||
tooltip: "Become a publicly traded and owned entity. Going public " +
|
||||
"involves issuing shares for an IPO. Once you are a public " +
|
||||
@ -183,10 +187,9 @@ export class Overview extends BaseReactComponent {
|
||||
}
|
||||
|
||||
// Render the buttons for when your Corporation has gone public
|
||||
renderPublicButtons(generalBtns) {
|
||||
const corp = this.corp();
|
||||
function renderPublicButtons(generalBtns: any) {
|
||||
const corp = props.corp;
|
||||
|
||||
const sellSharesOnClick = this.eventHandler().createSellSharesPopup.bind(this.eventHandler());
|
||||
const sellSharesOnCd = (corp.shareSaleCooldown > 0);
|
||||
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
|
||||
const sellSharesTooltip = sellSharesOnCd
|
||||
@ -194,45 +197,42 @@ export class Overview extends BaseReactComponent {
|
||||
: "Sell your shares in the company. The money earned from selling your " +
|
||||
"shares goes into your personal account, not the Corporation's. " +
|
||||
"This is one of the only ways to profit from your business venture."
|
||||
const sellSharesBtn = this.createButton({
|
||||
const sellSharesBtn = createButton({
|
||||
class: sellSharesClass,
|
||||
display: "inline-block",
|
||||
onClick: function(event) {
|
||||
onClick: function(event: MouseEvent) {
|
||||
if(!event.isTrusted) return;
|
||||
sellSharesOnClick(event);
|
||||
props.eventHandler.createSellSharesPopup(event);
|
||||
},
|
||||
text: "Sell Shares",
|
||||
tooltip: sellSharesTooltip,
|
||||
});
|
||||
|
||||
const buybackSharesOnClick = this.eventHandler().createBuybackSharesPopup.bind(this.eventHandler());
|
||||
const buybackSharesBtn = this.createButton({
|
||||
const buybackSharesBtn = createButton({
|
||||
class: "std-button",
|
||||
display: "inline-block",
|
||||
onClick: buybackSharesOnClick,
|
||||
onClick: props.eventHandler.createBuybackSharesPopup,
|
||||
text: "Buyback shares",
|
||||
tooltip: "Buy back shares you that previously issued or sold at market price.",
|
||||
});
|
||||
|
||||
const issueNewSharesOnClick = this.eventHandler().createIssueNewSharesPopup.bind(this.eventHandler());
|
||||
const issueNewSharesOnCd = (corp.issueNewSharesCooldown > 0);
|
||||
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
|
||||
const issueNewSharesTooltip = issueNewSharesOnCd
|
||||
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
|
||||
: "Issue new equity shares to raise capital.";
|
||||
const issueNewSharesBtn = this.createButton({
|
||||
const issueNewSharesBtn = createButton({
|
||||
class: issueNewSharesClass,
|
||||
display: "inline-block",
|
||||
onClick: issueNewSharesOnClick,
|
||||
onClick: props.eventHandler.createIssueNewSharesPopup,
|
||||
text: "Issue New Shares",
|
||||
tooltip: issueNewSharesTooltip,
|
||||
});
|
||||
|
||||
const issueDividendsOnClick = this.eventHandler().createIssueDividendsPopup.bind(this.eventHandler());
|
||||
const issueDividendsBtn = this.createButton({
|
||||
const issueDividendsBtn = createButton({
|
||||
class: "std-button",
|
||||
display: "inline-block",
|
||||
onClick: issueDividendsOnClick,
|
||||
onClick: props.eventHandler.createIssueDividendsPopup,
|
||||
text: "Issue Dividends",
|
||||
tooltip: "Manage the dividends that are paid out to shareholders (including yourself)",
|
||||
});
|
||||
@ -252,23 +252,27 @@ export class Overview extends BaseReactComponent {
|
||||
}
|
||||
|
||||
// Render the UI for Corporation upgrades
|
||||
renderUpgrades() {
|
||||
function renderUpgrades() {
|
||||
// Don't show upgrades
|
||||
if (this.corp().divisions.length <= 0) { return; }
|
||||
if (props.corp.divisions.length <= 0) { return; }
|
||||
|
||||
// Create an array of all Unlocks
|
||||
const unlockUpgrades = [];
|
||||
const unlockUpgrades: React.ReactElement[] = [];
|
||||
Object.values(CorporationUnlockUpgrades).forEach((unlockData) => {
|
||||
if (this.corp().unlockUpgrades[unlockData[0]] === 0) {
|
||||
unlockUpgrades.push(this.renderUnlockUpgrade(unlockData));
|
||||
if (props.corp.unlockUpgrades[unlockData[0]] === 0) {
|
||||
unlockUpgrades.push(<UnlockUpgrade
|
||||
corp={props.corp}
|
||||
upgradeData={unlockData}
|
||||
key={unlockData[0]}
|
||||
/>);
|
||||
}
|
||||
});
|
||||
|
||||
// Create an array of properties of all unlocks
|
||||
const levelableUpgradeProps = [];
|
||||
for (let i = 0; i < this.corp().upgrades.length; ++i) {
|
||||
for (let i = 0; i < props.corp.upgrades.length; ++i) {
|
||||
const upgradeData = CorporationUpgrades[i];
|
||||
const level = this.corp().upgrades[i];
|
||||
const level = props.corp.upgrades[i];
|
||||
|
||||
levelableUpgradeProps.push({
|
||||
upgradeData: upgradeData,
|
||||
@ -284,44 +288,25 @@ export class Overview extends BaseReactComponent {
|
||||
|
||||
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
|
||||
{
|
||||
levelableUpgradeProps.map((data) => {
|
||||
return this.renderLevelableUpgrade(data);
|
||||
})
|
||||
levelableUpgradeProps.map((data: any) => <LevelableUpgrade
|
||||
corp={props.corp}
|
||||
upgradeData={data.upgradeData}
|
||||
upgradeLevel={data.upgradeLevel}
|
||||
key={data.upgradeData[0]}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderUnlockUpgrade(data) {
|
||||
return (
|
||||
<UnlockUpgrade
|
||||
{...this.props}
|
||||
upgradeData={data}
|
||||
key={data[0]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
renderLevelableUpgrade(data) {
|
||||
return (
|
||||
<LevelableUpgrade
|
||||
{...this.props}
|
||||
upgradeData={data.upgradeData}
|
||||
upgradeLevel={data.upgradeLevel}
|
||||
key={data.upgradeData[0]}
|
||||
/>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p dangerouslySetInnerHTML={{__html: this.getOverviewText()}}></p>
|
||||
{this.renderButtons()}
|
||||
<br />
|
||||
{this.renderUpgrades()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p dangerouslySetInnerHTML={{__html: getOverviewText()}}></p>
|
||||
{renderButtons()}
|
||||
<br />
|
||||
{renderUpgrades()}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// React Components for the Unlock upgrade buttons on the overview page
|
||||
import React from "react";
|
||||
import { BaseReactComponent } from "./BaseReactComponent";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
export class UnlockUpgrade extends BaseReactComponent {
|
||||
render() {
|
||||
const data = this.props.upgradeData;
|
||||
const text = `${data[2]} - ${numeralWrapper.formatMoney(data[1])}`;
|
||||
const tooltip = data[3];
|
||||
const onClick = () => {
|
||||
const corp = this.corp();
|
||||
if (corp.funds.lt(data[1])) {
|
||||
dialogBoxCreate("Insufficient funds");
|
||||
} else {
|
||||
corp.unlock(data);
|
||||
corp.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
|
||||
{text}
|
||||
<span className={"tooltiptext"}>{tooltip}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
32
src/Corporation/ui/UnlockUpgrade.tsx
Normal file
32
src/Corporation/ui/UnlockUpgrade.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
// React Components for the Unlock upgrade buttons on the overview page
|
||||
import React from "react";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
interface IProps {
|
||||
upgradeData: number[];
|
||||
corp: any;
|
||||
}
|
||||
|
||||
export function UnlockUpgrade(props: IProps): React.ReactElement {
|
||||
const data = props.upgradeData;
|
||||
const text = `${data[2]} - ${numeralWrapper.formatMoney(data[1])}`;
|
||||
const tooltip = data[3];
|
||||
function onClick() {
|
||||
const corp = props.corp;
|
||||
if (corp.funds.lt(data[1])) {
|
||||
dialogBoxCreate("Insufficient funds");
|
||||
} else {
|
||||
corp.unlock(data);
|
||||
corp.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{"width" : "45%"}} onClick={onClick}>
|
||||
{text}
|
||||
<span className={"tooltiptext"}>{tooltip}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
2
src/InteractiveTutorial.d.ts
vendored
2
src/InteractiveTutorial.d.ts
vendored
@ -1,3 +1,3 @@
|
||||
export declare function iTutorialNextStep(): void;
|
||||
export declare const ITutorial: {isRunning: boolean, currStep: number};
|
||||
export declare const ITutorial: {isRunning: boolean; currStep: number};
|
||||
export declare const iTutorialSteps: {[key: string]: number};
|
Loading…
Reference in New Issue
Block a user