merge corp not async

This commit is contained in:
Olivier Gagnon 2022-07-20 17:27:11 -04:00
commit ec17cfdaf3
18 changed files with 581 additions and 565 deletions

4
dist/main.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

42
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -13,8 +13,6 @@ import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade } from "./data/CorporationUpgrades";
import { Cities } from "../Locations/Cities";
import { EmployeePositions } from "./EmployeePositions";
import { Employee } from "./Employee";
import { IndustryUpgrades } from "./IndustryUpgrades";
import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers";
@ -304,9 +302,19 @@ export function BuyBackShares(corporation: ICorporation, player: IPlayer, numSha
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.`);
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 {
@ -323,15 +331,32 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size:
corp.funds = corp.funds - cost;
}
export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number {
const totalCost = costPerEmployee * office.employees.length;
if (corp.funds < totalCost) return 0;
corp.funds = corp.funds - totalCost;
let mult = 0;
for (let i = 0; i < office.employees.length; ++i) {
mult = office.employees[i].throwParty(costPerEmployee);
export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean {
const cost = office.getCoffeeCost();
if (corp.funds < cost) {
return false;
}
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;
}
@ -362,26 +387,11 @@ export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, wareho
corp.funds = corp.funds - sizeUpgradeCost;
}
export function BuyCoffee(corp: ICorporation, division: IIndustry, office: OfficeSpace): void {
const upgrade = IndustryUpgrades[0];
const cost = office.employees.length * upgrade[1];
export function HireAdVert(corp: ICorporation, division: IIndustry): void {
const cost = division.getAdVertCost();
if (corp.funds < cost) return;
corp.funds = corp.funds - cost;
division.upgrade(upgrade, {
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,
});
division.applyAdVert(corp);
}
export function MakeProduct(

@ -3,7 +3,6 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { EmployeePositions } from "./EmployeePositions";
import { ICorporation } from "./ICorporation";
import { OfficeSpace } from "./OfficeSpace";
import { IIndustry } from "./IIndustry";
interface IParams {
@ -34,6 +33,7 @@ export class Employee {
cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise;
loc: string;
pos: string;
nextPos: string;
constructor(params: IParams = {}) {
this.name = params.name ? params.name : "Bobby";
@ -52,12 +52,13 @@ export class Employee {
this.loc = params.loc ? params.loc : "";
this.pos = EmployeePositions.Unassigned;
this.nextPos = this.pos;
}
//Returns the amount the employee needs to be paid
process(marketCycles = 1, office: OfficeSpace): number {
const gain = 0.003 * marketCycles,
det = gain * Math.random();
process(marketCycles = 1): number {
const gain = 0.003 * marketCycles;
const det = gain * Math.random();
this.exp += gain;
//Training
@ -72,12 +73,6 @@ export class Employee {
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;
}
@ -118,16 +113,6 @@ export class Employee {
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(): IReviverValue {
return Generic_toJSON("Employee", this);
}

@ -3,7 +3,6 @@ import { Warehouse } from "./Warehouse";
import { ICorporation } from "./ICorporation";
import { OfficeSpace } from "./OfficeSpace";
import { Product } from "./Product";
import { IndustryUpgrade } from "./IndustryUpgrades";
import { IReviverValue } from "../utils/JSONReviver";
export interface IIndustry {
@ -37,12 +36,11 @@ export interface IIndustry {
thisCycleRevenue: number;
thisCycleExpenses: number;
upgrades: number[];
state: string;
newInd: boolean;
warehouses: { [key: string]: Warehouse | 0 };
offices: { [key: string]: OfficeSpace | 0 };
numAdVerts: number;
init(): void;
getProductDescriptionText(): string;
@ -57,7 +55,8 @@ export interface IIndustry {
processProducts(marketCycles: number, corporation: ICorporation): [number, number];
processProduct(marketCycles: number, product: Product, corporation: ICorporation): number;
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;
getBusinessFactor(office: OfficeSpace): number;
getAdvertisingFactors(): [number, number, number, number];

@ -14,7 +14,6 @@ import { MaterialSizes } from "./MaterialSizes";
import { Warehouse } from "./Warehouse";
import { ICorporation } from "./ICorporation";
import { IIndustry } from "./IIndustry";
import { IndustryUpgrade, IndustryUpgrades } from "./IndustryUpgrades";
interface IParams {
name?: string;
@ -59,9 +58,6 @@ export class Industry implements IIndustry {
thisCycleRevenue: number;
thisCycleExpenses: number;
//Upgrades
upgrades: number[] = Array(Object.keys(IndustryUpgrades).length).fill(0);
state = "START";
newInd = true;
@ -81,6 +77,8 @@ export class Industry implements IIndustry {
[CityName.Volhaven]: 0,
};
numAdVerts = 0;
constructor(params: IParams = {}) {
this.name = params.name ? params.name : "";
this.type = params.type ? params.type : Industries.Agriculture;
@ -1004,23 +1002,9 @@ export class Industry implements IIndustry {
const office = this.offices[city];
if (office === 0) continue;
// Designing/Creating a Product is based mostly off Engineers
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);
prod.createProduct(marketCycles, office.employeeProd);
if (prod.prog >= 100) {
prod.finishProduct(office.employeeProd, this);
prod.finishProduct(this);
}
break;
}
@ -1262,38 +1246,19 @@ export class Industry implements IIndustry {
}
}
upgrade(upgrade: IndustryUpgrade, refs: { corporation: ICorporation; office: OfficeSpace }): void {
const corporation = refs.corporation;
const office = refs.office;
const upgN = upgrade[0];
while (this.upgrades.length <= upgN) {
this.upgrades.push(0);
}
++this.upgrades[upgN];
getAdVertCost(): number {
return 1e9 * Math.pow(1.06, this.numAdVerts);
}
switch (upgN) {
case 0: {
//Coffee, 5% energy per employee
for (let i = 0; i < office.employees.length; ++i) {
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);
applyAdVert(corporation: ICorporation): void {
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);
this.popularity = Math.min(popularity, Number.MAX_VALUE);
break;
}
default: {
console.error(`Un-implemented function index: ${upgN}`);
break;
}
}
const popularity = (this.popularity + 1 * advMult) * ((1 + getRandomInt(1, 3) / 100) * advMult);
this.popularity = Math.min(popularity, Number.MAX_VALUE);
++this.numAdVerts;
}
// Returns how much of a material can be produced based of office productivity (employee stats)

@ -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.",
],
};

@ -15,11 +15,22 @@ interface IParams {
export class OfficeSpace {
loc: string;
size: number;
minEne = 0;
maxEne = 100;
minHap = 0;
minMor = 0;
maxEne = 100;
maxHap = 100;
maxMor = 100;
autoCoffee = false;
autoParty = false;
coffeeMult = 0;
partyMult = 0;
coffeeEmployees = 0;
partyEmployees = 0;
employees: Employee[] = [];
employeeProd: { [key: string]: number } = {
[EmployeePositions.Operations]: 0,
@ -37,7 +48,15 @@ export class OfficeSpace {
[EmployeePositions.RandD]: 0,
[EmployeePositions.Training]: 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 = {}) {
@ -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.calculateNextEmployees();
// Process Office properties
this.maxEne = 100;
this.maxHap = 100;
this.maxMor = 100;
if (industry.hasResearch("Go-Juice")) {
this.maxEne += 10;
}
@ -73,6 +98,12 @@ export class OfficeSpace {
if (industry.hasResearch("Sti.mu")) {
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
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);
}
const hasAutobrew = industry.hasResearch("AutoBrew");
const hasAutoparty = industry.hasResearch("AutoPartyManager");
let totalSalary = 0;
for (const employee of this.employees) {
const salary = employee.process(marketCycles);
totalSalary += salary;
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;
if (this.autoCoffee) {
employee.ene = this.maxEne;
} else if (this.coffeeMult > 1) {
const mult = 1 + ((this.coffeeMult - 1) * this.employees.length) / this.coffeeEmployees;
employee.ene *= mult;
} else {
emp.mor *= perfMult;
emp.hap *= perfMult;
emp.mor = Math.min(emp.mor, this.maxMor);
emp.hap = Math.min(emp.hap, this.maxHap);
employee.ene *= perfMult;
}
if (hasAutobrew) {
emp.ene = this.maxEne;
if (this.autoParty) {
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 {
emp.ene *= perfMult;
emp.ene = Math.min(emp.ene, this.maxEne);
employee.mor *= perfMult;
employee.hap *= perfMult;
}
const salary = emp.process(marketCycles, this);
salaryPaid += salary;
employee.ene = Math.max(Math.min(employee.ene, this.maxEne), this.minEne);
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);
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 {
@ -123,7 +175,6 @@ export class OfficeSpace {
const employee = this.employees[i];
this.employeeJobs[employee.pos]++;
}
this.employeeJobs.total = this.employees.length;
}
calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void {
@ -173,45 +224,57 @@ export class OfficeSpace {
emp.name = name;
this.employees.push(emp);
this.calculateTotalEmployees();
this.calculateNextEmployees();
return emp;
}
//Finds the first unassigned employee and assigns its to the specified job
assignEmployeeToJob(job: string): 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;
assignSingleJob(employee: Employee, job: string): void {
employee.nextPos = job;
this.calculateNextEmployees();
}
//Finds the first employee with the given job and unassigns it
unassignEmployeeFromJob(job: string): 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;
}
setEmployeeToJob(job: string, amount: number): boolean {
let jobCount = this.employees.reduce((acc, employee) => (employee.pos === job ? acc + 1 : acc), 0);
autoAssignJob(job: string, target: number): boolean {
let count = this.employeeNextJobs[job];
for (const employee of this.employees) {
if (jobCount == amount) return true;
if (employee.pos === EmployeePositions.Unassigned && jobCount <= amount) {
employee.pos = job;
jobCount++;
} else if (employee.pos === job && jobCount >= amount) {
employee.pos = EmployeePositions.Unassigned;
jobCount--;
if (count === target) {
break;
} else if (employee.nextPos === EmployeePositions.Unassigned && count <= target) {
employee.nextPos = job;
count++;
} else if (employee.nextPos === job && count >= target) {
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(): IReviverValue {

@ -55,6 +55,16 @@ export class Product {
designCost = 0; // How much money was invested into designing 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'
// This is based on the stats/properties below. The weighting of the
// stats/properties below differs between different industries
@ -117,25 +127,48 @@ export class Product {
this.reqMats = params.req ? params.req : {};
}
// empWorkMult is a multiplier that increases progress rate based on
// productivity of employees
createProduct(marketCycles = 1, empWorkMult = 1): void {
// Make progress on this product based on current employee productivity
createProduct(marketCycles: number, employeeProd: typeof this["creationProd"]): void {
if (this.fin) {
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
finishProduct(employeeProd: { [key: string]: number }, industry: IIndustry): void {
finishProduct(industry: IIndustry): void {
this.fin = true;
//Calculate properties
const engrRatio = employeeProd[EmployeePositions.Engineer] / employeeProd["total"];
const mgmtRatio = employeeProd[EmployeePositions.Management] / employeeProd["total"];
const rndRatio = employeeProd[EmployeePositions.RandD] / employeeProd["total"];
const opsRatio = employeeProd[EmployeePositions.Operations] / employeeProd["total"];
const busRatio = employeeProd[EmployeePositions.Business] / employeeProd["total"];
// Calculate properties
const totalProd = this.creationProd.total;
const engrRatio = this.creationProd[EmployeePositions.Engineer] / totalProd;
const mgmtRatio = this.creationProd[EmployeePositions.Management] / totalProd;
const rndRatio = this.creationProd[EmployeePositions.RandD] / totalProd;
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 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;
@ -143,49 +176,49 @@ export class Product {
this.qlt =
totalMult *
(0.1 * employeeProd[EmployeePositions.Engineer] +
0.05 * employeeProd[EmployeePositions.Management] +
0.05 * employeeProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] +
0.02 * employeeProd[EmployeePositions.Business]);
(0.1 * this.creationProd[EmployeePositions.Engineer] +
0.05 * this.creationProd[EmployeePositions.Management] +
0.05 * this.creationProd[EmployeePositions.RandD] +
0.02 * this.creationProd[EmployeePositions.Operations] +
0.02 * this.creationProd[EmployeePositions.Business]);
this.per =
totalMult *
(0.15 * employeeProd[EmployeePositions.Engineer] +
0.02 * employeeProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] +
0.02 * employeeProd[EmployeePositions.Business]);
(0.15 * this.creationProd[EmployeePositions.Engineer] +
0.02 * this.creationProd[EmployeePositions.Management] +
0.02 * this.creationProd[EmployeePositions.RandD] +
0.02 * this.creationProd[EmployeePositions.Operations] +
0.02 * this.creationProd[EmployeePositions.Business]);
this.dur =
totalMult *
(0.05 * employeeProd[EmployeePositions.Engineer] +
0.02 * employeeProd[EmployeePositions.Management] +
0.08 * employeeProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] +
0.05 * employeeProd[EmployeePositions.Business]);
(0.05 * this.creationProd[EmployeePositions.Engineer] +
0.02 * this.creationProd[EmployeePositions.Management] +
0.08 * this.creationProd[EmployeePositions.RandD] +
0.05 * this.creationProd[EmployeePositions.Operations] +
0.05 * this.creationProd[EmployeePositions.Business]);
this.rel =
totalMult *
(0.02 * employeeProd[EmployeePositions.Engineer] +
0.08 * employeeProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] +
0.08 * employeeProd[EmployeePositions.Business]);
(0.02 * this.creationProd[EmployeePositions.Engineer] +
0.08 * this.creationProd[EmployeePositions.Management] +
0.02 * this.creationProd[EmployeePositions.RandD] +
0.05 * this.creationProd[EmployeePositions.Operations] +
0.08 * this.creationProd[EmployeePositions.Business]);
this.aes =
totalMult *
(0.0 * employeeProd[EmployeePositions.Engineer] +
0.08 * employeeProd[EmployeePositions.Management] +
0.05 * employeeProd[EmployeePositions.RandD] +
0.02 * employeeProd[EmployeePositions.Operations] +
0.1 * employeeProd[EmployeePositions.Business]);
(0.0 * this.creationProd[EmployeePositions.Engineer] +
0.08 * this.creationProd[EmployeePositions.Management] +
0.05 * this.creationProd[EmployeePositions.RandD] +
0.02 * this.creationProd[EmployeePositions.Operations] +
0.1 * this.creationProd[EmployeePositions.Business]);
this.fea =
totalMult *
(0.08 * employeeProd[EmployeePositions.Engineer] +
0.05 * employeeProd[EmployeePositions.Management] +
0.02 * employeeProd[EmployeePositions.RandD] +
0.05 * employeeProd[EmployeePositions.Operations] +
0.05 * employeeProd[EmployeePositions.Business]);
(0.08 * this.creationProd[EmployeePositions.Engineer] +
0.05 * this.creationProd[EmployeePositions.Management] +
0.02 * this.creationProd[EmployeePositions.RandD] +
0.05 * this.creationProd[EmployeePositions.Operations] +
0.05 * this.creationProd[EmployeePositions.Business]);
this.calculateRating(industry);
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);
// I actually don't understand well enough to know if this is right.

@ -25,7 +25,7 @@ export function Industry(props: IProps): React.ReactElement {
return (
<Box display="flex">
<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} />
</Box>
<Box sx={{ width: "50%" }}>

@ -5,7 +5,9 @@ import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { Employee } from "../Employee";
import { EmployeePositions } from "../EmployeePositions";
import { BuyCoffee } from "../Actions";
import { MoneyCost } from "./MoneyCost";
import { numeralWrapper } from "../../ui/numeralFormat";
import { UpgradeOfficeSizeModal } from "./modals/UpgradeOfficeSizeModal";
@ -17,6 +19,7 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import Tooltip from "@mui/material/Tooltip";
@ -33,14 +36,6 @@ interface IProps {
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 {
manualMode: boolean;
switchMode: (f: (b: boolean) => boolean) => void;
@ -115,14 +110,14 @@ function ManualManagement(props: IProps): React.ReactElement {
{positionNames[i]}
</MenuItem>,
);
if (emp != null && emp.pos === positionNames[i]) {
employeePositionSelectorInitialValue = positionNames[i];
if (emp != null && emp.nextPos === positionNames[i]) {
employeePositionSelectorInitialValue = emp.nextPos;
}
}
function employeePositionSelectorOnChange(e: SelectChangeEvent<string>): void {
if (employee === null) return;
employee.pos = e.target.value;
props.office.assignSingleJob(employee, e.target.value);
props.rerender();
}
@ -178,41 +173,53 @@ interface IAutoAssignProps {
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 {
const corp = useCorporation();
const division = useDivision();
const numJob = countEmployee(props.office.employees, props.job);
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
const currJob = props.office.employeeJobs[props.job];
const nextJob = props.office.employeeNextJobs[props.job];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
function assignEmployee(): void {
if (numUnassigned <= 0) {
if (nextUna <= 0) {
console.warn("Cannot assign employee. No unassigned employees available");
return;
}
props.office.assignEmployeeToJob(props.job);
props.office.calculateEmployeeProductivity(corp, division);
props.office.autoAssignJob(props.job, nextJob + 1);
props.rerender();
}
function unassignEmployee(): void {
props.office.unassignEmployeeFromJob(props.job);
props.office.calculateEmployeeProductivity(corp, division);
props.office.autoAssignJob(props.job, nextJob - 1);
props.rerender();
}
return (
<TableRow>
<TableCell>
<Tooltip title={props.desc}>
<Typography>
{props.job} ({numJob})
</Typography>
<Typography>{props.job}</Typography>
</Tooltip>
</TableCell>
<TableCell>
<IconButton disabled={numUnassigned === 0} onClick={assignEmployee}>
<EmployeeCount num={currJob} next={nextJob} />
</TableCell>
<TableCell width="1px">
<IconButton disabled={nextUna === 0} onClick={assignEmployee}>
<ArrowDropUpIcon />
</IconButton>
<IconButton disabled={numJob === 0} onClick={unassignEmployee}>
</TableCell>
<TableCell width="1px">
<IconButton disabled={nextJob === 0} onClick={unassignEmployee}>
<ArrowDropDownIcon />
</IconButton>
</TableCell>
@ -223,7 +230,6 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
function AutoManagement(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade
// Calculate average morale, happiness, energy, and salary.
@ -247,168 +253,164 @@ function AutoManagement(props: IProps): React.ReactElement {
avgEnergy = totalEnergy / props.office.employees.length;
}
const currUna = props.office.employeeJobs[EmployeePositions.Unassigned];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
return (
<>
<Table padding="none">
<TableBody>
<TableRow>
<TableCell>
<Typography>Unassigned Employees:</Typography>
</TableCell>
<TableCell>
<Typography>{numUnassigned}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Morale:</Typography>
</TableCell>
<TableCell>
<Typography>{numeralWrapper.format(avgMorale, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Happiness:</Typography>
</TableCell>
<TableCell>
<Typography>{numeralWrapper.format(avgHappiness, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Energy:</Typography>
</TableCell>
<TableCell>
<Typography>{numeralWrapper.format(avgEnergy, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Total Employee Salary:</Typography>
</TableCell>
<TableCell>
<Typography>
<Money money={totalSalary} />
</Typography>
</TableCell>
</TableRow>
{vechain && (
<>
<TableRow>
<TableCell>
<Tooltip
title={
<Typography>
The base amount of material this office can produce. Does not include production multipliers
from upgrades and materials. This value is based off the productivity of your Operations,
Engineering, and Management employees
</Typography>
}
>
<Typography>Material Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography>
{numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")}
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Tooltip
title={
<Typography>
The base amount of any given Product this office can produce. Does not include production
multipliers from upgrades and materials. This value is based off the productivity of your
Operations, Engineering, and Management employees
</Typography>
}
>
<Typography>Product Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography>
{numeralWrapper.format(
division.getOfficeProductivity(props.office, {
forProduct: true,
}),
"0.000",
)}
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Tooltip
title={<Typography>The effect this office's 'Business' employees has on boosting sales</Typography>}
>
<Typography> Business Multiplier:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography>x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")}</Typography>
</TableCell>
</TableRow>
</>
)}
</TableBody>
</Table>
<Table padding="none">
<TableBody>
<TableRow>
<TableCell>
<Typography>Unassigned Employees:</Typography>
</TableCell>
<TableCell>
<EmployeeCount num={currUna} next={nextUna} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Morale:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{numeralWrapper.format(avgMorale, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Happiness:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{numeralWrapper.format(avgHappiness, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Avg Employee Energy:</Typography>
</TableCell>
<TableCell align="right">
<Typography>{numeralWrapper.format(avgEnergy, "0.000")}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography>Total Employee Salary:</Typography>
</TableCell>
<TableCell>
<Typography align="right">
<Money money={totalSalary} />
</Typography>
</TableCell>
</TableRow>
{vechain && (
<>
<TableRow>
<TableCell>
<Tooltip
title={
<Typography>
The base amount of material this office can produce. Does not include production multipliers from
upgrades and materials. This value is based off the productivity of your Operations, Engineering,
and Management employees
</Typography>
}
>
<Typography>Material Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography align="right">
{numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")}
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Tooltip
title={
<Typography>
The base amount of any given Product this office can produce. Does not include production
multipliers from upgrades and materials. This value is based off the productivity of your
Operations, Engineering, and Management employees
</Typography>
}
>
<Typography>Product Production:</Typography>
</Tooltip>
</TableCell>
<TableCell>
<Typography align="right">
{numeralWrapper.format(
division.getOfficeProductivity(props.office, {
forProduct: true,
}),
"0.000",
)}
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Tooltip
title={<Typography>The effect this office's 'Business' employees has on boosting sales</Typography>}
>
<Typography> Business Multiplier:</Typography>
</Tooltip>
</TableCell>
<TableCell align="right">
<Typography>x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")}</Typography>
</TableCell>
</TableRow>
</>
)}
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Operations}
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."}
/>
<Table padding="none">
<TableBody>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Operations}
desc={"Manages supply chain operations. Improves the amount of Materials and Products you produce."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Engineer}
desc={
"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
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Engineer}
desc={
"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
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Business}
desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Business}
desc={"Handles sales and finances. Improves the amount of Materials and Products you can sell."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Management}
desc={
"Leads and oversees employees and office operations. Improves the effectiveness of Engineer and Operations employees."
}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.Management}
desc={
"Leads and oversees employees and office operations. Improves the effectiveness of Engineer and Operations employees."
}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.RandD}
desc={"Research new innovative ways to improve the company. Generates Scientific Research."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
job={EmployeePositions.RandD}
desc={"Research new innovative ways to improve the company. Generates Scientific Research."}
/>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
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>
</>
<AutoAssignJob
rerender={props.rerender}
office={props.office}
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)}
/>
{!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") && (
<>
<Tooltip
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>}
>
<span>
<Button disabled={corp.funds < 0} onClick={() => setThrowPartyOpen(true)}>
Throw Party
<Button
disabled={corp.funds < 0 || props.office.partyMult > 0}
onClick={() => setThrowPartyOpen(true)}
>
{props.office.partyMult > 0 ? "Throwing Party..." : "Throw Party"}
</Button>
</span>
</Tooltip>

@ -2,9 +2,8 @@
// (top-left panel in the Industry UI)
import React, { useState } from "react";
import { OfficeSpace } from "../OfficeSpace";
import { Industries } from "../IndustryData";
import { IndustryUpgrades } from "../IndustryUpgrades";
import { HireAdVert } from "../Actions";
import { numeralWrapper } from "../../ui/numeralFormat";
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
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 division = useDivision();
const [helpOpen, setHelpOpen] = useState(false);
@ -113,7 +117,7 @@ function Text(): React.ReactElement {
}
return (
<>
<Paper>
<Typography>
Industry: {division.type} (Corp Funds: <Money money={corp.funds} />)
</Typography>
@ -191,7 +195,6 @@ function Text(): React.ReactElement {
</Typography>
</StaticModal>
</Box>
<Box display="flex" alignItems="center">
<Tooltip
title={
@ -207,76 +210,30 @@ function Text(): React.ReactElement {
</Button>
<ResearchModal open={researchOpen} onClose={() => setResearchOpen(false)} industry={division} />
</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 />
<Typography>Purchases & Upgrades</Typography>
<Upgrades office={props.office} rerender={props.rerender} /> <br />
{division.makesProducts && <MakeProductButton />}
<Box display="flex" alignItems="center">
<Tooltip
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>
);
}

@ -38,11 +38,15 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
dialogBoxCreate("You don't have enough company funds to throw a party!");
} else {
const mult = ThrowParty(corp, props.office, cost);
dialogBoxCreate(
"You threw a party for the office! The morale and happiness " +
"of each employee increased by " +
numeralWrapper.formatPercentage(mult - 1),
);
if (mult > 0) {
dialogBoxCreate(
"You threw a party for the office! The morale and happiness " +
"of each employee increased by " +
numeralWrapper.formatPercentage(mult - 1),
);
}
props.rerender();
props.onClose();
}

@ -649,7 +649,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
bladeburner: NetscriptBladeburner(Player, workerScript),
codingcontract: NetscriptCodingContract(Player, workerScript),
sleeve: NetscriptSleeve(Player),
corporation: NetscriptCorporation(Player, workerScript),
corporation: NetscriptCorporation(Player),
stanek: NetscriptStanek(Player, workerScript, helper),
infiltration: NetscriptInfiltration(Player),
ui: NetscriptUserInterface(),

@ -1,6 +1,4 @@
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer";
import { netscriptDelay } from "../NetscriptEvaluator";
import { OfficeSpace } from "../Corporation/OfficeSpace";
import { Employee } from "../Corporation/Employee";
@ -35,11 +33,12 @@ import {
SetSmartSupply,
BuyMaterial,
AssignJob,
AutoAssignJob,
UpgradeOfficeSize,
ThrowParty,
PurchaseWarehouse,
UpgradeWarehouse,
BuyCoffee,
ThrowParty,
HireAdVert,
MakeProduct,
Research,
@ -60,17 +59,15 @@ import {
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
import { CorporationUpgrades } from "../Corporation/data/CorporationUpgrades";
import { EmployeePositions } from "../Corporation/EmployeePositions";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
import { Industry } from "../Corporation/Industry";
import { IndustryResearchTrees, IndustryStartingCosts } from "../Corporation/IndustryData";
import { CorporationConstants } from "../Corporation/data/Constants";
import { IndustryUpgrades } from "../Corporation/IndustryUpgrades";
import { ResearchMap } from "../Corporation/ResearchMap";
import { Factions } from "../Faction/Factions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
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 {
if (!player.canAccessCorporation() || player.hasCorporation()) return false;
if (!corporationName) return false;
@ -303,7 +300,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
lastCycleExpenses: division.lastCycleExpenses,
thisCycleRevenue: division.thisCycleRevenue,
thisCycleExpenses: division.thisCycleExpenses,
upgrades: division.upgrades.slice(),
upgrades: [0, division.numAdVerts],
cities: cities,
products: division.products === undefined ? [] : Object.keys(division.products),
makesProducts: division.makesProducts,
@ -659,8 +656,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const division = getDivision(divisionName);
const upgrade = IndustryUpgrades[1];
return upgrade[1] * Math.pow(upgrade[2], division.upgrades[1]);
return division.getAdVertCost();
},
getHireAdVertCount:
(ctx: NetscriptContext) =>
@ -668,7 +664,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const division = getDivision(divisionName);
return division.upgrades[1];
return division.numAdVerts;
},
getResearchCost:
(ctx: NetscriptContext) =>
@ -686,20 +682,6 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
const researchName = ctx.helper.string("researchName", _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:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): number => {
@ -719,18 +701,31 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
},
assignJob:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): Promise<void> => {
(_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): void => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName);
const job = ctx.helper.string("job", _job);
const employee = getEmployee(divisionName, cityName, employeeName);
return netscriptDelay(["Training", "Unassigned"].includes(employee.pos) ? 0 : 1000, workerScript).then(
function () {
return Promise.resolve(AssignJob(employee, job));
},
);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
const office = getOffice(divisionName, cityName);
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:
(ctx: NetscriptContext) =>
@ -770,35 +765,32 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
},
throwParty:
(ctx: NetscriptContext) =>
async (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): Promise<number> => {
(_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
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");
const office = getOffice(divisionName, cityName);
}
const corporation = getCorporation();
return netscriptDelay(
(60 * 1000) / (player.mults.hacking_speed * calculateIntelligenceBonus(player.intelligence, 1)),
workerScript,
).then(function () {
return Promise.resolve(ThrowParty(corporation, office, costPerEmployee));
});
const office = getOffice(divisionName, cityName);
return ThrowParty(corporation, office, costPerEmployee);
},
buyCoffee:
(ctx: NetscriptContext) =>
async (_divisionName: unknown, _cityName: unknown): Promise<void> => {
(_divisionName: unknown, _cityName: unknown): boolean => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const corporation = getCorporation();
return netscriptDelay(
(60 * 1000) / (player.mults.hacking_speed * calculateIntelligenceBonus(player.intelligence, 1)),
workerScript,
).then(function () {
return Promise.resolve(BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName)));
});
const office = getOffice(divisionName, cityName);
return BuyCoffee(corporation, office);
},
hireAdVert:
(ctx: NetscriptContext) =>
@ -806,7 +798,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const corporation = getCorporation();
HireAdVert(corporation, getDivision(divisionName), getOffice(divisionName, "Sector-12"));
HireAdVert(corporation, getDivision(divisionName));
},
research:
(ctx: NetscriptContext) =>
@ -830,6 +822,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
maxEne: office.maxEne,
minHap: office.minHap,
maxHap: office.maxHap,
minMor: office.minMor,
maxMor: office.maxMor,
employees: office.employees.map((e) => e.name),
employeeProd: {

@ -6589,9 +6589,8 @@ export interface OfficeAPI {
* @param cityName - Name of the city
* @param employeeName - name of the employee
* @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.
* @param divisionName - Name of the division
@ -6611,16 +6610,16 @@ export interface OfficeAPI {
* @param divisionName - Name of the division
* @param cityName - Name of the city
* @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
* @param divisionName - Name of the division
* @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.
* @param divisionName - Name of the division
@ -6679,9 +6678,9 @@ export interface OfficeAPI {
* @param cityName - Name of the city
* @param job - Name of the 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.
* @param divisionName - Name of the division
@ -7200,6 +7199,8 @@ export interface Office {
minHap: number;
/** Maximum happiness of the employees */
maxHap: number;
/** Minimum morale of the employees */
minMor: number;
/** Maximum morale of the employees */
maxMor: number;
/** Name of all the employees */