From b9356ea782c785babe56ad5f5f0749c389010dbd Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 18:11:33 +0100 Subject: [PATCH 01/16] Only switch employee jobs at the start of corp cycles --- src/Corporation/Actions.ts | 14 ++++- src/Corporation/Employee.ts | 2 + src/Corporation/OfficeSpace.ts | 77 ++++++++++++++++----------- src/Corporation/ui/IndustryOffice.tsx | 34 ++++++------ src/NetscriptFunctions/Corporation.ts | 42 +++++++++------ 5 files changed, 103 insertions(+), 66 deletions(-) diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index 1ec820037..d3b6b31c9 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -304,9 +304,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 { diff --git a/src/Corporation/Employee.ts b/src/Corporation/Employee.ts index 60a08f202..17b485e25 100644 --- a/src/Corporation/Employee.ts +++ b/src/Corporation/Employee.ts @@ -34,6 +34,7 @@ export class Employee { cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise; loc: string; pos: string; + nextPos: string; constructor(params: IParams = {}) { this.name = params.name ? params.name : "Bobby"; @@ -52,6 +53,7 @@ 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 diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index 623b3c5d3..fe5f2d781 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -37,7 +37,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,7 +66,13 @@ export class OfficeSpace { } } + for (let i = 0; i < this.employees.length; ++i) { + const emp = this.employees[i]; + emp.pos = emp.nextPos; + } + this.calculateTotalEmployees(); + this.calculateNextEmployees(); // Process Office properties this.maxEne = 100; @@ -113,6 +127,18 @@ export class OfficeSpace { return salaryPaid; } + 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 { //Reset for (const name of Object.keys(this.employeeJobs)) { @@ -123,7 +149,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 +198,33 @@ 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; } toJSON(): any { diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index 10bf65af8..a4536de28 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -115,14 +115,14 @@ function ManualManagement(props: IProps): React.ReactElement { {positionNames[i]} , ); - if (emp != null && emp.pos === positionNames[i]) { - employeePositionSelectorInitialValue = positionNames[i]; + if (emp != null && emp.nextPos === positionNames[i]) { + employeePositionSelectorInitialValue = emp.nextPos; } } function employeePositionSelectorOnChange(e: SelectChangeEvent): void { if (employee === null) return; - employee.pos = e.target.value; + props.office.assignSingleJob(employee, e.target.value); props.rerender(); } @@ -181,38 +181,40 @@ interface IAutoAssignProps { 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 ( - {props.job} ({numJob}) + {props.job} ({(currJob == nextJob ? currJob : `${currJob} -> ${nextJob}`)}) - + - + @@ -223,7 +225,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,6 +248,9 @@ 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 ( <> @@ -256,7 +260,7 @@ function AutoManagement(props: IProps): React.ReactElement { Unassigned Employees: - {numUnassigned} + {(currUna == nextUna ? currUna : `${currUna} -> ${nextUna}`)} diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 9ed771625..27f9ab7a9 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -34,6 +34,7 @@ import { SetSmartSupply, BuyMaterial, AssignJob, + AutoAssignJob, UpgradeOfficeSize, ThrowParty, PurchaseWarehouse, @@ -685,20 +686,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 => { - 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 => { @@ -724,10 +711,31 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript 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); + + return netscriptDelay(0, workerScript).then(function () { + return Promise.resolve(AssignJob(office, employeeName, job)); }); + //return AssignJob(office, employeeName, job); + }, + setAutoJobAssignment: + (ctx: NetscriptContext) => + (_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): Promise => { + 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 netscriptDelay(0, workerScript).then(function () { + return Promise.resolve(AutoAssignJob(office, job, amount)); + }); + //return AutoAssignJob(office, job, amount); }, hireEmployee: (ctx: NetscriptContext) => From 7d3a43f7b59e2d259a662f498ab83e5d72d7cd75 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 18:18:53 +0100 Subject: [PATCH 02/16] Remove async from employee assignment functions --- src/NetscriptFunctions/Corporation.ts | 14 ++++---------- src/ScriptEditor/NetscriptDefinitions.d.ts | 7 +++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 27f9ab7a9..6d28ca518 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -705,7 +705,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript }, assignJob: (ctx: NetscriptContext) => - (_divisionName: unknown, _cityName: unknown, _employeeName: unknown, _job: unknown): Promise => { + (_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); @@ -715,14 +715,11 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); const office = getOffice(divisionName, cityName); - return netscriptDelay(0, workerScript).then(function () { - return Promise.resolve(AssignJob(office, employeeName, job)); - }); - //return AssignJob(office, employeeName, job); + AssignJob(office, employeeName, job); }, setAutoJobAssignment: (ctx: NetscriptContext) => - (_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): Promise => { + (_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); @@ -732,10 +729,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); const office = getOffice(divisionName, cityName); - return netscriptDelay(0, workerScript).then(function () { - return Promise.resolve(AutoAssignJob(office, job, amount)); - }); - //return AutoAssignJob(office, job, amount); + return AutoAssignJob(office, job, amount); }, hireEmployee: (ctx: NetscriptContext) => diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 01432f441..d8b5e575a 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -6618,9 +6618,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; + assignJob(divisionName: string, cityName: string, employeeName: string, job: string): void; /** * Hire an employee. * @param divisionName - Name of the division @@ -6708,9 +6707,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; + setAutoJobAssignment(divisionName: string, cityName: string, job: string, amount: number): boolean; /** * Cost to Upgrade office size. * @param divisionName - Name of the division From 1ba5902e1ebecccca0d29254992d097c2c8fd063 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 18:34:24 +0100 Subject: [PATCH 03/16] Stop auto employee buttons moving around when the numbers change --- src/Corporation/ui/IndustryOffice.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index a4536de28..ba80822a3 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -203,7 +203,7 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { return ( - + {props.job} ({(currJob == nextJob ? currJob : `${currJob} -> ${nextJob}`)}) @@ -256,7 +256,7 @@ function AutoManagement(props: IProps): React.ReactElement {
- + Unassigned Employees: @@ -264,7 +264,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + Avg Employee Morale: @@ -272,7 +272,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + Avg Employee Happiness: @@ -280,7 +280,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + Avg Employee Energy: @@ -288,7 +288,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + Total Employee Salary: @@ -300,7 +300,7 @@ function AutoManagement(props: IProps): React.ReactElement { {vechain && ( <> - + @@ -320,7 +320,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + @@ -345,7 +345,7 @@ function AutoManagement(props: IProps): React.ReactElement { - + The effect this office's 'Business' employees has on boosting sales} > From ffaa38d08613336a6ab912c00efd0928cab16455 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 23:26:32 +0100 Subject: [PATCH 04/16] Unify code paths for buying coffee and throwing parties --- src/Corporation/Actions.ts | 32 ++++---- src/Corporation/Employee.ts | 20 +---- src/Corporation/OfficeSpace.ts | 86 +++++++++++++++------- src/NetscriptFunctions/Corporation.ts | 28 ++++--- src/ScriptEditor/NetscriptDefinitions.d.ts | 2 + 5 files changed, 95 insertions(+), 73 deletions(-) diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index d3b6b31c9..71e59eaad 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -333,14 +333,21 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: corp.funds = corp.funds - cost; } +export function BuyCoffee(corp: ICorporation, office: OfficeSpace): void { + const cost = 500e3 * office.employees.length; + if (corp.funds < cost) { return; } + + if (!office.setCoffee()) { return; } + 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); - } + 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; } @@ -372,17 +379,6 @@ 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]; - 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]); diff --git a/src/Corporation/Employee.ts b/src/Corporation/Employee.ts index 17b485e25..3d7db353d 100644 --- a/src/Corporation/Employee.ts +++ b/src/Corporation/Employee.ts @@ -58,8 +58,8 @@ export class Employee { //Returns the amount the employee needs to be paid process(marketCycles = 1, office: OfficeSpace): number { - const gain = 0.003 * marketCycles, - det = gain * Math.random(); + const gain = 0.003 * marketCycles; + const det = gain * Math.random(); this.exp += gain; //Training @@ -74,12 +74,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; } @@ -120,16 +114,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(): any { return Generic_toJSON("Employee", this); } diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index fe5f2d781..20d8e6e1f 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -15,11 +15,20 @@ 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; + employees: Employee[] = []; employeeProd: { [key: string]: number } = { [EmployeePositions.Operations]: 0, @@ -66,11 +75,8 @@ export class OfficeSpace { } } - for (let i = 0; i < this.employees.length; ++i) { - const emp = this.employees[i]; - emp.pos = emp.nextPos; - } - + // Update employee jobs and job counts + for (const employee of this.employees) { employee.pos = employee.nextPos; } this.calculateTotalEmployees(); this.calculateNextEmployees(); @@ -78,6 +84,7 @@ export class OfficeSpace { this.maxEne = 100; this.maxHap = 100; this.maxMor = 100; + if (industry.hasResearch("Go-Juice")) { this.maxEne += 10; } @@ -87,6 +94,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 @@ -96,35 +109,40 @@ 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, this); + 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) { + employee.ene *= this.coffeeMult; } 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) { + employee.mor *= this.partyMult; + employee.hap *= this.partyMult; } 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.calculateEmployeeProductivity(corporation, industry); - return salaryPaid; + return totalSalary; } calculateNextEmployees(): void { @@ -227,6 +245,24 @@ export class OfficeSpace { return count === target; } + setCoffee(mult = 1.05): boolean { + if (mult > 1 && this.coffeeMult === 0 && !this.autoCoffee) { + this.coffeeMult = mult; + return true; + } + + return false; + } + + setParty(mult: number): boolean { + if (mult > 1 && this.partyMult === 0 && !this.autoParty) { + this.partyMult = mult; + return true; + } + + return false; + } + toJSON(): any { return Generic_toJSON("OfficeSpace", this); } diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 6d28ca518..1f7bd94c7 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -36,10 +36,10 @@ import { AssignJob, AutoAssignJob, UpgradeOfficeSize, - ThrowParty, PurchaseWarehouse, UpgradeWarehouse, BuyCoffee, + ThrowParty, HireAdVert, MakeProduct, Research, @@ -774,16 +774,18 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript 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.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), - workerScript, - ).then(function () { + const office = getOffice(divisionName, cityName); + + return netscriptDelay(0, workerScript).then(function () { return Promise.resolve(ThrowParty(corporation, office, costPerEmployee)); }); + //return ThrowParty(corporation, office, costPerEmployee) }, buyCoffee: (ctx: NetscriptContext) => @@ -791,13 +793,14 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript 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.hacking_speed_mult * calculateIntelligenceBonus(player.intelligence, 1)), - workerScript, - ).then(function () { - return Promise.resolve(BuyCoffee(corporation, getDivision(divisionName), getOffice(divisionName, cityName))); + const office = getOffice(divisionName, cityName); + + return netscriptDelay(0, workerScript).then(function () { + return Promise.resolve(BuyCoffee(corporation, office)); }); + //BuyCoffee(corporation, getOffice(divisionName, cityName); }, hireAdVert: (ctx: NetscriptContext) => @@ -829,6 +832,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: { diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index d8b5e575a..e4be6a507 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -7222,6 +7222,8 @@ 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 */ From 04efd899a087e7c6c96c3be6567206c8dcbe6849 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 23:28:14 +0100 Subject: [PATCH 05/16] Remove async from buyCoffee and throwParty --- src/Corporation/Actions.ts | 8 +++++--- src/NetscriptFunctions/Corporation.ts | 14 ++++---------- src/ScriptEditor/NetscriptDefinitions.d.ts | 8 ++++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index 71e59eaad..fa4d383a4 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -333,12 +333,14 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: corp.funds = corp.funds - cost; } -export function BuyCoffee(corp: ICorporation, office: OfficeSpace): void { +export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean { const cost = 500e3 * office.employees.length; - if (corp.funds < cost) { return; } + if (corp.funds < cost) { return false; } - if (!office.setCoffee()) { return; } + if (!office.setCoffee()) { return false; } corp.funds -= cost; + + return true; } export function ThrowParty(corp: ICorporation, office: OfficeSpace, costPerEmployee: number): number { diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 1f7bd94c7..0fc8804fc 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -769,7 +769,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript }, throwParty: (ctx: NetscriptContext) => - async (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): Promise => { + (_divisionName: unknown, _cityName: unknown, _costPerEmployee: unknown): number => { checkAccess(ctx, 8); const divisionName = ctx.helper.string("divisionName", _divisionName); const cityName = ctx.helper.city("cityName", _cityName); @@ -782,14 +782,11 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript const corporation = getCorporation(); const office = getOffice(divisionName, cityName); - return netscriptDelay(0, workerScript).then(function () { - return Promise.resolve(ThrowParty(corporation, office, costPerEmployee)); - }); - //return ThrowParty(corporation, office, costPerEmployee) + return ThrowParty(corporation, office, costPerEmployee) }, buyCoffee: (ctx: NetscriptContext) => - async (_divisionName: unknown, _cityName: unknown): Promise => { + (_divisionName: unknown, _cityName: unknown): boolean => { checkAccess(ctx, 8); const divisionName = ctx.helper.string("divisionName", _divisionName); const cityName = ctx.helper.city("cityName", _cityName); @@ -797,10 +794,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript const corporation = getCorporation(); const office = getOffice(divisionName, cityName); - return netscriptDelay(0, workerScript).then(function () { - return Promise.resolve(BuyCoffee(corporation, office)); - }); - //BuyCoffee(corporation, getOffice(divisionName, cityName); + return BuyCoffee(corporation, office); }, hireAdVert: (ctx: NetscriptContext) => diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index e4be6a507..cf0e12a82 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -6639,16 +6639,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; + 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; + buyCoffee(divisionName: string, cityName: string): boolean; /** * Hire AdVert. * @param divisionName - Name of the division From fe83ca0f3f06bef64e6604fb4d77554900e3f88e Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Wed, 1 Jun 2022 23:45:29 +0100 Subject: [PATCH 06/16] Make throw party UI reflect if we're throwing a party --- src/Corporation/ui/IndustryOffice.tsx | 4 ++-- src/Corporation/ui/modals/ThrowPartyModal.tsx | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index ba80822a3..b5f040a0b 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -464,8 +464,8 @@ export function IndustryOffice(props: IProps): React.ReactElement { title={Throw an office party to increase your employee's morale and happiness} > - diff --git a/src/Corporation/ui/modals/ThrowPartyModal.tsx b/src/Corporation/ui/modals/ThrowPartyModal.tsx index 1df61aac0..8bbd9d3f7 100644 --- a/src/Corporation/ui/modals/ThrowPartyModal.tsx +++ b/src/Corporation/ui/modals/ThrowPartyModal.tsx @@ -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(); } From 9ffec86b58fd6c8e3b053c2c0925d510108e6f81 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 00:00:30 +0100 Subject: [PATCH 07/16] Make buy coffee UI reflect if we're buying coffee --- src/Corporation/ui/IndustryOverview.tsx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Corporation/ui/IndustryOverview.tsx b/src/Corporation/ui/IndustryOverview.tsx index 60390e11e..a0e687fb5 100644 --- a/src/Corporation/ui/IndustryOverview.tsx +++ b/src/Corporation/ui/IndustryOverview.tsx @@ -2,6 +2,8 @@ // (top-left panel in the Industry UI) import React, { useState } from "react"; +import { BuyCoffee } from "../Actions"; + import { OfficeSpace } from "../OfficeSpace"; import { Industries } from "../IndustryData"; import { IndustryUpgrades } from "../IndustryUpgrades"; @@ -226,30 +228,39 @@ function Upgrades(props: { office: OfficeSpace; rerender: () => void }): React.R const i = upgrade[0]; const baseCost = upgrade[1]; const priceMult = upgrade[2]; + let cost = 0; + let disabled = false; switch (i) { case 0: //Coffee, cost is static per employee cost = props.office.employees.length * baseCost; + disabled = cost > corp.funds || props.office.coffeeMult > 0; break; default: cost = baseCost * Math.pow(priceMult, division.upgrades[i]); + disabled = cost > corp.funds; break; } function onClick(): void { if (corp.funds < cost) return; corp.funds = corp.funds - cost; - division.upgrade(upgrade, { - corporation: corp, - office: props.office, - }); + + if (i == 0) { + BuyCoffee(corp, props.office); + } else { + division.upgrade(upgrade, { + corporation: corp, + office: props.office, + }); + } props.rerender(); } upgrades.push( - From 18a80d3fe97248006a1436847572e0ca2d9dd532 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 00:07:34 +0100 Subject: [PATCH 08/16] Stop potential exploit where you could cheat at coffee/party prices --- src/Corporation/OfficeSpace.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index 20d8e6e1f..a299c37ea 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -28,6 +28,8 @@ export class OfficeSpace { autoParty = false; coffeeMult = 0; partyMult = 0; + coffeeEmployees = 0; + partyEmployees = 0; employees: Employee[] = []; employeeProd: { [key: string]: number } = { @@ -117,7 +119,8 @@ export class OfficeSpace { if (this.autoCoffee) { employee.ene = this.maxEne; } else if (this.coffeeMult > 1) { - employee.ene *= this.coffeeMult; + const mult = 1 + (this.coffeeMult - 1) * this.employees.length / this.coffeeEmployees; + employee.ene *= mult; } else { employee.ene *= perfMult; } @@ -126,8 +129,9 @@ export class OfficeSpace { employee.mor = this.maxMor; employee.hap = this.maxHap; } else if (this.partyMult > 1) { - employee.mor *= this.partyMult; - employee.hap *= this.partyMult; + const mult = 1 + (this.partyMult - 1) * this.employees.length / this.partyEmployees; + employee.mor *= mult; + employee.hap *= mult; } else { employee.mor *= perfMult; employee.hap *= perfMult; @@ -140,6 +144,8 @@ export class OfficeSpace { this.coffeeMult = 0; this.partyMult = 0; + this.coffeeEmployees = 0; + this.partyEmployees = 0; this.calculateEmployeeProductivity(corporation, industry); return totalSalary; @@ -246,8 +252,9 @@ export class OfficeSpace { } setCoffee(mult = 1.05): boolean { - if (mult > 1 && this.coffeeMult === 0 && !this.autoCoffee) { + if (mult > 1 && this.coffeeMult === 0 && !this.autoCoffee && this.employees.length > 0) { this.coffeeMult = mult; + this.coffeeEmployees = this.employees.length; return true; } @@ -255,8 +262,9 @@ export class OfficeSpace { } setParty(mult: number): boolean { - if (mult > 1 && this.partyMult === 0 && !this.autoParty) { + if (mult > 1 && this.partyMult === 0 && !this.autoParty && this.employees.length > 0) { this.partyMult = mult; + this.partyEmployees = this.employees.length; return true; } From ba7b76369b76bb763bad339f490e2594a783eed5 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 02:43:22 +0100 Subject: [PATCH 09/16] Remove industry upgrades There are only two industry upgrades, one of which is buying coffee which is not an upgrade, and for the office not the industry. Moving that to the office leaves just hiring AdVerts, which is better as an explicitly named set of methods. --- src/Corporation/Actions.ts | 13 ++-- src/Corporation/IIndustry.ts | 7 +- src/Corporation/Industry.ts | 47 ++++-------- src/Corporation/IndustryUpgrades.ts | 22 ------ src/Corporation/OfficeSpace.ts | 4 ++ src/Corporation/ui/IndustryOverview.tsx | 95 ++++++++----------------- src/NetscriptFunctions/Corporation.ts | 10 ++- 7 files changed, 59 insertions(+), 139 deletions(-) delete mode 100644 src/Corporation/IndustryUpgrades.ts diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index fa4d383a4..2492ac999 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -14,7 +14,6 @@ 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"; @@ -334,7 +333,7 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: } export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean { - const cost = 500e3 * office.employees.length; + const cost = office.getCoffeeCost(); if (corp.funds < cost) { return false; } if (!office.setCoffee()) { return false; } @@ -381,15 +380,11 @@ export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, wareho corp.funds = corp.funds - sizeUpgradeCost; } -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]); +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, - }); + division.applyAdVert(corp); } export function MakeProduct( diff --git a/src/Corporation/IIndustry.ts b/src/Corporation/IIndustry.ts index 1cb5737ea..7b465720d 100644 --- a/src/Corporation/IIndustry.ts +++ b/src/Corporation/IIndustry.ts @@ -3,7 +3,6 @@ import { Warehouse } from "./Warehouse"; import { ICorporation } from "./ICorporation"; import { OfficeSpace } from "./OfficeSpace"; import { Product } from "./Product"; -import { IndustryUpgrade } from "./IndustryUpgrades"; export interface IIndustry { name: string; @@ -36,12 +35,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; @@ -56,7 +54,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]; diff --git a/src/Corporation/Industry.ts b/src/Corporation/Industry.ts index f2a12e129..3c00ae379 100644 --- a/src/Corporation/Industry.ts +++ b/src/Corporation/Industry.ts @@ -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; @@ -1262,38 +1260,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) diff --git a/src/Corporation/IndustryUpgrades.ts b/src/Corporation/IndustryUpgrades.ts deleted file mode 100644 index 6190fabf4..000000000 --- a/src/Corporation/IndustryUpgrades.ts +++ /dev/null @@ -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 = { - "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.", - ], -}; diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index a299c37ea..7f662a769 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -251,6 +251,10 @@ export class OfficeSpace { 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; diff --git a/src/Corporation/ui/IndustryOverview.tsx b/src/Corporation/ui/IndustryOverview.tsx index a0e687fb5..6c75830d1 100644 --- a/src/Corporation/ui/IndustryOverview.tsx +++ b/src/Corporation/ui/IndustryOverview.tsx @@ -2,11 +2,9 @@ // (top-left panel in the Industry UI) import React, { useState } from "react"; -import { BuyCoffee } from "../Actions"; - import { OfficeSpace } from "../OfficeSpace"; import { Industries } from "../IndustryData"; -import { IndustryUpgrades } from "../IndustryUpgrades"; +import { BuyCoffee, HireAdVert } from "../Actions"; import { numeralWrapper } from "../../ui/numeralFormat"; import { createProgressBarText } from "../../utils/helpers/createProgressBarText"; import { MakeProductModal } from "./modals/MakeProductModal"; @@ -209,69 +207,40 @@ function Text(): React.ReactElement { setResearchOpen(false)} industry={division} /> + + Purchases & Upgrades + + + + + + + + + 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. + + }> + + + + + ); } -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; - let disabled = false; - switch (i) { - case 0: //Coffee, cost is static per employee - cost = props.office.employees.length * baseCost; - disabled = cost > corp.funds || props.office.coffeeMult > 0; - break; - default: - cost = baseCost * Math.pow(priceMult, division.upgrades[i]); - disabled = cost > corp.funds; - break; - } - - function onClick(): void { - if (corp.funds < cost) return; - corp.funds = corp.funds - cost; - - if (i == 0) { - BuyCoffee(corp, props.office); - } else { - division.upgrade(upgrade, { - corporation: corp, - office: props.office, - }); - } - props.rerender(); - } - - upgrades.push( - - - - - , - ); - } - - return <>{upgrades}; -} - interface IProps { currentCity: string; office: OfficeSpace; @@ -285,8 +254,6 @@ export function IndustryOverview(props: IProps): React.ReactElement {
- Purchases & Upgrades -
{division.makesProducts && }
); diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 0fc8804fc..212b7a3ff 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -64,7 +64,6 @@ import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligen 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"; @@ -303,7 +302,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 +658,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 +666,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) => @@ -802,7 +800,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) => From 333975ecf6bdb58480355dbcabf27b0560ae1201 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 14:43:14 +0100 Subject: [PATCH 10/16] Move buy coffee button to office UI section --- src/Corporation/ui/IndustryOffice.tsx | 16 ++++++++ src/Corporation/ui/IndustryOverview.tsx | 54 +++++++------------------ 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index b5f040a0b..a2b79736d 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -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"; @@ -458,6 +460,20 @@ export function IndustryOffice(props: IProps): React.ReactElement { onClose={() => setUpgradeOfficeSizeOpen(false)} /> + {!division.hasResearch("AutoBrew") && ( + <> + Throw an office party to increase your employee's morale and happiness} + > + + + + + + )} + {!division.hasResearch("AutoPartyManager") && ( <> ); } -function Text(): React.ReactElement { + +interface IProps { + currentCity: string; + office: OfficeSpace; + rerender: () => void; +} + +export function IndustryOverview(props: IProps): React.ReactElement { const corp = useCorporation(); const division = useDivision(); const [helpOpen, setHelpOpen] = useState(false); @@ -113,7 +120,7 @@ function Text(): React.ReactElement { } return ( - <> + Industry: {division.type} (Corp Funds: ) @@ -191,7 +198,6 @@ function Text(): React.ReactElement { - setResearchOpen(false)} industry={division} /> - - Purchases & Upgrades - +
- - - - - @@ -229,32 +225,12 @@ function Text(): React.ReactElement { that increase the power of your advertising. }> - - - + + {division.makesProducts && } - - ); -} - -interface IProps { - currentCity: string; - office: OfficeSpace; - rerender: () => void; -} - -export function IndustryOverview(props: IProps): React.ReactElement { - const division = useDivision(); - - return ( - - -
- {division.makesProducts && }
); } From 1ed19168f676ef91669310b3e981bc8973bd92a1 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 17:47:31 +0100 Subject: [PATCH 11/16] Use nicer arrows and alignment in office UI --- src/Corporation/ui/IndustryOffice.tsx | 327 +++++++++++++------------- 1 file changed, 167 insertions(+), 160 deletions(-) diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index a2b79736d..ae29985bb 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -19,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 KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp"; import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import Tooltip from "@mui/material/Tooltip"; @@ -180,6 +181,16 @@ interface IAutoAssignProps { rerender: () => void; } +function EmployeeCount(props: { num: number, next: number }): React.ReactElement { + return ( + + {props.num === props.next ? null : props.num} + {props.num === props.next ? null : } + {props.next} + + ); +} + function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { const corp = useCorporation(); const division = useDivision(); @@ -205,17 +216,20 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { return ( - + - - {props.job} ({(currJob == nextJob ? currJob : `${currJob} -> ${nextJob}`)}) - + {props.job} + + + + + @@ -254,167 +268,160 @@ function AutoManagement(props: IProps): React.ReactElement { const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned]; return ( - <> -
- - - - Unassigned Employees: - - - {(currUna == nextUna ? currUna : `${currUna} -> ${nextUna}`)} - - - - - Avg Employee Morale: - - - {numeralWrapper.format(avgMorale, "0.000")} - - - - - Avg Employee Happiness: - - - {numeralWrapper.format(avgHappiness, "0.000")} - - - - - Avg Employee Energy: - - - {numeralWrapper.format(avgEnergy, "0.000")} - - - - - Total Employee Salary: - - - - - - - - {vechain && ( - <> - - - - 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 - - } - > - Material Production: - - - - - {numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")} - - - - - - - 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 - - } - > - Product Production: - - - - - {numeralWrapper.format( - division.getOfficeProductivity(props.office, { - forProduct: true, - }), - "0.000", - )} - - - - - - The effect this office's 'Business' employees has on boosting sales} - > - Business Multiplier: - - - - x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")} - - - - )} - -
+ + + + + Unassigned Employees: + + + + + + + + Avg Employee Morale: + + + {numeralWrapper.format(avgMorale, "0.000")} + + + + + Avg Employee Happiness: + + + {numeralWrapper.format(avgHappiness, "0.000")} + + + + + Avg Employee Energy: + + + {numeralWrapper.format(avgEnergy, "0.000")} + + + + + Total Employee Salary: + + + + + + + + {vechain && ( + <> + + + + 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 + + } + > + Material Production: + + + + + {numeralWrapper.format(division.getOfficeProductivity(props.office), "0.000")} + + + + + + + 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 + + } + > + Product Production: + + + + + {numeralWrapper.format( + division.getOfficeProductivity(props.office, { + forProduct: true, + }), + "0.000", + )} + + + + + + The effect this office's 'Business' employees has on boosting sales} + > + Business Multiplier: + + + + x{numeralWrapper.format(division.getBusinessFactor(props.office), "0.000")} + + + + )} + -
- - + - + - + - + - - - - -
- + + + ); } From b29c8e0039968660f82644644feda9a0df2a64f8 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 22:11:34 +0100 Subject: [PATCH 12/16] Stop potential exploit where you switch employees around right before a product finishes --- src/Corporation/Industry.ts | 18 +----- src/Corporation/Product.ts | 119 ++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 63 deletions(-) diff --git a/src/Corporation/Industry.ts b/src/Corporation/Industry.ts index 3c00ae379..21dc4d6af 100644 --- a/src/Corporation/Industry.ts +++ b/src/Corporation/Industry.ts @@ -1002,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; } diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index cfe15917f..b674dba77 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -55,6 +55,15 @@ 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, + }; + // 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,75 +126,91 @@ 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 { - if (this.fin) { - return; + // Make progress on this product based on current employee productivity + createProduct(marketCycles: number, employeeProd: typeof this["creationProd"]): void { + if (this.fin) { return; } + + // 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)) { + this.creationProd[pos] += employeeProd[pos] * progress / 100; } - this.prog += marketCycles * 0.01 * empWorkMult; } // @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"]; - const designMult = 1 + Math.pow(this.designCost, 0.1) / 100; + // Calculate properties + const totalProd = Object.values(this.creationProd).reduce((p, q) => p + q); + 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; - const totalMult = balanceMult * designMult * sciMult; + const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; + const totalMult = balanceMult * designMult * sciMult; 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. From 02b07bb33215b2eb5f3ee2bc406112a460682383 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Thu, 2 Jun 2022 22:51:36 +0100 Subject: [PATCH 13/16] Fix relevant linter errors and run formatter --- src/Corporation/Actions.ts | 21 +++++++++----- src/Corporation/Employee.ts | 3 +- src/Corporation/OfficeSpace.ts | 20 +++++++------ src/Corporation/Product.ts | 36 ++++++++++++++---------- src/Corporation/ui/Industry.tsx | 2 +- src/Corporation/ui/IndustryOffice.tsx | 37 +++++++++++++------------ src/Corporation/ui/IndustryOverview.tsx | 23 ++++++++------- src/NetscriptFunctions.ts | 2 +- src/NetscriptFunctions/Corporation.ts | 9 ++---- 9 files changed, 84 insertions(+), 69 deletions(-) diff --git a/src/Corporation/Actions.ts b/src/Corporation/Actions.ts index 2492ac999..22eccc181 100644 --- a/src/Corporation/Actions.ts +++ b/src/Corporation/Actions.ts @@ -13,7 +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 { ResearchMap } from "./ResearchMap"; import { isRelevantMaterial } from "./ui/Helpers"; @@ -304,7 +303,7 @@ export function BuyBackShares(corporation: ICorporation, player: IPlayer, numSha } export function AssignJob(office: OfficeSpace, employeeName: string, job: string): void { - const employee = office.employees.find(e => e.name === employeeName); + 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.`); @@ -314,7 +313,7 @@ export function AssignJob(office: OfficeSpace, employeeName: string, job: string 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); } @@ -334,9 +333,13 @@ export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean { const cost = office.getCoffeeCost(); - if (corp.funds < cost) { return false; } + if (corp.funds < cost) { + return false; + } - if (!office.setCoffee()) { return false; } + if (!office.setCoffee()) { + return false; + } corp.funds -= cost; return true; @@ -345,9 +348,13 @@ export function BuyCoffee(corp: ICorporation, office: OfficeSpace): boolean { 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 (corp.funds < cost) { + return 0; + } - if (!office.setParty(mult)) { return 0; } + if (!office.setParty(mult)) { + return 0; + } corp.funds -= cost; return mult; diff --git a/src/Corporation/Employee.ts b/src/Corporation/Employee.ts index 3d7db353d..bed72a99c 100644 --- a/src/Corporation/Employee.ts +++ b/src/Corporation/Employee.ts @@ -3,7 +3,6 @@ import { getRandomInt } from "../utils/helpers/getRandomInt"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { EmployeePositions } from "./EmployeePositions"; import { ICorporation } from "./ICorporation"; -import { OfficeSpace } from "./OfficeSpace"; import { IIndustry } from "./IIndustry"; interface IParams { @@ -57,7 +56,7 @@ export class Employee { } //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 det = gain * Math.random(); this.exp += gain; diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index 7f662a769..63412ee61 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -25,11 +25,11 @@ export class OfficeSpace { maxMor = 100; autoCoffee = false; - autoParty = false; + autoParty = false; coffeeMult = 0; - partyMult = 0; + partyMult = 0; coffeeEmployees = 0; - partyEmployees = 0; + partyEmployees = 0; employees: Employee[] = []; employeeProd: { [key: string]: number } = { @@ -78,7 +78,9 @@ export class OfficeSpace { } // Update employee jobs and job counts - for (const employee of this.employees) { employee.pos = employee.nextPos; } + for (const employee of this.employees) { + employee.pos = employee.nextPos; + } this.calculateTotalEmployees(); this.calculateNextEmployees(); @@ -113,13 +115,13 @@ export class OfficeSpace { let totalSalary = 0; for (const employee of this.employees) { - const salary = employee.process(marketCycles, this); + const salary = employee.process(marketCycles); totalSalary += salary; if (this.autoCoffee) { employee.ene = this.maxEne; } else if (this.coffeeMult > 1) { - const mult = 1 + (this.coffeeMult - 1) * this.employees.length / this.coffeeEmployees; + const mult = 1 + ((this.coffeeMult - 1) * this.employees.length) / this.coffeeEmployees; employee.ene *= mult; } else { employee.ene *= perfMult; @@ -129,7 +131,7 @@ export class OfficeSpace { employee.mor = this.maxMor; employee.hap = this.maxHap; } else if (this.partyMult > 1) { - const mult = 1 + (this.partyMult - 1) * this.employees.length / this.partyEmployees; + const mult = 1 + ((this.partyMult - 1) * this.employees.length) / this.partyEmployees; employee.mor *= mult; employee.hap *= mult; } else { @@ -143,9 +145,9 @@ export class OfficeSpace { } this.coffeeMult = 0; - this.partyMult = 0; + this.partyMult = 0; this.coffeeEmployees = 0; - this.partyEmployees = 0; + this.partyEmployees = 0; this.calculateEmployeeProductivity(corporation, industry); return totalSalary; diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index b674dba77..9917a276a 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -128,24 +128,30 @@ export class Product { // Make progress on this product based on current employee productivity createProduct(marketCycles: number, employeeProd: typeof this["creationProd"]): void { - if (this.fin) { return; } + if (this.fin) { + return; + } // Designing/Creating a Product is based mostly off Engineers - const opProd = employeeProd[EmployeePositions.Operations]; + const opProd = employeeProd[EmployeePositions.Operations]; const engrProd = employeeProd[EmployeePositions.Engineer]; const mgmtProd = employeeProd[EmployeePositions.Management]; - const total = opProd + engrProd + mgmtProd; - if (total <= 0) { return; } + 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; } + 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)) { - this.creationProd[pos] += employeeProd[pos] * progress / 100; + this.creationProd[pos] += (employeeProd[pos] * progress) / 100; } } @@ -155,16 +161,16 @@ export class Product { // Calculate properties const totalProd = Object.values(this.creationProd).reduce((p, q) => p + q); - const engrRatio = this.creationProd[EmployeePositions.Engineer] / totalProd; + 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 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 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; - const totalMult = balanceMult * designMult * sciMult; + const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; + const totalMult = balanceMult * designMult * sciMult; this.qlt = totalMult * diff --git a/src/Corporation/ui/Industry.tsx b/src/Corporation/ui/Industry.tsx index 9a5f65eb1..9c1fafadf 100644 --- a/src/Corporation/ui/Industry.tsx +++ b/src/Corporation/ui/Industry.tsx @@ -25,7 +25,7 @@ export function Industry(props: IProps): React.ReactElement { return ( - + diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index ae29985bb..f7b28d114 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -36,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; @@ -181,7 +173,7 @@ interface IAutoAssignProps { rerender: () => void; } -function EmployeeCount(props: { num: number, next: number }): React.ReactElement { +function EmployeeCount(props: { num: number; next: number }): React.ReactElement { return ( {props.num === props.next ? null : props.num} @@ -192,9 +184,6 @@ function EmployeeCount(props: { num: number, next: number }): React.ReactElement } function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { - const corp = useCorporation(); - const division = useDivision(); - const currJob = props.office.employeeJobs[props.job]; const nextJob = props.office.employeeNextJobs[props.job]; const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned]; @@ -319,9 +308,9 @@ function AutoManagement(props: IProps): React.ReactElement { - 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 + 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 } > @@ -473,8 +462,17 @@ export function IndustryOffice(props: IProps): React.ReactElement { title={Throw an office party to increase your employee's morale and happiness} > - @@ -487,7 +485,10 @@ export function IndustryOffice(props: IProps): React.ReactElement { title={Throw an office party to increase your employee's morale and happiness} > - diff --git a/src/Corporation/ui/IndustryOverview.tsx b/src/Corporation/ui/IndustryOverview.tsx index 4682097c3..337e52d5b 100644 --- a/src/Corporation/ui/IndustryOverview.tsx +++ b/src/Corporation/ui/IndustryOverview.tsx @@ -2,7 +2,6 @@ // (top-left panel in the Industry UI) import React, { useState } from "react"; -import { OfficeSpace } from "../OfficeSpace"; import { Industries } from "../IndustryData"; import { HireAdVert } from "../Actions"; import { numeralWrapper } from "../../ui/numeralFormat"; @@ -89,8 +88,6 @@ function MakeProductButton(): React.ReactElement { } interface IProps { - currentCity: string; - office: OfficeSpace; rerender: () => void; } @@ -218,14 +215,20 @@ export function IndustryOverview(props: IProps): React.ReactElement { - 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. + 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. - }> - diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 02d3a74ba..e4ced14c8 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -531,7 +531,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(), diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 212b7a3ff..fb34437f4 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -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"; @@ -60,7 +58,6 @@ 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"; @@ -69,7 +66,7 @@ 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 { +export function NetscriptCorporation(player: IPlayer): InternalAPI { function createCorporation(corporationName: string, selfFund = true): boolean { if (!player.canAccessCorporation() || player.hasCorporation()) return false; if (!corporationName) return false; @@ -257,7 +254,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript function getMaterial(divisionName: string, cityName: string, materialName: string): Material { const warehouse = getWarehouse(divisionName, cityName); - const matName = (materialName ).replace(/ /g, ""); + const matName = materialName.replace(/ /g, ""); const material = warehouse.materials[matName]; if (material === undefined) throw new Error(`Invalid material name: '${materialName}'`); return material; @@ -780,7 +777,7 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript const corporation = getCorporation(); const office = getOffice(divisionName, cityName); - return ThrowParty(corporation, office, costPerEmployee) + return ThrowParty(corporation, office, costPerEmployee); }, buyCoffee: (ctx: NetscriptContext) => From eb71097006adf6e3b86a8ba68733edf2c3a413ed Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Fri, 3 Jun 2022 00:19:43 +0100 Subject: [PATCH 14/16] Fix bug where NaNs can leak into product creation productivities --- src/Corporation/Product.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index 9917a276a..931fc5d52 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -62,6 +62,7 @@ export class Product { [EmployeePositions.Business]: 0, [EmployeePositions.Management]: 0, [EmployeePositions.RandD]: 0, + total: 0 }; // Aggregate score for this Product's 'rating' @@ -151,6 +152,7 @@ export class Product { 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; } } @@ -160,7 +162,7 @@ export class Product { this.fin = true; // Calculate properties - const totalProd = Object.values(this.creationProd).reduce((p, q) => p + q); + 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; @@ -172,6 +174,12 @@ export class Product { const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; const totalMult = balanceMult * designMult * sciMult; + console.log("============"); + console.log(`${totalProd} ${this.creationProd[EmployeePositions.Engineer]} ${this.creationProd[EmployeePositions.Management]} ${this.creationProd[EmployeePositions.RandD]} ${this.creationProd[EmployeePositions.Operations]} ${this.creationProd[EmployeePositions.Business]}`); + console.log(`${engrRatio} ${mgmtRatio} ${rndRatio} ${opsRatio} ${busRatio}`); + console.log(`${designMult} ${balanceMult} ${sciMult} ${totalMult}`); + console.log("============"); + this.qlt = totalMult * (0.1 * this.creationProd[EmployeePositions.Engineer] + From 052aa33f0cfeb1718266581ec2f529038be907a7 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Fri, 3 Jun 2022 00:27:05 +0100 Subject: [PATCH 15/16] Remove debug console.logs --- src/Corporation/Product.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index 931fc5d52..1e30f66bb 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -62,7 +62,7 @@ export class Product { [EmployeePositions.Business]: 0, [EmployeePositions.Management]: 0, [EmployeePositions.RandD]: 0, - total: 0 + total: 0, }; // Aggregate score for this Product's 'rating' @@ -174,12 +174,6 @@ export class Product { const sciMult = 1 + Math.pow(industry.sciResearch.qty, industry.sciFac) / 800; const totalMult = balanceMult * designMult * sciMult; - console.log("============"); - console.log(`${totalProd} ${this.creationProd[EmployeePositions.Engineer]} ${this.creationProd[EmployeePositions.Management]} ${this.creationProd[EmployeePositions.RandD]} ${this.creationProd[EmployeePositions.Operations]} ${this.creationProd[EmployeePositions.Business]}`); - console.log(`${engrRatio} ${mgmtRatio} ${rndRatio} ${opsRatio} ${busRatio}`); - console.log(`${designMult} ${balanceMult} ${sciMult} ${totalMult}`); - console.log("============"); - this.qlt = totalMult * (0.1 * this.creationProd[EmployeePositions.Engineer] + From 53743ecb7dbd77a4bef64b19cba1656b128463d9 Mon Sep 17 00:00:00 2001 From: Staszek Welsh Date: Fri, 3 Jun 2022 22:16:03 +0100 Subject: [PATCH 16/16] Change UI arrows --- src/Corporation/ui/IndustryOffice.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index f7b28d114..b48031e46 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -19,7 +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 KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; +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"; @@ -177,7 +177,7 @@ function EmployeeCount(props: { num: number; next: number }): React.ReactElement return ( {props.num === props.next ? null : props.num} - {props.num === props.next ? null : } + {props.num === props.next ? null : } {props.next} );