diff --git a/markdown/bitburner.officeapi.md b/markdown/bitburner.officeapi.md index ce5bcbabd..2ad7a14da 100644 --- a/markdown/bitburner.officeapi.md +++ b/markdown/bitburner.officeapi.md @@ -30,7 +30,7 @@ Requires the Office API upgrade from your corporation. | [hireAdVert(divisionName)](./bitburner.officeapi.hireadvert.md) | Hire AdVert. | | [hireEmployee(divisionName, city, employeePosition)](./bitburner.officeapi.hireemployee.md) | Hire an employee. | | [research(divisionName, researchName)](./bitburner.officeapi.research.md) | Purchase a research. | -| [setAutoJobAssignment(divisionName, city, job, amount)](./bitburner.officeapi.setautojobassignment.md) | Set the job assignment for a job. | +| [setJobAssignment(divisionName, city, job, amount)](./bitburner.officeapi.setjobassignment.md) | Set the job assignment for a job. | | [throwParty(divisionName, city, costPerEmployee)](./bitburner.officeapi.throwparty.md) | Throw a party for your employees. | | [upgradeOfficeSize(divisionName, city, size)](./bitburner.officeapi.upgradeofficesize.md) | Upgrade office size. | diff --git a/markdown/bitburner.officeapi.setautojobassignment.md b/markdown/bitburner.officeapi.setjobassignment.md similarity index 54% rename from markdown/bitburner.officeapi.setautojobassignment.md rename to markdown/bitburner.officeapi.setjobassignment.md index 966287260..c24a07635 100644 --- a/markdown/bitburner.officeapi.setautojobassignment.md +++ b/markdown/bitburner.officeapi.setjobassignment.md @@ -1,15 +1,20 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [OfficeAPI](./bitburner.officeapi.md) > [setAutoJobAssignment](./bitburner.officeapi.setautojobassignment.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [OfficeAPI](./bitburner.officeapi.md) > [setJobAssignment](./bitburner.officeapi.setjobassignment.md) -## OfficeAPI.setAutoJobAssignment() method +## OfficeAPI.setJobAssignment() method Set the job assignment for a job. **Signature:** ```typescript -setAutoJobAssignment(divisionName: string, city: CityName, job: string, amount: number): boolean; +setJobAssignment( + divisionName: string, + city: CityName, + job: Exclude, + amount: number, + ): boolean; ``` ## Parameters @@ -18,7 +23,7 @@ setAutoJobAssignment(divisionName: string, city: CityName, job: string, amount: | --- | --- | --- | | divisionName | string | Name of the division | | city | [CityName](./bitburner.cityname.md) | Name of the city | -| job | string | Name of the job | +| job | Exclude<[CorpEmployeePosition](./bitburner.corpemployeeposition.md), "Unassigned"> | Name of the job. Passing "Unassigned" will cause this API to not do anything and just return false. | | amount | number | Number of employees to assign to that job | **Returns:** diff --git a/src/Documentation/doc/advanced/corporation/faq.md b/src/Documentation/doc/advanced/corporation/faq.md index b7849b377..4257f4111 100644 --- a/src/Documentation/doc/advanced/corporation/faq.md +++ b/src/Documentation/doc/advanced/corporation/faq.md @@ -127,7 +127,7 @@ Check the optimizer in this [section](./boost-material.md). API (`upgradeOfficeSize`) gives you granular control over office size. You cannot do that through UI. -#### Why does setAutoJobAssignment not take effect immediately? +#### Why does `setJobAssignment` not take effect immediately? It only takes effect in the next cycle's START state. diff --git a/src/Documentation/doc/advanced/corporation/office.md b/src/Documentation/doc/advanced/corporation/office.md index ebc435c17..739fab6a9 100644 --- a/src/Documentation/doc/advanced/corporation/office.md +++ b/src/Documentation/doc/advanced/corporation/office.md @@ -2,7 +2,7 @@ ## Basic information -Employee's stats are kept track as average value. There are 6 average values: `AvgEnergy`, `AvgMorale`, `AvgIntelligence`, `AvgCharisma`, `AvgCreativity`, `AvgEfficiency`. Every time you hire a new employee, these average values are recalculated, they are modified by a randomized number from 50 to 100: +Employee stats are kept track of as average values. There are 6 average values: `AvgEnergy`, `AvgMorale`, `AvgIntelligence`, `AvgCharisma`, `AvgCreativity`, `AvgEfficiency`. Every time you hire a new employee, these average values are recalculated. They are modified by a randomized number from 50 to 100: ```typescript this.avgMorale = @@ -11,19 +11,19 @@ this.avgMorale = Job assignment: -- Each office has 2 records: `employeeJobs` and `employeeNextJobs`. Data in `employeeJobs` (number of employees in each job) is used for calculations of other relevant data like `EmployeeProductionByJob`, `AvgEnergy`, `AvgMorale`, `TotalExperience`. When you call `setAutoJobAssignment`, its parameter is calculated and assigned to `employeeNextJobs`. In next cycle's START state, data in `employeeNextJobs` will be copied to `employeeJobs`. -- Behavior of `setAutoJobAssignment` may be confused at first glance. Let's say you call it like this: `ns.corporation.setAutoJobAssignment("Agriculture","Sector-12","Operations", 5)` +- Each office has 2 records: `employeeJobs` and `employeeNextJobs`. Data in `employeeJobs` (number of employees in each job) is used for calculations of other relevant data like `EmployeeProductionByJob`, `AvgEnergy`, `AvgMorale`, `TotalExperience`. When you call `setJobAssignment`, its parameter is calculated and assigned to `employeeNextJobs`. In the next cycle's START state, data in `employeeNextJobs` will be copied to `employeeJobs`. +- Behavior of `setJobAssignment` may be confused at first glance. Let's say you call it like this: `ns.corporation.setJobAssignment("Agriculture","Sector-12","Operations", 5)` - If you have 5 \"Operations\" employees, it does nothing. - If you have 7 \"Operations\" employees, it reduces number of \"Operations\" employees to 5, and set \"Unassigned\" employees to 2. - If you have 2 \"Operations\" employees, it checks if you have at least 3 \"Unassigned\" employees. If yes, it changes \"Operations\" employees to 5 and reduces \"Unassigned\" employees by 3. If not, it throws error. Essentially, it tries to move employees from \"Unassigned\" to \"Operations\". -- This means the proper way to use `setAutoJobAssignment` is: +- This means the proper way to use `setJobAssignment` is: - Use it to set all jobs to 0. - Use it to set all jobs to your requirements. Total experience is increased in these cases: -- Hire new employee. Each new employee increases total experience by `getRandomInt(50, 100)`. -- In START state. Gain per cycle: +- Hire a new employee. Each new employee increases total experience by `getRandomInt(50, 100)`. +- In the START state. Gain per cycle: $$TotalExperienceGain = 0.0015\ast(TotalEmployees - UnassignedEmployees + InternEmployees\ast 9)$$ @@ -65,7 +65,7 @@ $$MaxSize = 3\ast\log_{1.09}\left( MaxCost\ast\frac{0.09}{BasePrice} + {1.09}^{\ ## Energy and morale -They are calculated in START state. +They are calculated in the START state. They start dropping when your office's number of employees is greater than or equal to 9. The minimum value is 10. @@ -83,9 +83,9 @@ When throwing party, `PartyMult` is calculated. It's used in the calculation of $$PartyMult = 1 + \frac{PartyCostPerEmployee}{10^{7}}$$ -`PartyMult` is not affected by number of employees. Therefore, you can throw a "big party" (high `PartyCostPerEmployee`) when you have 1 employee at low total cost (due to having only 1 employee), then hire the rest of employees later. +`PartyMult` is not affected by the number of employees. Therefore, you can throw a "big party" (high `PartyCostPerEmployee`) when you have 1 employee at low total cost (due to having only 1 employee), then hire the rest of the employees later. -There is a flat randomized reduction of energy/morale per cycle. It's capped at 0.002 per cycle. This is tiny so it's not a problem. +There is a flat randomized reduction of energy/morale per cycle. It's capped at 0.002 per cycle. This is tiny, so it's not a problem. There is a flat increase of morale if `PartyMult` is greater than 1. `PartyMult` is based on `PartyCostPerEmployee`, so this increase is based on `PartyCostPerEmployee`. @@ -104,11 +104,11 @@ this.avgMorale = ((this.avgMorale - reduction * Math.random()) * perfMult + incr There are 3 ways to counter the drop of energy/morale: -- Buy tea and throw party. You should always use this option. Writing script to automate them is very easy. +- Buy tea and throw party. You should always use this option. Writing a script to automate them is very easy. - Assign Intern. Many people throw around the ratio 1/9 as the way to counter the drop of energy/morale. You can only use that ratio when your corporation/division works fine. If it does not, there is a penalty multiplier (0.001). In this case, you need to use 1/6. - Buy 2 research upgrades: AutoBrew and AutoPartyManager. They keep energy/morale at maximum value. However, you should never buy them. It's always better to spend your RP on other useful research upgrades or just stock up on RP. -`AvgEnergy` and `AvgMorale` are increased by a randomized amount when we hire new employee. +`AvgEnergy` and `AvgMorale` are increased by a randomized amount when we hire a new employee. ```typescript this.avgMorale = (this.avgMorale * this.numEmployees + getRandomInt(50, 100)) / (this.numEmployees + 1); @@ -146,7 +146,7 @@ $$x_{2} = 500000\ast\left( \sqrt{(a\ast k - 10)^{2} + 40\ast b} - a\ast k - 10 \ One big party is less cost-effective than multiple small parties. For example: throwing 1 big party for 70→100 morale costs more than throwing 3 small parties: 70→80, 80→90, 90→100. -Don't be a cheapskate when it comes to tea/party. Energy and morale are vital to efficient office. Check the next part for the formulas. +Don't be a cheapskate when it comes to tea/party. Energy and morale are vital to an efficient office. Check the next part for the formulas. - It's fine to spend 500e3 per employee when throwing party. You can spend more if you want. - Try to maintain maximum energy/morale at all times. Personally, I always buy tea / throw party when energy/morale decreases to 99.5 (109.5, if I bought the relevant research upgrades). @@ -154,7 +154,7 @@ Don't be a cheapskate when it comes to tea/party. Energy and morale are vital to ## Employee production by job -In each cycle's START state, all stats are used for calculating "production" values, these values are saved in `office.employeeProductionByJob`. These values can be used later for calculating: +In each cycle's START state, all stats are used for calculating "production" values. These values are saved in `office.employeeProductionByJob` and used later for calculating: - RP. - Material's quality. @@ -164,7 +164,7 @@ In each cycle's START state, all stats are used for calculating "production" val Formulas: -- Calculate multipliers of Intelligence, Charisma, Creativity, and Efficiency. They are the product of average value, upgrade benefit and research benefit. +- Calculate multipliers of Intelligence, Charisma, Creativity, and Efficiency. They are the product of average values, upgrade benefit and research benefit. - Production base: $$ProductionBase = AvgMorale\ast AvgEnergy\ast 10^{-4}$$ @@ -188,4 +188,4 @@ $$EmployeeProductionByJob = EmployeesJobCount\ast ProductionMultiplier\ast Produ 4 stats `AvgIntelligence`, `AvgCharisma`, `AvgCreativity`, `AvgEfficiency` are inaccessible through NS API. -We can calculate them by using the formulas from previous part and [Ceres Solver](./miscellany.md). In 5 jobs Operations, Engineer, Business, Management, Research & Development, we need at least 4 jobs having 1 employee at the minimum to use this solution. +We can calculate them by using the formulas from the previous part and [Ceres Solver](./miscellany.md). In 5 jobs (i.e., Operations, Engineer, Business, Management, and Research & Development), we need at least 4 jobs having 1 employee at the minimum to use this solution. diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index 0c003c0be..dd97e6126 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -484,7 +484,7 @@ const corporation = { getHireAdVertCount: RamCostConstants.CorporationInfo, getResearchCost: RamCostConstants.CorporationInfo, hasResearched: RamCostConstants.CorporationInfo, - setAutoJobAssignment: RamCostConstants.CorporationAction, + setJobAssignment: RamCostConstants.CorporationAction, getOfficeSizeUpgradeCost: RamCostConstants.CorporationInfo, } as const; diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 6630e3257..da0ace3c9 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -487,29 +487,37 @@ export function NetscriptCorporation(): InternalAPI { const office = getOffice(divisionName, cityName); return calculateOfficeSizeUpgradeCost(office.size, increase); }, - setAutoJobAssignment: (ctx) => (_divisionName, _cityName, _job, _amount) => { + setJobAssignment: (ctx) => (_divisionName, _cityName, _job, _amount) => { checkAccess(ctx, CorpUnlockName.OfficeAPI); const divisionName = helpers.string(ctx, "divisionName", _divisionName); const cityName = getEnumHelper("CityName").nsGetMember(ctx, _cityName); const amount = helpers.number(ctx, "amount", _amount); const job = getEnumHelper("CorpEmployeeJob").nsGetMember(ctx, _job, "job"); - if (job === CorpEmployeeJob.Unassigned) return false; - if (amount < 0 || !Number.isInteger(amount)) + if (job === CorpEmployeeJob.Unassigned) { + helpers.log( + ctx, + () => `This API will not do anything and just return false if you pass "Unassigned" to the "job" parameter.`, + ); + return false; + } + if (amount < 0 || !Number.isInteger(amount)) { throw helpers.errorMessage( ctx, `Invalid value for amount! Must be an integer and greater than or be 0". Amount:'${amount}'`, ); + } const office = getOffice(divisionName, cityName); const totalNewEmployees = amount - office.employeeNextJobs[job]; - if (office.employeeNextJobs[CorpEmployeeJob.Unassigned] < totalNewEmployees) + if (office.employeeNextJobs[CorpEmployeeJob.Unassigned] < totalNewEmployees) { throw helpers.errorMessage( ctx, `Unable to bring '${job} employees to ${amount}. Requires ${totalNewEmployees} unassigned employees`, ); + } return office.autoAssignJob(job, amount); }, hireEmployee: (ctx) => (_divisionName, _cityName, _position) => { @@ -797,7 +805,7 @@ export function NetscriptCorporation(): InternalAPI { setRemovedFunctions(corpFunctions, { assignJob: { version: "2.2.0", - replacement: "Removed due to employees no longer being objects. Use ns.corporation.setAutoJobAssignment instead.", + replacement: "Removed due to employees no longer being objects. Use ns.corporation.setJobAssignment instead.", replaceMsg: true, }, getEmployee: { @@ -813,6 +821,7 @@ export function NetscriptCorporation(): InternalAPI { getResearchNames: { version: "2.2.0", replacement: "corporation.getConstants().researchNames" }, getUnlockables: { version: "2.2.0", replacement: "corporation.getConstants().unlockNames" }, getUpgradeNames: { version: "2.2.0", replacement: "corporation.getConstants().upgradeNames" }, + setAutoJobAssignment: { version: "3.0.0", replacement: "corporation.setJobAssignment()" }, }); return corpFunctions; } diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index e78a683fc..dc1c75d5a 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -8906,11 +8906,16 @@ export interface OfficeAPI { * * @param divisionName - Name of the division * @param city - Name of the city - * @param job - Name of the job + * @param job - Name of the job. Passing "Unassigned" will cause this API to not do anything and just return false. * @param amount - Number of employees to assign to that job * @returns true if the employee count reached the target amount, false if not */ - setAutoJobAssignment(divisionName: string, city: CityName, job: string, amount: number): boolean; + setJobAssignment( + divisionName: string, + city: CityName, + job: Exclude, + amount: number, + ): boolean; /** * Get the cost to upgrade an office. diff --git a/src/utils/APIBreaks/3.0.0.ts b/src/utils/APIBreaks/3.0.0.ts index 6a3852b84..b0354ce5c 100644 --- a/src/utils/APIBreaks/3.0.0.ts +++ b/src/utils/APIBreaks/3.0.0.ts @@ -94,4 +94,19 @@ export const breakInfos300: APIBreakInfo[] = [ 'It has been automatically replaced with "ns.ui.setTailTitle()".\n\n', showPopUp: false, }, + { + brokenAPIs: [ + { + name: "ns.corporation.setAutoJobAssignment", + migration: { + searchValue: "setAutoJobAssignment", + replaceValue: "setJobAssignment", + }, + }, + ], + info: + "ns.corporation.setAutoJobAssignment() was removed.\n" + + 'It has been automatically replaced with "ns.corporation.setJobAssignment()".\n\n', + showPopUp: false, + }, ];