Merge pull request #3812 from stalefishies/corp-remove-async

CORPORATION: (BREAKING) Remove async
This commit is contained in:
hydroflame
2022-07-20 17:02:52 -04:00
committed by GitHub
14 changed files with 556 additions and 540 deletions
+39 -29
View File
@@ -13,8 +13,6 @@ import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade } from "./data/CorporationUpgrades"; import { CorporationUpgrade } from "./data/CorporationUpgrades";
import { Cities } from "../Locations/Cities"; import { Cities } from "../Locations/Cities";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { Employee } from "./Employee";
import { IndustryUpgrades } from "./IndustryUpgrades";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers"; import { isRelevantMaterial } from "./ui/Helpers";
@@ -304,9 +302,19 @@ export function BuyBackShares(corporation: ICorporation, player: IPlayer, numSha
return true; return true;
} }
export function AssignJob(employee: Employee, job: string): void { export function AssignJob(office: OfficeSpace, employeeName: string, job: string): void {
const employee = office.employees.find((e) => e.name === employeeName);
if (!employee) throw new Error(`Could not find employee '${name}'.`);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
employee.pos = job;
office.assignSingleJob(employee, job);
}
export function AutoAssignJob(office: OfficeSpace, job: string, count: number): boolean {
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
return office.autoAssignJob(job, count);
} }
export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: number): void { export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: number): void {
@@ -323,15 +331,32 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size:
corp.funds = corp.funds - cost; corp.funds = corp.funds - cost;
} }
export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number { export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean {
const totalCost = costPerEmployee * office.employees.length; const cost = office.getCoffeeCost();
if (corp.funds < totalCost) return 0; if (corp.funds < cost) {
corp.funds = corp.funds - totalCost; return false;
let mult = 0;
for (let i = 0; i < office.employees.length; ++i) {
mult = office.employees[i].throwParty(costPerEmployee);
} }
if (!office.setCoffee()) {
return false;
}
corp.funds -= cost;
return true;
}
export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number {
const mult = 1 + costPerEmployee / 10e6;
const cost = costPerEmployee * office.employees.length;
if (corp.funds < cost) {
return 0;
}
if (!office.setParty(mult)) {
return 0;
}
corp.funds -= cost;
return mult; return mult;
} }
@@ -362,26 +387,11 @@ export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, wareho
corp.funds = corp.funds - sizeUpgradeCost; corp.funds = corp.funds - sizeUpgradeCost;
} }
export function BuyCoffee(corp: ICorporation, division: IIndustry, office: OfficeSpace): void { export function HireAdVert(corp: ICorporation, division: IIndustry): void {
const upgrade = IndustryUpgrades[0]; const cost = division.getAdVertCost();
const cost = office.employees.length * upgrade[1];
if (corp.funds < cost) return; if (corp.funds < cost) return;
corp.funds = corp.funds - cost; corp.funds = corp.funds - cost;
division.upgrade(upgrade, { division.applyAdVert(corp);
corporation: corp,
office: office,
});
}
export function HireAdVert(corp: ICorporation, division: IIndustry, office: OfficeSpace): void {
const upgrade = IndustryUpgrades[1];
const cost = upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]);
if (corp.funds < cost) return;
corp.funds = corp.funds - cost;
division.upgrade(upgrade, {
corporation: corp,
office: office,
});
} }
export function MakeProduct( export function MakeProduct(
+5 -20
View File
@@ -3,7 +3,6 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { ICorporation } from "./ICorporation"; import { ICorporation } from "./ICorporation";
import { OfficeSpace } from "./OfficeSpace";
import { IIndustry } from "./IIndustry"; import { IIndustry } from "./IIndustry";
interface IParams { interface IParams {
@@ -34,6 +33,7 @@ export class Employee {
cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise; cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise;
loc: string; loc: string;
pos: string; pos: string;
nextPos: string;
constructor(params: IParams = {}) { constructor(params: IParams = {}) {
this.name = params.name ? params.name : "Bobby"; this.name = params.name ? params.name : "Bobby";
@@ -52,12 +52,13 @@ export class Employee {
this.loc = params.loc ? params.loc : ""; this.loc = params.loc ? params.loc : "";
this.pos = EmployeePositions.Unassigned; this.pos = EmployeePositions.Unassigned;
this.nextPos = this.pos;
} }
//Returns the amount the employee needs to be paid //Returns the amount the employee needs to be paid
process(marketCycles = 1, office: OfficeSpace): number { process(marketCycles = 1): number {
const gain = 0.003 * marketCycles, const gain = 0.003 * marketCycles;
det = gain * Math.random(); const det = gain * Math.random();
this.exp += gain; this.exp += gain;
//Training //Training
@@ -72,12 +73,6 @@ export class Employee {
this.ene -= det; this.ene -= det;
this.hap -= 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; const salary = this.sal * marketCycles * CorporationConstants.SecsPerMarketCycle;
return salary; return salary;
} }
@@ -118,16 +113,6 @@ export class Employee {
return prodBase * prodMult; return prodBase * prodMult;
} }
//Process benefits from having an office party thrown
throwParty(money: number): 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;
}
toJSON(): any { toJSON(): any {
return Generic_toJSON("Employee", this); return Generic_toJSON("Employee", this);
} }
+3 -4
View File
@@ -3,7 +3,6 @@ import { Warehouse } from "./Warehouse";
import { ICorporation } from "./ICorporation"; import { ICorporation } from "./ICorporation";
import { OfficeSpace } from "./OfficeSpace"; import { OfficeSpace } from "./OfficeSpace";
import { Product } from "./Product"; import { Product } from "./Product";
import { IndustryUpgrade } from "./IndustryUpgrades";
export interface IIndustry { export interface IIndustry {
name: string; name: string;
@@ -36,12 +35,11 @@ export interface IIndustry {
thisCycleRevenue: number; thisCycleRevenue: number;
thisCycleExpenses: number; thisCycleExpenses: number;
upgrades: number[];
state: string; state: string;
newInd: boolean; newInd: boolean;
warehouses: { [key: string]: Warehouse | 0 }; warehouses: { [key: string]: Warehouse | 0 };
offices: { [key: string]: OfficeSpace | 0 }; offices: { [key: string]: OfficeSpace | 0 };
numAdVerts: number;
init(): void; init(): void;
getProductDescriptionText(): string; getProductDescriptionText(): string;
@@ -56,7 +54,8 @@ export interface IIndustry {
processProducts(marketCycles: number, corporation: ICorporation): [number, number]; processProducts(marketCycles: number, corporation: ICorporation): [number, number];
processProduct(marketCycles: number, product: Product, corporation: ICorporation): number; processProduct(marketCycles: number, product: Product, corporation: ICorporation): number;
discontinueProduct(product: Product): void; discontinueProduct(product: Product): void;
upgrade(upgrade: IndustryUpgrade, refs: { corporation: ICorporation; office: OfficeSpace }): void; getAdVertCost(): number;
applyAdVert(corporation: ICorporation): void;
getOfficeProductivity(office: OfficeSpace, params?: { forProduct?: boolean }): number; getOfficeProductivity(office: OfficeSpace, params?: { forProduct?: boolean }): number;
getBusinessFactor(office: OfficeSpace): number; getBusinessFactor(office: OfficeSpace): number;
getAdvertisingFactors(): [number, number, number, number]; getAdvertisingFactors(): [number, number, number, number];
+15 -50
View File
@@ -14,7 +14,6 @@ import { MaterialSizes } from "./MaterialSizes";
import { Warehouse } from "./Warehouse"; import { Warehouse } from "./Warehouse";
import { ICorporation } from "./ICorporation"; import { ICorporation } from "./ICorporation";
import { IIndustry } from "./IIndustry"; import { IIndustry } from "./IIndustry";
import { IndustryUpgrade, IndustryUpgrades } from "./IndustryUpgrades";
interface IParams { interface IParams {
name?: string; name?: string;
@@ -59,9 +58,6 @@ export class Industry implements IIndustry {
thisCycleRevenue: number; thisCycleRevenue: number;
thisCycleExpenses: number; thisCycleExpenses: number;
//Upgrades
upgrades: number[] = Array(Object.keys(IndustryUpgrades).length).fill(0);
state = "START"; state = "START";
newInd = true; newInd = true;
@@ -81,6 +77,8 @@ export class Industry implements IIndustry {
[CityName.Volhaven]: 0, [CityName.Volhaven]: 0,
}; };
numAdVerts = 0;
constructor(params: IParams = {}) { constructor(params: IParams = {}) {
this.name = params.name ? params.name : ""; this.name = params.name ? params.name : "";
this.type = params.type ? params.type : Industries.Agriculture; this.type = params.type ? params.type : Industries.Agriculture;
@@ -1004,23 +1002,9 @@ export class Industry implements IIndustry {
const office = this.offices[city]; const office = this.offices[city];
if (office === 0) continue; if (office === 0) continue;
// Designing/Creating a Product is based mostly off Engineers prod.createProduct(marketCycles, office.employeeProd);
const engrProd = office.employeeProd[EmployeePositions.Engineer];
const mgmtProd = office.employeeProd[EmployeePositions.Management];
const opProd = office.employeeProd[EmployeePositions.Operations];
const total = engrProd + mgmtProd + opProd;
if (total <= 0) {
break;
}
// Management is a multiplier for the production from Engineers
const mgmtFactor = 1 + mgmtProd / (1.2 * total);
const progress = (Math.pow(engrProd, 0.34) + Math.pow(opProd, 0.2)) * mgmtFactor;
prod.createProduct(marketCycles, progress);
if (prod.prog >= 100) { if (prod.prog >= 100) {
prod.finishProduct(office.employeeProd, this); prod.finishProduct(this);
} }
break; break;
} }
@@ -1262,38 +1246,19 @@ export class Industry implements IIndustry {
} }
} }
upgrade(upgrade: IndustryUpgrade, refs: { corporation: ICorporation; office: OfficeSpace }): void { getAdVertCost(): number {
const corporation = refs.corporation; return 1e9 * Math.pow(1.06, this.numAdVerts);
const office = refs.office; }
const upgN = upgrade[0];
while (this.upgrades.length <= upgN) {
this.upgrades.push(0);
}
++this.upgrades[upgN];
switch (upgN) { applyAdVert(corporation: ICorporation): void {
case 0: { const advMult = corporation.getAdvertisingMultiplier() * this.getAdvertisingMultiplier();
//Coffee, 5% energy per employee const awareness = (this.awareness + 3 * advMult) * (1.01 * advMult);
for (let i = 0; i < office.employees.length; ++i) { this.awareness = Math.min(awareness, Number.MAX_VALUE);
office.employees[i].ene = Math.min(office.employees[i].ene * 1.05, office.maxEne);
}
break;
}
case 1: {
//AdVert.Inc,
const advMult = corporation.getAdvertisingMultiplier() * this.getAdvertisingMultiplier();
const awareness = (this.awareness + 3 * advMult) * (1.01 * advMult);
this.awareness = Math.min(awareness, Number.MAX_VALUE);
const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 100) * advMult); const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 100) * advMult);
this.popularity = Math.min(popularity, Number.MAX_VALUE); this.popularity = Math.min(popularity, Number.MAX_VALUE);
break;
} ++this.numAdVerts;
default: {
console.error(`Un-implemented function index: ${upgN}`);
break;
}
}
} }
// Returns how much of a material can be produced based of office productivity (employee stats) // Returns how much of a material can be produced based of office productivity (employee stats)
-22
View File
@@ -1,22 +0,0 @@
import { IMap } from "../types";
export type IndustryUpgrade = [number, number, number, number, string, string];
// Industry upgrades
// The data structure is an array with the following format:
// [index in array, base price, price mult, benefit mult (if applicable), name, desc]
export const IndustryUpgrades: IMap<IndustryUpgrade> = {
"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.",
],
};
+115 -52
View File
@@ -15,11 +15,22 @@ interface IParams {
export class OfficeSpace { export class OfficeSpace {
loc: string; loc: string;
size: number; size: number;
minEne = 0; minEne = 0;
maxEne = 100;
minHap = 0; minHap = 0;
minMor = 0;
maxEne = 100;
maxHap = 100; maxHap = 100;
maxMor = 100; maxMor = 100;
autoCoffee = false;
autoParty = false;
coffeeMult = 0;
partyMult = 0;
coffeeEmployees = 0;
partyEmployees = 0;
employees: Employee[] = []; employees: Employee[] = [];
employeeProd: { [key: string]: number } = { employeeProd: { [key: string]: number } = {
[EmployeePositions.Operations]: 0, [EmployeePositions.Operations]: 0,
@@ -37,7 +48,15 @@ export class OfficeSpace {
[EmployeePositions.RandD]: 0, [EmployeePositions.RandD]: 0,
[EmployeePositions.Training]: 0, [EmployeePositions.Training]: 0,
[EmployeePositions.Unassigned]: 0, [EmployeePositions.Unassigned]: 0,
total: 0, };
employeeNextJobs: { [key: string]: number } = {
[EmployeePositions.Operations]: 0,
[EmployeePositions.Engineer]: 0,
[EmployeePositions.Business]: 0,
[EmployeePositions.Management]: 0,
[EmployeePositions.RandD]: 0,
[EmployeePositions.Training]: 0,
[EmployeePositions.Unassigned]: 0,
}; };
constructor(params: IParams = {}) { constructor(params: IParams = {}) {
@@ -58,12 +77,18 @@ export class OfficeSpace {
} }
} }
// Update employee jobs and job counts
for (const employee of this.employees) {
employee.pos = employee.nextPos;
}
this.calculateTotalEmployees(); this.calculateTotalEmployees();
this.calculateNextEmployees();
// Process Office properties // Process Office properties
this.maxEne = 100; this.maxEne = 100;
this.maxHap = 100; this.maxHap = 100;
this.maxMor = 100; this.maxMor = 100;
if (industry.hasResearch("Go-Juice")) { if (industry.hasResearch("Go-Juice")) {
this.maxEne += 10; this.maxEne += 10;
} }
@@ -73,6 +98,12 @@ export class OfficeSpace {
if (industry.hasResearch("Sti.mu")) { if (industry.hasResearch("Sti.mu")) {
this.maxMor += 10; this.maxMor += 10;
} }
if (industry.hasResearch("AutoBrew")) {
this.autoCoffee = true;
}
if (industry.hasResearch("AutoPartyManager")) {
this.autoParty = true;
}
// Calculate changes in Morale/Happiness/Energy for Employees // Calculate changes in Morale/Happiness/Energy for Employees
let perfMult = 1; //Multiplier for employee morale/happiness/energy based on company performance let perfMult = 1; //Multiplier for employee morale/happiness/energy based on company performance
@@ -82,35 +113,56 @@ export class OfficeSpace {
perfMult = Math.pow(1.01, marketCycles); perfMult = Math.pow(1.01, marketCycles);
} }
const hasAutobrew = industry.hasResearch("AutoBrew"); let totalSalary = 0;
const hasAutoparty = industry.hasResearch("AutoPartyManager"); for (const employee of this.employees) {
const salary = employee.process(marketCycles);
totalSalary += salary;
let salaryPaid = 0; if (this.autoCoffee) {
for (let i = 0; i < this.employees.length; ++i) { employee.ene = this.maxEne;
const emp = this.employees[i]; } else if (this.coffeeMult > 1) {
if (hasAutoparty) { const mult = 1 + ((this.coffeeMult - 1) * this.employees.length) / this.coffeeEmployees;
emp.mor = this.maxMor; employee.ene *= mult;
emp.hap = this.maxHap;
} else { } else {
emp.mor *= perfMult; employee.ene *= perfMult;
emp.hap *= perfMult;
emp.mor = Math.min(emp.mor, this.maxMor);
emp.hap = Math.min(emp.hap, this.maxHap);
} }
if (hasAutobrew) { if (this.autoParty) {
emp.ene = this.maxEne; employee.mor = this.maxMor;
employee.hap = this.maxHap;
} else if (this.partyMult > 1) {
const mult = 1 + ((this.partyMult - 1) * this.employees.length) / this.partyEmployees;
employee.mor *= mult;
employee.hap *= mult;
} else { } else {
emp.ene *= perfMult; employee.mor *= perfMult;
emp.ene = Math.min(emp.ene, this.maxEne); employee.hap *= perfMult;
} }
const salary = emp.process(marketCycles, this); employee.ene = Math.max(Math.min(employee.ene, this.maxEne), this.minEne);
salaryPaid += salary; employee.mor = Math.max(Math.min(employee.mor, this.maxMor), this.minMor);
employee.hap = Math.max(Math.min(employee.hap, this.maxHap), this.minHap);
} }
this.coffeeMult = 0;
this.partyMult = 0;
this.coffeeEmployees = 0;
this.partyEmployees = 0;
this.calculateEmployeeProductivity(corporation, industry); this.calculateEmployeeProductivity(corporation, industry);
return salaryPaid; return totalSalary;
}
calculateNextEmployees(): void {
//Reset
for (const name of Object.keys(this.employeeNextJobs)) {
this.employeeNextJobs[name] = 0;
}
for (let i = 0; i < this.employees.length; ++i) {
const employee = this.employees[i];
this.employeeNextJobs[employee.nextPos]++;
}
} }
calculateTotalEmployees(): void { calculateTotalEmployees(): void {
@@ -123,7 +175,6 @@ export class OfficeSpace {
const employee = this.employees[i]; const employee = this.employees[i];
this.employeeJobs[employee.pos]++; this.employeeJobs[employee.pos]++;
} }
this.employeeJobs.total = this.employees.length;
} }
calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void { calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void {
@@ -173,45 +224,57 @@ export class OfficeSpace {
emp.name = name; emp.name = name;
this.employees.push(emp); this.employees.push(emp);
this.calculateTotalEmployees();
this.calculateNextEmployees();
return emp; return emp;
} }
//Finds the first unassigned employee and assigns its to the specified job assignSingleJob(employee: Employee, job: string): void {
assignEmployeeToJob(job: string): boolean { employee.nextPos = job;
for (let i = 0; i < this.employees.length; ++i) { this.calculateNextEmployees();
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 autoAssignJob(job: string, target: number): boolean {
unassignEmployeeFromJob(job: string): boolean { let count = this.employeeNextJobs[job];
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;
}
setEmployeeToJob(job: string, amount: number): boolean {
let jobCount = this.employees.reduce((acc, employee) => (employee.pos === job ? acc + 1 : acc), 0);
for (const employee of this.employees) { for (const employee of this.employees) {
if (jobCount == amount) return true; if (count === target) {
if (employee.pos === EmployeePositions.Unassigned && jobCount <= amount) { break;
employee.pos = job; } else if (employee.nextPos === EmployeePositions.Unassigned && count <= target) {
jobCount++; employee.nextPos = job;
} else if (employee.pos === job && jobCount >= amount) { count++;
employee.pos = EmployeePositions.Unassigned; } else if (employee.nextPos === job && count >= target) {
jobCount--; employee.nextPos = EmployeePositions.Unassigned;
count--;
} }
} }
return jobCount === amount;
this.calculateNextEmployees();
return count === target;
}
getCoffeeCost(): number {
return 500e3 * this.employees.length;
}
setCoffee(mult = 1.05): boolean {
if (mult > 1 && this.coffeeMult === 0 && !this.autoCoffee && this.employees.length > 0) {
this.coffeeMult = mult;
this.coffeeEmployees = this.employees.length;
return true;
}
return false;
}
setParty(mult: number): boolean {
if (mult > 1 && this.partyMult === 0 && !this.autoParty && this.employees.length > 0) {
this.partyMult = mult;
this.partyEmployees = this.employees.length;
return true;
}
return false;
} }
toJSON(): any { toJSON(): any {
+75 -42
View File
@@ -55,6 +55,16 @@ export class Product {
designCost = 0; // How much money was invested into designing this Product designCost = 0; // How much money was invested into designing this Product
advCost = 0; // How much money was invested into advertising this Product advCost = 0; // How much money was invested into advertising this Product
// The average employee productivity and scientific research across the creation of the Product
creationProd: { [key: string]: number } = {
[EmployeePositions.Operations]: 0,
[EmployeePositions.Engineer]: 0,
[EmployeePositions.Business]: 0,
[EmployeePositions.Management]: 0,
[EmployeePositions.RandD]: 0,
total: 0,
};
// Aggregate score for this Product's 'rating' // Aggregate score for this Product's 'rating'
// This is based on the stats/properties below. The weighting of the // This is based on the stats/properties below. The weighting of the
// stats/properties below differs between different industries // stats/properties below differs between different industries
@@ -117,25 +127,48 @@ export class Product {
this.reqMats = params.req ? params.req : {}; this.reqMats = params.req ? params.req : {};
} }
// empWorkMult is a multiplier that increases progress rate based on // Make progress on this product based on current employee productivity
// productivity of employees createProduct(marketCycles: number, employeeProd: typeof this["creationProd"]): void {
createProduct(marketCycles = 1, empWorkMult = 1): void {
if (this.fin) { if (this.fin) {
return; return;
} }
this.prog += marketCycles * 0.01 * empWorkMult;
// Designing/Creating a Product is based mostly off Engineers
const opProd = employeeProd[EmployeePositions.Operations];
const engrProd = employeeProd[EmployeePositions.Engineer];
const mgmtProd = employeeProd[EmployeePositions.Management];
const total = opProd + engrProd + mgmtProd;
if (total <= 0) {
return;
}
// Management is a multiplier for the production from Engineers
const mgmtFactor = 1 + mgmtProd / (1.2 * total);
const prodMult = (Math.pow(engrProd, 0.34) + Math.pow(opProd, 0.2)) * mgmtFactor;
const progress = Math.min(marketCycles * 0.01 * prodMult, 100 - this.prog);
if (progress <= 0) {
return;
}
this.prog += progress;
for (const pos of Object.keys(employeeProd)) {
console.log(`${pos} ${this.creationProd[pos]} += ${(employeeProd[pos] * progress) / 100}`);
this.creationProd[pos] += (employeeProd[pos] * progress) / 100;
}
} }
// @param industry - Industry object. Reference to industry that makes this Product // @param industry - Industry object. Reference to industry that makes this Product
finishProduct(employeeProd: { [key: string]: number }, industry: IIndustry): void { finishProduct(industry: IIndustry): void {
this.fin = true; this.fin = true;
//Calculate properties // Calculate properties
const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"]; const totalProd = this.creationProd.total;
const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"]; const engrRatio = this.creationProd[EmployeePositions.Engineer] / totalProd;
const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"]; const mgmtRatio = this.creationProd[EmployeePositions.Management] / totalProd;
const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"]; const rndRatio = this.creationProd[EmployeePositions.RandD] / totalProd;
const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"]; const opsRatio = this.creationProd[EmployeePositions.Operations] / totalProd;
const busRatio = this.creationProd[EmployeePositions.Business] / totalProd;
const designMult = 1 + Math.pow(this.designCost, 0.1) / 100; const designMult = 1 + Math.pow(this.designCost, 0.1) / 100;
const balanceMult = 1.2 * engrRatio + 0.9 * mgmtRatio + 1.3 * rndRatio + 1.5 * opsRatio + busRatio; const balanceMult = 1.2 * engrRatio + 0.9 * mgmtRatio + 1.3 * rndRatio + 1.5 * opsRatio + busRatio;
const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800;
@@ -143,49 +176,49 @@ export class Product {
this.qlt = this.qlt =
totalMult * totalMult *
(0.1 * employeeProd[EmployeePositions.Engineer] + (0.1 * this.creationProd[EmployeePositions.Engineer] +
0.05 * employeeProd[EmployeePositions.Management] + 0.05 * this.creationProd[EmployeePositions.Management] +
0.05 * employeeProd[EmployeePositions.RandD] + 0.05 * this.creationProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] + 0.02 * this.creationProd[EmployeePositions.Operations] +
0.02 * employeeProd[EmployeePositions.Business]); 0.02 * this.creationProd[EmployeePositions.Business]);
this.per = this.per =
totalMult * totalMult *
(0.15 * employeeProd[EmployeePositions.Engineer] + (0.15 * this.creationProd[EmployeePositions.Engineer] +
0.02 * employeeProd[EmployeePositions.Management] + 0.02 * this.creationProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] + 0.02 * this.creationProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] + 0.02 * this.creationProd[EmployeePositions.Operations] +
0.02 * employeeProd[EmployeePositions.Business]); 0.02 * this.creationProd[EmployeePositions.Business]);
this.dur = this.dur =
totalMult * totalMult *
(0.05 * employeeProd[EmployeePositions.Engineer] + (0.05 * this.creationProd[EmployeePositions.Engineer] +
0.02 * employeeProd[EmployeePositions.Management] + 0.02 * this.creationProd[EmployeePositions.Management] +
0.08 * employeeProd[EmployeePositions.RandD] + 0.08 * this.creationProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] + 0.05 * this.creationProd[EmployeePositions.Operations] +
0.05 * employeeProd[EmployeePositions.Business]); 0.05 * this.creationProd[EmployeePositions.Business]);
this.rel = this.rel =
totalMult * totalMult *
(0.02 * employeeProd[EmployeePositions.Engineer] + (0.02 * this.creationProd[EmployeePositions.Engineer] +
0.08 * employeeProd[EmployeePositions.Management] + 0.08 * this.creationProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] + 0.02 * this.creationProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] + 0.05 * this.creationProd[EmployeePositions.Operations] +
0.08 * employeeProd[EmployeePositions.Business]); 0.08 * this.creationProd[EmployeePositions.Business]);
this.aes = this.aes =
totalMult * totalMult *
(0.0 * employeeProd[EmployeePositions.Engineer] + (0.0 * this.creationProd[EmployeePositions.Engineer] +
0.08 * employeeProd[EmployeePositions.Management] + 0.08 * this.creationProd[EmployeePositions.Management] +
0.05 * employeeProd[EmployeePositions.RandD] + 0.05 * this.creationProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] + 0.02 * this.creationProd[EmployeePositions.Operations] +
0.1 * employeeProd[EmployeePositions.Business]); 0.1 * this.creationProd[EmployeePositions.Business]);
this.fea = this.fea =
totalMult * totalMult *
(0.08 * employeeProd[EmployeePositions.Engineer] + (0.08 * this.creationProd[EmployeePositions.Engineer] +
0.05 * employeeProd[EmployeePositions.Management] + 0.05 * this.creationProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] + 0.02 * this.creationProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] + 0.05 * this.creationProd[EmployeePositions.Operations] +
0.05 * employeeProd[EmployeePositions.Business]); 0.05 * this.creationProd[EmployeePositions.Business]);
this.calculateRating(industry); this.calculateRating(industry);
const advMult = 1 + Math.pow(this.advCost, 0.1) / 100; const advMult = 1 + Math.pow(this.advCost, 0.1) / 100;
const busmgtgRatio = Math.max(busRatio + mgmtRatio, 1 / employeeProd["total"]); const busmgtgRatio = Math.max(busRatio + mgmtRatio, 1 / totalProd);
this.mku = 100 / (advMult * Math.pow(this.qlt + 0.001, 0.65) * busmgtgRatio); this.mku = 100 / (advMult * Math.pow(this.qlt + 0.001, 0.65) * busmgtgRatio);
// I actually don't understand well enough to know if this is right. // I actually don't understand well enough to know if this is right.
+1 -1
View File
@@ -25,7 +25,7 @@ export function Industry(props: IProps): React.ReactElement {
return ( return (
<Box display="flex"> <Box display="flex">
<Box sx={{ width: "50%" }}> <Box sx={{ width: "50%" }}>
<IndustryOverview rerender={props.rerender} currentCity={props.city} office={props.office} /> <IndustryOverview rerender={props.rerender} />
<IndustryOffice rerender={props.rerender} office={props.office} /> <IndustryOffice rerender={props.rerender} office={props.office} />
</Box> </Box>
<Box sx={{ width: "50%" }}> <Box sx={{ width: "50%" }}>
+212 -184
View File
@@ -5,7 +5,9 @@ import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace"; import { OfficeSpace } from "../OfficeSpace";
import { Employee } from "../Employee"; import { Employee } from "../Employee";
import { EmployeePositions } from "../EmployeePositions"; import { EmployeePositions } from "../EmployeePositions";
import { BuyCoffee } from "../Actions";
import { MoneyCost } from "./MoneyCost";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { UpgradeOfficeSizeModal } from "./modals/UpgradeOfficeSizeModal"; import { UpgradeOfficeSizeModal } from "./modals/UpgradeOfficeSizeModal";
@@ -17,6 +19,7 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import IconButton from "@mui/material/IconButton"; import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp"; import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@@ -33,14 +36,6 @@ interface IProps {
rerender: () => void; rerender: () => void;
} }
function countEmployee(employees: Employee[], job: string): number {
let n = 0;
for (let i = 0; i < employees.length; ++i) {
if (employees[i].pos === job) n++;
}
return n;
}
interface ISwitchProps { interface ISwitchProps {
manualMode: boolean; manualMode: boolean;
switchMode: (f: (b: boolean) => boolean) => void; switchMode: (f: (b: boolean) => boolean) => void;
@@ -115,14 +110,14 @@ function ManualManagement(props: IProps): React.ReactElement {
{positionNames[i]} {positionNames[i]}
</MenuItem>, </MenuItem>,
); );
if (emp != null && emp.pos === positionNames[i]) { if (emp != null && emp.nextPos === positionNames[i]) {
employeePositionSelectorInitialValue = positionNames[i]; employeePositionSelectorInitialValue = emp.nextPos;
} }
} }
function employeePositionSelectorOnChange(e: SelectChangeEvent<string>): void { function employeePositionSelectorOnChange(e: SelectChangeEvent<string>): void {
if (employee === null) return; if (employee === null) return;
employee.pos = e.target.value; props.office.assignSingleJob(employee, e.target.value);
props.rerender(); props.rerender();
} }
@@ -178,41 +173,53 @@ interface IAutoAssignProps {
rerender: () => void; rerender: () => void;
} }
function EmployeeCount(props: { num: number; next: number }): React.ReactElement {
return (
<Typography display="flex" alignItems="center" justifyContent="flex-end">
{props.num === props.next ? null : props.num}
{props.num === props.next ? null : <ArrowForwardIcon fontSize="inherit"/>}
{props.next}
</Typography>
);
}
function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
const corp = useCorporation(); const currJob = props.office.employeeJobs[props.job];
const division = useDivision(); const nextJob = props.office.employeeNextJobs[props.job];
const numJob = countEmployee(props.office.employees, props.job); const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
function assignEmployee(): void { function assignEmployee(): void {
if (numUnassigned <= 0) { if (nextUna <= 0) {
console.warn("Cannot assign employee. No unassigned employees available"); console.warn("Cannot assign employee. No unassigned employees available");
return; return;
} }
props.office.assignEmployeeToJob(props.job); props.office.autoAssignJob(props.job, nextJob + 1);
props.office.calculateEmployeeProductivity(corp, division);
props.rerender(); props.rerender();
} }
function unassignEmployee(): void { function unassignEmployee(): void {
props.office.unassignEmployeeFromJob(props.job); props.office.autoAssignJob(props.job, nextJob - 1);
props.office.calculateEmployeeProductivity(corp, division);
props.rerender(); props.rerender();
} }
return ( return (
<TableRow> <TableRow>
<TableCell> <TableCell>
<Tooltip title={props.desc}> <Tooltip title={props.desc}>
<Typography> <Typography>{props.job}</Typography>
{props.job} ({numJob})
</Typography>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
<TableCell> <TableCell>
<IconButton disabled={numUnassigned === 0} onClick={assignEmployee}> <EmployeeCount num={currJob} next={nextJob} />
</TableCell>
<TableCell width="1px">
<IconButton disabled={nextUna === 0} onClick={assignEmployee}>
<ArrowDropUpIcon /> <ArrowDropUpIcon />
</IconButton> </IconButton>
<IconButton disabled={numJob === 0} onClick={unassignEmployee}> </TableCell>
<TableCell width="1px">
<IconButton disabled={nextJob === 0} onClick={unassignEmployee}>
<ArrowDropDownIcon /> <ArrowDropDownIcon />
</IconButton> </IconButton>
</TableCell> </TableCell>
@@ -223,7 +230,6 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
function AutoManagement(props: IProps): React.ReactElement { function AutoManagement(props: IProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); const division = useDivision();
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade
// Calculate average morale, happiness, energy, and salary. // Calculate average morale, happiness, energy, and salary.
@@ -247,168 +253,164 @@ function AutoManagement(props: IProps): React.ReactElement {
avgEnergy = totalEnergy / props.office.employees.length; avgEnergy = totalEnergy / props.office.employees.length;
} }
const currUna = props.office.employeeJobs[EmployeePositions.Unassigned];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
return ( return (
<> <Table padding="none">
<Table padding="none"> <TableBody>
<TableBody> <TableRow>
<TableRow> <TableCell>
<TableCell> <Typography>Unassigned Employees:</Typography>
<Typography>Unassigned Employees:</Typography> </TableCell>
</TableCell> <TableCell>
<TableCell> <EmployeeCount num={currUna} next={nextUna} />
<Typography>{numUnassigned}</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Typography>Avg Employee Morale:</Typography>
<Typography>Avg Employee Morale:</Typography> </TableCell>
</TableCell> <TableCell align="right">
<TableCell> <Typography>{numeralWrapper.format(avgMorale, "0.000")}</Typography>
<Typography>{numeralWrapper.format(avgMorale, "0.000")}</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Typography>Avg Employee Happiness:</Typography>
<Typography>Avg Employee Happiness:</Typography> </TableCell>
</TableCell> <TableCell align="right">
<TableCell> <Typography>{numeralWrapper.format(avgHappiness, "0.000")}</Typography>
<Typography>{numeralWrapper.format(avgHappiness, "0.000")}</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Typography>Avg Employee Energy:</Typography>
<Typography>Avg Employee Energy:</Typography> </TableCell>
</TableCell> <TableCell align="right">
<TableCell> <Typography>{numeralWrapper.format(avgEnergy, "0.000")}</Typography>
<Typography>{numeralWrapper.format(avgEnergy, "0.000")}</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Typography>Total Employee Salary:</Typography>
<Typography>Total Employee Salary:</Typography> </TableCell>
</TableCell> <TableCell>
<TableCell> <Typography align="right">
<Typography> <Money money={totalSalary} />
<Money money={totalSalary} /> </Typography>
</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> {vechain && (
{vechain && ( <>
<> <TableRow>
<TableRow> <TableCell>
<TableCell> <Tooltip
<Tooltip title={
title={ <Typography>
<Typography> The base amount of material this office can produce. Does not include production multipliers from
The base amount of material this office can produce. Does not include production multipliers upgrades and materials. This value is based off the productivity of your Operations, Engineering,
from upgrades and materials. This value is based off the productivity of your Operations, and Management employees
Engineering, and Management employees </Typography>
</Typography> }
} >
> <Typography>Material Production:</Typography>
<Typography>Material Production:</Typography> </Tooltip>
</Tooltip> </TableCell>
</TableCell> <TableCell>
<TableCell> <Typography align="right">
<Typography> {numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")}
{numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")} </Typography>
</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Tooltip
<Tooltip title={
title={ <Typography>
<Typography> The base amount of any given Product this office can produce. Does not include production
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
multipliers from upgrades and materials. This value is based off the productivity of your Operations, Engineering, and Management employees
Operations, Engineering, and Management employees </Typography>
</Typography> }
} >
> <Typography>Product Production:</Typography>
<Typography>Product Production:</Typography> </Tooltip>
</Tooltip> </TableCell>
</TableCell> <TableCell>
<TableCell> <Typography align="right">
<Typography> {numeralWrapper.format(
{numeralWrapper.format( division.getOfficeProductivity(props.office, {
division.getOfficeProductivity(props.office, { forProduct: true,
forProduct: true, }),
}), "0.000",
"0.000", )}
)} </Typography>
</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> <TableRow>
<TableRow> <TableCell>
<TableCell> <Tooltip
<Tooltip title={<Typography>The effect this office's 'Business' employees has on boosting sales</Typography>}
title={<Typography>The effect this office's 'Business' employees has on boosting sales</Typography>} >
> <Typography> Business Multiplier:</Typography>
<Typography> Business Multiplier:</Typography> </Tooltip>
</Tooltip> </TableCell>
</TableCell> <TableCell align="right">
<TableCell> <Typography>x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")}</Typography>
<Typography>x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")}</Typography> </TableCell>
</TableCell> </TableRow>
</TableRow> </>
</> )}
)} <AutoAssignJob
</TableBody> rerender={props.rerender}
</Table> office={props.office}
job={EmployeePositions.Operations}
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."}
/>
<Table padding="none"> <AutoAssignJob
<TableBody> rerender={props.rerender}
<AutoAssignJob office={props.office}
rerender={props.rerender} job={EmployeePositions.Engineer}
office={props.office} desc={
job={EmployeePositions.Operations} "Develops and maintains products and production systems. Increases the quality of everything you produce. Also increases the amount you produce (not as much as Operations, however)"
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."} }
/> />
<AutoAssignJob <AutoAssignJob
rerender={props.rerender} rerender={props.rerender}
office={props.office} office={props.office}
job={EmployeePositions.Engineer} job={EmployeePositions.Business}
desc={ desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."}
"Develops and maintains products and production systems. Increases the quality of everything you produce. Also increases the amount you produce (not as much as Operations, however)" />
}
/>
<AutoAssignJob <AutoAssignJob
rerender={props.rerender} rerender={props.rerender}
office={props.office} office={props.office}
job={EmployeePositions.Business} job={EmployeePositions.Management}
desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."} desc={
/> "Leads and oversees employees and office operations. Improves the effectiveness of Engineer and Operations employees."
}
/>
<AutoAssignJob <AutoAssignJob
rerender={props.rerender} rerender={props.rerender}
office={props.office} office={props.office}
job={EmployeePositions.Management} job={EmployeePositions.RandD}
desc={ desc={"Research new innovative ways to improve the company. Generates Scientific Research."}
"Leads and oversees employees and office operations. Improves the effectiveness of Engineer and Operations employees." />
}
/>
<AutoAssignJob <AutoAssignJob
rerender={props.rerender} rerender={props.rerender}
office={props.office} office={props.office}
job={EmployeePositions.RandD} job={EmployeePositions.Training}
desc={"Research new innovative ways to improve the company. Generates Scientific Research."} desc={
/> "Set employee to training, which will increase some of their stats. Employees in training do not affect any company operations."
}
<AutoAssignJob />
rerender={props.rerender} </TableBody>
office={props.office} </Table>
job={EmployeePositions.Training}
desc={
"Set employee to training, which will increase some of their stats. Employees in training do not affect any company operations."
}
/>
</TableBody>
</Table>
</>
); );
} }
@@ -454,14 +456,40 @@ export function IndustryOffice(props: IProps): React.ReactElement {
onClose={() => setUpgradeOfficeSizeOpen(false)} onClose={() => setUpgradeOfficeSizeOpen(false)}
/> />
{!division.hasResearch("AutoBrew") && (
<>
<Tooltip
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>}
>
<span>
<Button
disabled={corp.funds < props.office.getCoffeeCost() || props.office.coffeeMult > 0}
onClick={() => BuyCoffee(corp, props.office)}
>
{props.office.coffeeMult > 0 ? (
"Buying coffee..."
) : (
<span>
Buy Coffee - <MoneyCost money={props.office.getCoffeeCost()} corp={corp} />
</span>
)}
</Button>
</span>
</Tooltip>
</>
)}
{!division.hasResearch("AutoPartyManager") && ( {!division.hasResearch("AutoPartyManager") && (
<> <>
<Tooltip <Tooltip
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>} title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>}
> >
<span> <span>
<Button disabled={corp.funds < 0} onClick={() => setThrowPartyOpen(true)}> <Button
Throw Party disabled={corp.funds < 0 || props.office.partyMult > 0}
onClick={() => setThrowPartyOpen(true)}
>
{props.office.partyMult > 0 ? "Throwing Party..." : "Throw Party"}
</Button> </Button>
</span> </span>
</Tooltip> </Tooltip>
+31 -74
View File
@@ -2,9 +2,8 @@
// (top-left panel in the Industry UI) // (top-left panel in the Industry UI)
import React, { useState } from "react"; import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { Industries } from "../IndustryData"; import { Industries } from "../IndustryData";
import { IndustryUpgrades } from "../IndustryUpgrades"; import { HireAdVert } from "../Actions";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { createProgressBarText } from "../../utils/helpers/createProgressBarText"; import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
import { MakeProductModal } from "./modals/MakeProductModal"; import { MakeProductModal } from "./modals/MakeProductModal";
@@ -87,7 +86,12 @@ function MakeProductButton(): React.ReactElement {
</> </>
); );
} }
function Text(): React.ReactElement {
interface IProps {
rerender: () => void;
}
export function IndustryOverview(props: IProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); const division = useDivision();
const [helpOpen, setHelpOpen] = useState(false); const [helpOpen, setHelpOpen] = useState(false);
@@ -113,7 +117,7 @@ function Text(): React.ReactElement {
} }
return ( return (
<> <Paper>
<Typography> <Typography>
Industry: {division.type} (Corp Funds: <Money money={corp.funds} />) Industry: {division.type} (Corp Funds: <Money money={corp.funds} />)
</Typography> </Typography>
@@ -191,7 +195,6 @@ function Text(): React.ReactElement {
</Typography> </Typography>
</StaticModal> </StaticModal>
</Box> </Box>
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Tooltip <Tooltip
title={ title={
@@ -207,76 +210,30 @@ function Text(): React.ReactElement {
</Button> </Button>
<ResearchModal open={researchOpen} onClose={() => setResearchOpen(false)} industry={division} /> <ResearchModal open={researchOpen} onClose={() => setResearchOpen(false)} industry={division} />
</Box> </Box>
</>
);
}
function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const upgrades = [];
for (const index of Object.keys(IndustryUpgrades)) {
const upgrade = IndustryUpgrades[index];
// AutoBrew research disables the Coffee upgrade
if (division.hasResearch("AutoBrew") && upgrade[4] === "Coffee") {
continue;
}
const i = upgrade[0];
const baseCost = upgrade[1];
const priceMult = upgrade[2];
let cost = 0;
switch (i) {
case 0: //Coffee, cost is static per employee
cost = props.office.employees.length * baseCost;
break;
default:
cost = baseCost * Math.pow(priceMult, division.upgrades[i]);
break;
}
function onClick(): void {
if (corp.funds < cost) return;
corp.funds = corp.funds - cost;
division.upgrade(upgrade, {
corporation: corp,
office: props.office,
});
props.rerender();
}
upgrades.push(
<Tooltip key={index} title={upgrade[5]}>
<span>
<Button disabled={corp.funds < cost} onClick={onClick}>
{upgrade[4]} -&nbsp;
<MoneyCost money={cost} corp={corp} />
</Button>
</span>
</Tooltip>,
);
}
return <>{upgrades}</>;
}
interface IProps {
currentCity: string;
office: OfficeSpace;
rerender: () => void;
}
export function IndustryOverview(props: IProps): React.ReactElement {
const division = useDivision();
return (
<Paper>
<Text />
<br /> <br />
<Typography>Purchases & Upgrades</Typography> <Box display="flex" alignItems="center">
<Upgrades office={props.office} rerender={props.rerender} /> <br /> <Tooltip
{division.makesProducts && <MakeProductButton />} title={
<Typography>
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.
</Typography>
}
>
<Button
disabled={division.getAdVertCost() > corp.funds}
onClick={function () {
HireAdVert(corp, division);
props.rerender();
}}
>
Hire AdVert -&nbsp; <MoneyCost money={division.getAdVertCost()} corp={corp} />
</Button>
</Tooltip>
{division.makesProducts && <MakeProductButton />}
</Box>
</Paper> </Paper>
); );
} }
@@ -38,11 +38,15 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
dialogBoxCreate("You don't have enough company funds to throw a party!"); dialogBoxCreate("You don't have enough company funds to throw a party!");
} else { } else {
const mult = ThrowParty(corp, props.office, cost); const mult = ThrowParty(corp, props.office, cost);
dialogBoxCreate(
"You threw a party for the office! The morale and happiness " + if (mult > 0) {
"of each employee increased by " + dialogBoxCreate(
numeralWrapper.formatPercentage(mult - 1), "You threw a party for the office! The morale and happiness " +
); "of each employee increased by " +
numeralWrapper.formatPercentage(mult - 1),
);
}
props.rerender(); props.rerender();
props.onClose(); props.onClose();
} }
+1 -1
View File
@@ -531,7 +531,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
bladeburner: NetscriptBladeburner(Player, workerScript), bladeburner: NetscriptBladeburner(Player, workerScript),
codingcontract: NetscriptCodingContract(Player, workerScript), codingcontract: NetscriptCodingContract(Player, workerScript),
sleeve: NetscriptSleeve(Player), sleeve: NetscriptSleeve(Player),
corporation: NetscriptCorporation(Player, workerScript), corporation: NetscriptCorporation(Player),
stanek: NetscriptStanek(Player, workerScript, helper), stanek: NetscriptStanek(Player, workerScript, helper),
infiltration: NetscriptInfiltration(Player), infiltration: NetscriptInfiltration(Player),
ui: NetscriptUserInterface(), ui: NetscriptUserInterface(),
+41 -48
View File
@@ -1,6 +1,4 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { netscriptDelay } from "../NetscriptEvaluator";
import { OfficeSpace } from "../Corporation/OfficeSpace"; import { OfficeSpace } from "../Corporation/OfficeSpace";
import { Employee } from "../Corporation/Employee"; import { Employee } from "../Corporation/Employee";
@@ -34,11 +32,12 @@ import {
SetSmartSupply, SetSmartSupply,
BuyMaterial, BuyMaterial,
AssignJob, AssignJob,
AutoAssignJob,
UpgradeOfficeSize, UpgradeOfficeSize,
ThrowParty,
PurchaseWarehouse, PurchaseWarehouse,
UpgradeWarehouse, UpgradeWarehouse,
BuyCoffee, BuyCoffee,
ThrowParty,
HireAdVert, HireAdVert,
MakeProduct, MakeProduct,
Research, Research,
@@ -59,17 +58,15 @@ import {
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades"; import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
import { CorporationUpgrades } from "../Corporation/data/CorporationUpgrades"; import { CorporationUpgrades } from "../Corporation/data/CorporationUpgrades";
import { EmployeePositions } from "../Corporation/EmployeePositions"; import { EmployeePositions } from "../Corporation/EmployeePositions";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
import { Industry } from "../Corporation/Industry"; import { Industry } from "../Corporation/Industry";
import { IndustryResearchTrees, IndustryStartingCosts } from "../Corporation/IndustryData"; import { IndustryResearchTrees, IndustryStartingCosts } from "../Corporation/IndustryData";
import { CorporationConstants } from "../Corporation/data/Constants"; import { CorporationConstants } from "../Corporation/data/Constants";
import { IndustryUpgrades } from "../Corporation/IndustryUpgrades";
import { ResearchMap } from "../Corporation/ResearchMap"; import { ResearchMap } from "../Corporation/ResearchMap";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript): InternalAPI<NSCorporation> { export function NetscriptCorporation(player: IPlayer): InternalAPI<NSCorporation> {
function createCorporation(corporationName: string, selfFund = true): boolean { function createCorporation(corporationName: string, selfFund = true): boolean {
if (!player.canAccessCorporation() || player.hasCorporation()) return false; if (!player.canAccessCorporation() || player.hasCorporation()) return false;
if (!corporationName) return false; if (!corporationName) return false;
@@ -302,7 +299,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
lastCycleExpenses: division.lastCycleExpenses, lastCycleExpenses: division.lastCycleExpenses,
thisCycleRevenue: division.thisCycleRevenue, thisCycleRevenue: division.thisCycleRevenue,
thisCycleExpenses: division.thisCycleExpenses, thisCycleExpenses: division.thisCycleExpenses,
upgrades: division.upgrades.slice(), upgrades: [0, division.numAdVerts],
cities: cities, cities: cities,
products: division.products === undefined ? [] : Object.keys(division.products), products: division.products === undefined ? [] : Object.keys(division.products),
makesProducts: division.makesProducts, makesProducts: division.makesProducts,
@@ -658,8 +655,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
const upgrade = IndustryUpgrades[1]; return division.getAdVertCost();
return upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]);
}, },
getHireAdVertCount: getHireAdVertCount:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
@@ -667,7 +663,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const division = getDivision(divisionName); const division = getDivision(divisionName);
return division.upgrades[1]; return division.numAdVerts;
}, },
getResearchCost: getResearchCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
@@ -685,20 +681,6 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
const researchName = ctx.helper.string("researchName", _researchName); const researchName = ctx.helper.string("researchName", _researchName);
return hasResearched(getDivision(divisionName), researchName); return hasResearched(getDivision(divisionName), researchName);
}, },
setAutoJobAssignment:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): Promise<boolean> => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amount = ctx.helper.number("amount", _amount);
const job = ctx.helper.string("job", _job);
const office = getOffice(divisionName, cityName);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
return netscriptDelay(1000, workerScript).then(function () {
return Promise.resolve(office.setEmployeeToJob(job, amount));
});
},
getOfficeSizeUpgradeCost: getOfficeSizeUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): number => { (_divisionName: unknown, _cityName: unknown, _size: unknown): number => {
@@ -718,18 +700,31 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
}, },
assignJob: assignJob:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): Promise<void> => { (_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): void => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = ctx.helper.city("cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName); const employeeName = ctx.helper.string("employeeName", _employeeName);
const job = ctx.helper.string("job", _job); const job = ctx.helper.string("job", _job);
const employee = getEmployee(divisionName, cityName, employeeName);
return netscriptDelay(["Training", "Unassigned"].includes(employee.pos) ? 0 : 1000, workerScript).then( if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
function () { const office = getOffice(divisionName, cityName);
return Promise.resolve(AssignJob(employee, job));
}, AssignJob(office, employeeName, job);
); },
setAutoJobAssignment:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): boolean => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amount = ctx.helper.number("amount", _amount);
const job = ctx.helper.string("job", _job);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName);
return AutoAssignJob(office, job, amount);
}, },
hireEmployee: hireEmployee:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
@@ -769,35 +764,32 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
}, },
throwParty: throwParty:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
async (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): Promise<number> => { (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = ctx.helper.city("cityName", _cityName);
const costPerEmployee = ctx.helper.number("costPerEmployee", _costPerEmployee); const costPerEmployee = ctx.helper.number("costPerEmployee", _costPerEmployee);
if (costPerEmployee < 0)
if (costPerEmployee < 0) {
throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0"); throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName); }
const corporation = getCorporation(); const corporation = getCorporation();
return netscriptDelay( const office = getOffice(divisionName, cityName);
(60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)),
workerScript, return ThrowParty(corporation, office, costPerEmployee);
).then(function () {
return Promise.resolve(ThrowParty(corporation, office, costPerEmployee));
});
}, },
buyCoffee: buyCoffee:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
async (_divisionName: unknown, _cityName: unknown): Promise<void> => { (_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName); const cityName = ctx.helper.city("cityName", _cityName);
const corporation = getCorporation(); const corporation = getCorporation();
return netscriptDelay( const office = getOffice(divisionName, cityName);
(60 * 1000) / (player.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)),
workerScript, return BuyCoffee(corporation, office);
).then(function () {
return Promise.resolve(BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName)));
});
}, },
hireAdVert: hireAdVert:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
@@ -805,7 +797,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8); checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName); const divisionName = ctx.helper.string("divisionName", _divisionName);
const corporation = getCorporation(); const corporation = getCorporation();
HireAdVert(corporation, getDivision(divisionName), getOffice(divisionName, "Sector-12")); HireAdVert(corporation, getDivision(divisionName));
}, },
research: research:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
@@ -829,6 +821,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
maxEne: office.maxEne, maxEne: office.maxEne,
minHap: office.minHap, minHap: office.minHap,
maxHap: office.maxHap, maxHap: office.maxHap,
minMor: office.minMor,
maxMor: office.maxMor, maxMor: office.maxMor,
employees: office.employees.map((e) => e.name), employees: office.employees.map((e) => e.name),
employeeProd: { employeeProd: {
+9 -8
View File
@@ -6623,9 +6623,8 @@ export interface OfficeAPI {
* @param cityName - Name of the city * @param cityName - Name of the city
* @param employeeName - name of the employee * @param employeeName - name of the employee
* @param job - Name of the job. * @param job - Name of the job.
* @returns A promise that is fulfilled when the assignment is complete.
*/ */
assignJob(divisionName: string, cityName: string, employeeName: string, job: string): Promise<void>; assignJob(divisionName: string, cityName: string, employeeName: string, job: string): void;
/** /**
* Hire an employee. * Hire an employee.
* @param divisionName - Name of the division * @param divisionName - Name of the division
@@ -6645,16 +6644,16 @@ export interface OfficeAPI {
* @param divisionName - Name of the division * @param divisionName - Name of the division
* @param cityName - Name of the city * @param cityName - Name of the city
* @param costPerEmployee - Amount to spend per employee. * @param costPerEmployee - Amount to spend per employee.
* @returns Amount of happiness increased. * @returns Multiplier for happiness and morale, or zero on failure
*/ */
throwParty(divisionName: string, cityName: string, costPerEmployee: number): Promise<number>; throwParty(divisionName: string, cityName: string, costPerEmployee: number): number;
/** /**
* Buy coffee for your employees * Buy coffee for your employees
* @param divisionName - Name of the division * @param divisionName - Name of the division
* @param cityName - Name of the city * @param cityName - Name of the city
* @returns A promise that is fulfilled when the coffee is served. * @returns true if buying coffee was successful, false otherwise
*/ */
buyCoffee(divisionName: string, cityName: string): Promise<void>; buyCoffee(divisionName: string, cityName: string): boolean;
/** /**
* Hire AdVert. * Hire AdVert.
* @param divisionName - Name of the division * @param divisionName - Name of the division
@@ -6713,9 +6712,9 @@ export interface OfficeAPI {
* @param cityName - Name of the city * @param cityName - Name of the city
* @param job - Name of the job * @param job - Name of the job
* @param amount - Number of employees to assign to that job * @param amount - Number of employees to assign to that job
* @returns A promise that is fulfilled when the assignment is complete. * @returns true if the employee count reached the target amount, false if not
*/ */
setAutoJobAssignment(divisionName: string, cityName: string, job: string, amount: number): Promise<boolean>; setAutoJobAssignment(divisionName: string, cityName: string, job: string, amount: number): boolean;
/** /**
* Cost to Upgrade office size. * Cost to Upgrade office size.
* @param divisionName - Name of the division * @param divisionName - Name of the division
@@ -7234,6 +7233,8 @@ interface Office {
minHap: number; minHap: number;
/** Maximum happiness of the employees */ /** Maximum happiness of the employees */
maxHap: number; maxHap: number;
/** Minimum morale of the employees */
minMor: number;
/** Maximum morale of the employees */ /** Maximum morale of the employees */
maxMor: number; maxMor: number;
/** Name of all the employees */ /** Name of all the employees */