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; return true;
} }
export function AssignJob(employee: Employee, job: string): void { export function AssignJob(office: OfficeSpace, employeeName: string, job: string): void {
const employee = office.employees.find(e => e.name === employeeName);
if (!employee) throw new Error(`Could not find employee '${name}'.`);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`); if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
employee.pos = job;
office.assignSingleJob(employee, job);
}
export function AutoAssignJob(office: OfficeSpace, job: string, count: number): boolean {
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
return office.autoAssignJob(job, count);
} }
export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: number): void { export function UpgradeOfficeSize(corp: ICorporation, office: OfficeSpace, size: number): void {

@ -34,6 +34,7 @@ export class Employee {
cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise; cyclesUntilRaise = CorporationConstants.CyclesPerEmployeeRaise;
loc: string; loc: string;
pos: string; pos: string;
nextPos: string;
constructor(params: IParams = {}) { constructor(params: IParams = {}) {
this.name = params.name ? params.name : "Bobby"; this.name = params.name ? params.name : "Bobby";
@ -52,6 +53,7 @@ export class Employee {
this.loc = params.loc ? params.loc : ""; this.loc = params.loc ? params.loc : "";
this.pos = EmployeePositions.Unassigned; this.pos = EmployeePositions.Unassigned;
this.nextPos = this.pos;
} }
//Returns the amount the employee needs to be paid //Returns the amount the employee needs to be paid

@ -37,7 +37,15 @@ export class OfficeSpace {
[EmployeePositions.RandD]: 0, [EmployeePositions.RandD]: 0,
[EmployeePositions.Training]: 0, [EmployeePositions.Training]: 0,
[EmployeePositions.Unassigned]: 0, [EmployeePositions.Unassigned]: 0,
total: 0, };
employeeNextJobs: { [key: string]: number } = {
[EmployeePositions.Operations]: 0,
[EmployeePositions.Engineer]: 0,
[EmployeePositions.Business]: 0,
[EmployeePositions.Management]: 0,
[EmployeePositions.RandD]: 0,
[EmployeePositions.Training]: 0,
[EmployeePositions.Unassigned]: 0,
}; };
constructor(params: IParams = {}) { constructor(params: IParams = {}) {
@ -58,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.calculateTotalEmployees();
this.calculateNextEmployees();
// Process Office properties // Process Office properties
this.maxEne = 100; this.maxEne = 100;
@ -113,6 +127,18 @@ export class OfficeSpace {
return salaryPaid; 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 { calculateTotalEmployees(): void {
//Reset //Reset
for (const name of Object.keys(this.employeeJobs)) { for (const name of Object.keys(this.employeeJobs)) {
@ -123,7 +149,6 @@ export class OfficeSpace {
const employee = this.employees[i]; const employee = this.employees[i];
this.employeeJobs[employee.pos]++; this.employeeJobs[employee.pos]++;
} }
this.employeeJobs.total = this.employees.length;
} }
calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void { calculateEmployeeProductivity(corporation: ICorporation, industry: IIndustry): void {
@ -173,45 +198,33 @@ export class OfficeSpace {
emp.name = name; emp.name = name;
this.employees.push(emp); this.employees.push(emp);
this.calculateTotalEmployees();
this.calculateNextEmployees();
return emp; return emp;
} }
//Finds the first unassigned employee and assigns its to the specified job assignSingleJob(employee: Employee, job: string): void {
assignEmployeeToJob(job: string): boolean { employee.nextPos = job;
for (let i = 0; i < this.employees.length; ++i) { this.calculateNextEmployees();
if (this.employees[i].pos === EmployeePositions.Unassigned) {
this.employees[i].pos = job;
return true;
}
}
return false;
} }
//Finds the first employee with the given job and unassigns it autoAssignJob(job: string, target: number): boolean {
unassignEmployeeFromJob(job: string): boolean { let count = this.employeeNextJobs[job];
for (let i = 0; i < this.employees.length; ++i) {
if (this.employees[i].pos === job) {
this.employees[i].pos = EmployeePositions.Unassigned;
return true;
}
}
return false;
}
setEmployeeToJob(job: string, amount: number): boolean {
let jobCount = this.employees.reduce((acc, employee) => (employee.pos === job ? acc + 1 : acc), 0);
for (const employee of this.employees) { for (const employee of this.employees) {
if (jobCount == amount) return true; if (count === target) {
if (employee.pos === EmployeePositions.Unassigned && jobCount <= amount) { break;
employee.pos = job; } else if (employee.nextPos === EmployeePositions.Unassigned && count <= target) {
jobCount++; employee.nextPos = job;
} else if (employee.pos === job && jobCount >= amount) { count++;
employee.pos = EmployeePositions.Unassigned; } else if (employee.nextPos === job && count >= target) {
jobCount--; employee.nextPos = EmployeePositions.Unassigned;
count--;
} }
} }
return jobCount === amount;
this.calculateNextEmployees();
return count === target;
} }
toJSON(): any { toJSON(): any {

@ -115,14 +115,14 @@ function ManualManagement(props: IProps): React.ReactElement {
{positionNames[i]} {positionNames[i]}
</MenuItem>, </MenuItem>,
); );
if (emp != null && emp.pos === positionNames[i]) { if (emp != null && emp.nextPos === positionNames[i]) {
employeePositionSelectorInitialValue = positionNames[i]; employeePositionSelectorInitialValue = emp.nextPos;
} }
} }
function employeePositionSelectorOnChange(e: SelectChangeEvent<string>): void { function employeePositionSelectorOnChange(e: SelectChangeEvent<string>): void {
if (employee === null) return; if (employee === null) return;
employee.pos = e.target.value; props.office.assignSingleJob(employee, e.target.value);
props.rerender(); props.rerender();
} }
@ -181,38 +181,40 @@ interface IAutoAssignProps {
function AutoAssignJob(props: IAutoAssignProps): React.ReactElement { function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); 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 { function assignEmployee(): void {
if (numUnassigned <= 0) { if (nextUna <= 0) {
console.warn("Cannot assign employee. No unassigned employees available"); console.warn("Cannot assign employee. No unassigned employees available");
return; return;
} }
props.office.assignEmployeeToJob(props.job); props.office.autoAssignJob(props.job, nextJob + 1);
props.office.calculateEmployeeProductivity(corp, division);
props.rerender(); props.rerender();
} }
function unassignEmployee(): void { function unassignEmployee(): void {
props.office.unassignEmployeeFromJob(props.job); props.office.autoAssignJob(props.job, nextJob - 1);
props.office.calculateEmployeeProductivity(corp, division);
props.rerender(); props.rerender();
} }
return ( return (
<TableRow> <TableRow>
<TableCell> <TableCell>
<Tooltip title={props.desc}> <Tooltip title={props.desc}>
<Typography> <Typography>
{props.job} ({numJob}) {props.job} ({(currJob == nextJob ? currJob : `${currJob} -> ${nextJob}`)})
</Typography> </Typography>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
<TableCell> <TableCell>
<IconButton disabled={numUnassigned === 0} onClick={assignEmployee}> <IconButton disabled={nextUna === 0} onClick={assignEmployee}>
<ArrowDropUpIcon /> <ArrowDropUpIcon />
</IconButton> </IconButton>
<IconButton disabled={numJob === 0} onClick={unassignEmployee}> <IconButton disabled={nextJob === 0} onClick={unassignEmployee}>
<ArrowDropDownIcon /> <ArrowDropDownIcon />
</IconButton> </IconButton>
</TableCell> </TableCell>
@ -223,7 +225,6 @@ function AutoAssignJob(props: IAutoAssignProps): React.ReactElement {
function AutoManagement(props: IProps): React.ReactElement { function AutoManagement(props: IProps): React.ReactElement {
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); const division = useDivision();
const numUnassigned = countEmployee(props.office.employees, EmployeePositions.Unassigned);
const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade const vechain = corp.unlockUpgrades[4] === 1; // Has Vechain upgrade
// Calculate average morale, happiness, energy, and salary. // Calculate average morale, happiness, energy, and salary.
@ -247,6 +248,9 @@ function AutoManagement(props: IProps): React.ReactElement {
avgEnergy = totalEnergy / props.office.employees.length; avgEnergy = totalEnergy / props.office.employees.length;
} }
const currUna = props.office.employeeJobs[EmployeePositions.Unassigned];
const nextUna = props.office.employeeNextJobs[EmployeePositions.Unassigned];
return ( return (
<> <>
<Table padding="none"> <Table padding="none">
@ -256,7 +260,7 @@ function AutoManagement(props: IProps): React.ReactElement {
<Typography>Unassigned Employees:</Typography> <Typography>Unassigned Employees:</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>
<Typography>{numUnassigned}</Typography> <Typography>{(currUna == nextUna ? currUna : `${currUna} -> ${nextUna}`)}</Typography>
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>

@ -34,6 +34,7 @@ import {
SetSmartSupply, SetSmartSupply,
BuyMaterial, BuyMaterial,
AssignJob, AssignJob,
AutoAssignJob,
UpgradeOfficeSize, UpgradeOfficeSize,
ThrowParty, ThrowParty,
PurchaseWarehouse, PurchaseWarehouse,
@ -685,20 +686,6 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
const researchName = ctx.helper.string("researchName", _researchName); const researchName = ctx.helper.string("researchName", _researchName);
return hasResearched(getDivision(divisionName), researchName); return hasResearched(getDivision(divisionName), researchName);
}, },
setAutoJobAssignment:
(ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _job: unknown, _amount: unknown): Promise<boolean> => {
checkAccess(ctx, 8);
const divisionName = ctx.helper.string("divisionName", _divisionName);
const cityName = ctx.helper.city("cityName", _cityName);
const amount = ctx.helper.number("amount", _amount);
const job = ctx.helper.string("job", _job);
const office = getOffice(divisionName, cityName);
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
return netscriptDelay(1000, workerScript).then(function () {
return Promise.resolve(office.setEmployeeToJob(job, amount));
});
},
getOfficeSizeUpgradeCost: getOfficeSizeUpgradeCost:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>
(_divisionName: unknown, _cityName: unknown, _size: unknown): number => { (_divisionName: unknown, _cityName: unknown, _size: unknown): number => {
@ -724,10 +711,31 @@ export function NetscriptCorporation(player: IPlayer, workerScript: WorkerScript
const cityName = ctx.helper.city("cityName", _cityName); const cityName = ctx.helper.city("cityName", _cityName);
const employeeName = ctx.helper.string("employeeName", _employeeName); const employeeName = ctx.helper.string("employeeName", _employeeName);
const job = ctx.helper.string("job", _job); const job = ctx.helper.string("job", _job);
const employee = getEmployee(divisionName, cityName, employeeName);
return netscriptDelay(["Training", "Unassigned"].includes(employee.pos) ? 0 : 1000, workerScript).then(function () { if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
return Promise.resolve(AssignJob(employee, 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: hireEmployee:
(ctx: NetscriptContext) => (ctx: NetscriptContext) =>