Only switch employee jobs at the start of corp cycles

This commit is contained in:
Staszek Welsh 2022-06-01 18:11:33 +01:00
parent 6f017bf4f6
commit b9356ea782
5 changed files with 103 additions and 66 deletions

@ -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 {

@ -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

@ -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 {

@ -115,14 +115,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();
}
@ -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 (
<TableRow>
<TableCell>
<Tooltip title={props.desc}>
<Typography>
{props.job} ({numJob})
{props.job} ({(currJob == nextJob ? currJob : `${currJob} -> ${nextJob}`)})
</Typography>
</Tooltip>
</TableCell>
<TableCell>
<IconButton disabled={numUnassigned === 0} onClick={assignEmployee}>
<IconButton disabled={nextUna === 0} onClick={assignEmployee}>
<ArrowDropUpIcon />
</IconButton>
<IconButton disabled={numJob === 0} onClick={unassignEmployee}>
<IconButton disabled={nextJob === 0} onClick={unassignEmployee}>
<ArrowDropDownIcon />
</IconButton>
</TableCell>
@ -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 (
<>
<Table padding="none">
@ -256,7 +260,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<Typography>Unassigned Employees:</Typography>
</TableCell>
<TableCell>
<Typography>{numUnassigned}</Typography>
<Typography>{(currUna == nextUna ? currUna : `${currUna} -> ${nextUna}`)}</Typography>
</TableCell>
</TableRow>
<TableRow>

@ -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<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 => {
@ -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<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 netscriptDelay(0, workerScript).then(function () {
return Promise.resolve(AutoAssignJob(office, job, amount));
});
//return AutoAssignJob(office, job, amount);
},
hireEmployee:
(ctx: NetscriptContext) =>