Compare commits

...

33 Commits

Author SHA1 Message Date
catloversg 01c63ea0c0 CORPORATION: Rework material production limit (#2683) 2026-04-28 15:50:40 -07:00
catloversg 8ad5ec075e MISC: Update description of "You and what army?" achievement (#2703) 2026-04-28 15:42:24 -07:00
catloversg 115b1b63ad API: Update RAM cost of nextUpdate and similar APIs (#2702) 2026-04-28 15:41:47 -07:00
catloversg 851ed2b9dc DOCUMENTATION: Fix api-extractor warnings (#2701) 2026-04-28 15:39:48 -07:00
catloversg 234ee7a923 API: Update error message of ns.singularity.joinFaction (#2700) 2026-04-28 15:38:43 -07:00
lucebac 9e85068cbb HACKNET: fix application of limits in cost functions (#2696) 2026-04-28 00:16:45 -07:00
The Gail ed6df3dfa7 MISC: Clarify what "backdoor" does in "help" command (#2694) 2026-04-28 00:14:39 -07:00
Michael Ficocelli 253b8b2672 DNET: Adjust charisma augmentation power (#2698) 2026-04-28 00:14:17 -07:00
catloversg 3146c50edc UI: Activate recovery mode on critical BN prestige bugs (#2699) 2026-04-28 00:11:23 -07:00
catloversg 4a91a71891 UI: Reload immediately after importing, deleting save data or killing all scripts (#2697) 2026-04-28 00:08:13 -07:00
catloversg 99afa3cd50 CORPORATION: Prevent duplicate processing of boost materials (#2695) 2026-04-28 00:06:12 -07:00
catloversg 750f79adf3 UI: Use "success" theme color for low infiltration difficulty instead of "primary" (#2693) 2026-04-27 23:55:35 -07:00
catloversg dbb20c1526 CODEBASE: Consistently check when to show intelligence skill (#2692) 2026-04-27 23:54:55 -07:00
catloversg 60fb303915 UI: Show effective amount of shared RAM when using UI (#2691) 2026-04-27 23:54:26 -07:00
catloversg 32fed9f142 BUGFIX: DarkscapeNavigator program is not granted on BN prestige when having SF15 (#2690) 2026-04-27 23:53:01 -07:00
catloversg 33ffc2107c DOCUMENTATION: Improve coding contract documentation (#2689) 2026-04-27 23:51:51 -07:00
catloversg 36e1adf2d2 API: Standardize "nextCompletion" promise in tasks (#2687) 2026-04-27 23:49:53 -07:00
David Walker ee3014b029 NETSCRIPT: Better error message for port serialization failure (#2688) 2026-04-24 13:55:39 -07:00
catloversg 112d317fd2 TOOLS: Ignore .DS_Store files when generating pages.ts (#2685) 2026-04-23 15:49:39 -07:00
catloversg 355f650367 CORPORATION: Remove max width of division list (#2686) 2026-04-23 15:42:33 -07:00
Michael Ficocelli a4b0f22a2e DNET: Update changelog (#2679) 2026-04-20 16:57:23 -07:00
catloversg 2aa5092d85 BLADEBURNER: Store BlackOp team count in save data (#2675) 2026-04-19 12:20:08 -07:00
catloversg a7409a01cc UI: Ensure intelligence override is a positive integer (#2673) 2026-04-19 12:09:11 -07:00
catloversg a99109d9c7 BUGFIX: Follow-up to #2660 (#2666) 2026-04-19 12:06:54 -07:00
catloversg 95af138c39 BLADEBURNER: Restrict team count of Ops/BlackOps to total team size (#2672) 2026-04-17 14:32:22 -07:00
Mathekatze f5bbc26495 MISC: Clear recent scripts when installing augmentations (#2670) 2026-04-17 14:20:07 -07:00
catloversg f8ec7f4294 CODEBASE: Fix passive event listener warning (#2671) 2026-04-17 14:09:12 -07:00
catloversg c06c6590c9 BUGFIX: calculateExp throws errors in edge cases (#2667) 2026-04-17 00:57:50 -07:00
catloversg 45bce6e45e MISC: Reduce achievements check interval (#2650) 2026-04-15 18:47:29 -07:00
catloversg c21d1f44b2 UI: Add button to open Faction page from Gang UI (#2655) 2026-04-14 15:53:40 -07:00
catloversg 956e00f789 BUGFIX: Intelligence data is incorrectly migrated when Intelligence is not unlocked (#2660) 2026-04-14 15:20:01 -07:00
catloversg c5536d252b MISC: Update "Last updated" date in changelog (#2658) 2026-04-13 13:10:59 +07:00
catloversg a99ca64455 MISC: Update changelog (#2657) 2026-04-13 11:32:39 +07:00
136 changed files with 3866 additions and 1556 deletions
+8 -4
View File
@@ -9,7 +9,7 @@ Base interface of all tasks.
**Signature:** **Signature:**
```typescript ```typescript
export interface BaseTask interface BaseTask
``` ```
## Properties ## Properties
@@ -37,7 +37,7 @@ Description
</th></tr></thead> </th></tr></thead>
<tbody><tr><td> <tbody><tr><td>
[cyclesWorked](./bitburner.basetask.cyclesworked.md) [nextCompletion](./bitburner.basetask.nextcompletion.md)
</td><td> </td><td>
@@ -45,12 +45,16 @@ Description
</td><td> </td><td>
number Promise&lt;void&gt;
</td><td> </td><td>
The number of game engine cycles has passed since this task started. 1 engine cycle = 200ms. This promise resolves when the task completes or is canceled.
Tasks that do not track progress, such as studying or working for a company, are non-completable, i.e., they continue indefinitely until canceled. The `nextCompletion` promise of these tasks resolves only when they are canceled.
Among completable tasks, some are repeatable, i.e., they automatically restart after completion. The `nextCompletion` promise of these tasks resolves on the next completion or when they are canceled.
</td></tr> </td></tr>
@@ -0,0 +1,17 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [BaseTask](./bitburner.basetask.md) &gt; [nextCompletion](./bitburner.basetask.nextcompletion.md)
## BaseTask.nextCompletion property
This promise resolves when the task completes or is canceled.
Tasks that do not track progress, such as studying or working for a company, are non-completable, i.e., they continue indefinitely until canceled. The `nextCompletion` promise of these tasks resolves only when they are canceled.
Among completable tasks, some are repeatable, i.e., they automatically restart after completion. The `nextCompletion` promise of these tasks resolves on the next completion or when they are canceled.
**Signature:**
```typescript
nextCompletion: Promise<void>;
```
+1 -1
View File
@@ -12,7 +12,7 @@ Default value:
- All boolean options: false - All boolean options: false
If you specify intelligenceOverride, it must be a non-negative integer. If you specify intelligenceOverride, it must be a positive integer.
**Signature:** **Signature:**
+1 -1
View File
@@ -19,7 +19,7 @@ Promise that resolves to the number of milliseconds of Bladeburner time that wer
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
The amount of real time spent asleep between updates can vary due to "bonus time" (usually 1 second). The amount of real time spent asleep between updates can vary due to "bonus time" (usually 1 second).
+2 -2
View File
@@ -9,9 +9,9 @@ Company Work
**Signature:** **Signature:**
```typescript ```typescript
export interface CompanyWorkTask extends BaseTask interface CompanyWorkTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
+1 -1
View File
@@ -19,7 +19,7 @@ Promise that resolves to the name of the state that was just processed.
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
The amount of real time spent asleep between updates can vary due to "bonus time" (usually 200 milliseconds - 2 seconds). The amount of real time spent asleep between updates can vary due to "bonus time" (usually 200 milliseconds - 2 seconds).
+2 -2
View File
@@ -9,9 +9,9 @@ Create Program
**Signature:** **Signature:**
```typescript ```typescript
export interface CreateProgramWorkTask extends BaseTask interface CreateProgramWorkTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
+2 -2
View File
@@ -9,9 +9,9 @@ Crime
**Signature:** **Signature:**
```typescript ```typescript
export interface CrimeTask extends BaseTask interface CrimeTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
+1 -1
View File
@@ -29,5 +29,5 @@ Promise&lt;void&gt;
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
+2 -2
View File
@@ -9,9 +9,9 @@ Faction Work
**Signature:** **Signature:**
```typescript ```typescript
export interface FactionWorkTask extends BaseTask interface FactionWorkTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
+1 -1
View File
@@ -19,7 +19,7 @@ Promise that resolves to the number of milliseconds of Gang time that were proce
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
The amount of real time spent asleep between updates can vary due to "bonus time". The amount of real time spent asleep between updates can vary due to "bonus time".
@@ -19,5 +19,5 @@ A promise that resolves when the current grafting finishes or is canceled. If th
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
@@ -1,13 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [GraftingTask](./bitburner.graftingtask.md) &gt; [completion](./bitburner.graftingtask.completion.md)
## GraftingTask.completion property
This promise resolves when the task is complete.
**Signature:**
```typescript
completion: Promise<void>;
```
+2 -21
View File
@@ -9,9 +9,9 @@ Grafting Work
**Signature:** **Signature:**
```typescript ```typescript
export interface GraftingTask extends BaseTask interface GraftingTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
@@ -56,25 +56,6 @@ string
</td><td> </td><td>
</td></tr>
<tr><td>
[completion](./bitburner.graftingtask.completion.md)
</td><td>
</td><td>
Promise&lt;void&gt;
</td><td>
This promise resolves when the task is complete.
</td></tr> </td></tr>
<tr><td> <tr><td>
+1 -1
View File
@@ -134,7 +134,7 @@ Calculate hack time.
</td><td> </td><td>
Calculate the security decrease from a weaken operation. Unlike other hacking formulas, weaken effect depends only on thread count and core count, not on server or player properties. The core bonus formula is . Calculate the security decrease from a weaken operation. Unlike other hacking formulas, weaken effect depends only on thread count and core count, not on server or player properties. The core bonus formula is `1 + (cores - 1) / 16}`<!-- -->.
</td></tr> </td></tr>
@@ -4,7 +4,7 @@
## HackingFormulas.weakenEffect() method ## HackingFormulas.weakenEffect() method
Calculate the security decrease from a weaken operation. Unlike other hacking formulas, weaken effect depends only on thread count and core count, not on server or player properties. The core bonus formula is . Calculate the security decrease from a weaken operation. Unlike other hacking formulas, weaken effect depends only on thread count and core count, not on server or player properties. The core bonus formula is `1 + (cores - 1) / 16}`<!-- -->.
**Signature:** **Signature:**
+102 -91
View File
@@ -123,7 +123,7 @@ Default value:
- All boolean options: false - All boolean options: false
If you specify intelligenceOverride, it must be a non-negative integer. If you specify intelligenceOverride, it must be a positive integer.
</td></tr> </td></tr>
@@ -1111,6 +1111,17 @@ Player must have killed at least this many people.
</td></tr>
<tr><td>
[PlayerBaseTask](./bitburner.playerbasetask.md)
</td><td>
Base interface of all player tasks.
</td></tr> </td></tr>
<tr><td> <tr><td>
@@ -1272,6 +1283,66 @@ Skills formulas
Sleeve API Sleeve API
</td></tr>
<tr><td>
[SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveClassTask](./bitburner.sleeveclasstask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveCompanyTask](./bitburner.sleevecompanytask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveCrimeTask](./bitburner.sleevecrimetask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveFactionTask](./bitburner.sleevefactiontask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md)
</td><td>
</td></tr> </td></tr>
<tr><td> <tr><td>
@@ -1282,6 +1353,36 @@ Sleeve API
</td></tr>
<tr><td>
[SleeveRecoveryTask](./bitburner.sleeverecoverytask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveSupportTask](./bitburner.sleevesupporttask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveSynchroTask](./bitburner.sleevesynchrotask.md)
</td><td>
</td></tr> </td></tr>
<tr><td> <tr><td>
@@ -2206,96 +2307,6 @@ Use React.createElement to make the ReactElement type, see [creating an element
</td></tr>
<tr><td>
[SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveClassTask](./bitburner.sleeveclasstask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveCompanyTask](./bitburner.sleevecompanytask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveCrimeTask](./bitburner.sleevecrimetask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveFactionTask](./bitburner.sleevefactiontask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveRecoveryTask](./bitburner.sleeverecoverytask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveSupportTask](./bitburner.sleevesupporttask.md)
</td><td>
</td></tr>
<tr><td>
[SleeveSynchroTask](./bitburner.sleevesynchrotask.md)
</td><td>
</td></tr> </td></tr>
<tr><td> <tr><td>
@@ -1,8 +1,8 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. --> <!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [BaseTask](./bitburner.basetask.md) &gt; [cyclesWorked](./bitburner.basetask.cyclesworked.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [PlayerBaseTask](./bitburner.playerbasetask.md) &gt; [cyclesWorked](./bitburner.playerbasetask.cyclesworked.md)
## BaseTask.cyclesWorked property ## PlayerBaseTask.cyclesWorked property
The number of game engine cycles has passed since this task started. 1 engine cycle = 200ms. The number of game engine cycles has passed since this task started. 1 engine cycle = 200ms.
+59
View File
@@ -0,0 +1,59 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [PlayerBaseTask](./bitburner.playerbasetask.md)
## PlayerBaseTask interface
Base interface of all player tasks.
**Signature:**
```typescript
interface PlayerBaseTask extends BaseTask
```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[cyclesWorked](./bitburner.playerbasetask.cyclesworked.md)
</td><td>
</td><td>
number
</td><td>
The number of game engine cycles has passed since this task started. 1 engine cycle = 200ms.
</td></tr>
</tbody></table>
@@ -52,7 +52,7 @@ Name of faction to join.
boolean boolean
True if player joined the faction, and false otherwise. True if the player successfully accepts an invitation, and false otherwise.
## Remarks ## Remarks
@@ -60,3 +60,5 @@ RAM cost: 3 GB \* 16/4/1
This function will automatically accept an invitation from a faction and join it. This function will automatically accept an invitation from a faction and join it.
Note that this function returns false if you are already a member of the specified faction.
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [actionName](./bitburner.sleevebladeburnertask.actionname.md)
## SleeveBladeburnerTask.actionName property
**Signature:**
```typescript
actionName: string;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [actionType](./bitburner.sleevebladeburnertask.actiontype.md)
## SleeveBladeburnerTask.actionType property
**Signature:**
```typescript
actionType: "General" | "Contracts";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [cyclesNeeded](./bitburner.sleevebladeburnertask.cyclesneeded.md)
## SleeveBladeburnerTask.cyclesNeeded property
**Signature:**
```typescript
cyclesNeeded: number;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [cyclesWorked](./bitburner.sleevebladeburnertask.cyclesworked.md)
## SleeveBladeburnerTask.cyclesWorked property
**Signature:**
```typescript
cyclesWorked: number;
```
+131 -10
View File
@@ -2,19 +2,140 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md)
## SleeveBladeburnerTask type ## SleeveBladeburnerTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveBladeburnerTask = { interface SleeveBladeburnerTask extends BaseTask
type: "BLADEBURNER";
actionType: "General" | "Contracts";
actionName: string;
cyclesWorked: number;
cyclesNeeded: number;
nextCompletion: Promise<void>;
tasksCompleted: number;
};
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[actionName](./bitburner.sleevebladeburnertask.actionname.md)
</td><td>
</td><td>
string
</td><td>
</td></tr>
<tr><td>
[actionType](./bitburner.sleevebladeburnertask.actiontype.md)
</td><td>
</td><td>
"General" \| "Contracts"
</td><td>
</td></tr>
<tr><td>
[cyclesNeeded](./bitburner.sleevebladeburnertask.cyclesneeded.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[cyclesWorked](./bitburner.sleevebladeburnertask.cyclesworked.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[tasksCompleted](./bitburner.sleevebladeburnertask.taskscompleted.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleevebladeburnertask.type.md)
</td><td>
</td><td>
"BLADEBURNER"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [tasksCompleted](./bitburner.sleevebladeburnertask.taskscompleted.md)
## SleeveBladeburnerTask.tasksCompleted property
**Signature:**
```typescript
tasksCompleted: number;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveBladeburnerTask](./bitburner.sleevebladeburnertask.md) &gt; [type](./bitburner.sleevebladeburnertask.type.md)
## SleeveBladeburnerTask.type property
**Signature:**
```typescript
type: "BLADEBURNER";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveClassTask](./bitburner.sleeveclasstask.md) &gt; [classType](./bitburner.sleeveclasstask.classtype.md)
## SleeveClassTask.classType property
**Signature:**
```typescript
classType: UniversityClassType | GymType;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveClassTask](./bitburner.sleeveclasstask.md) &gt; [location](./bitburner.sleeveclasstask.location.md)
## SleeveClassTask.location property
**Signature:**
```typescript
location: LocationName;
```
+79 -7
View File
@@ -2,17 +2,89 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveClassTask](./bitburner.sleeveclasstask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveClassTask](./bitburner.sleeveclasstask.md)
## SleeveClassTask type ## SleeveClassTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveClassTask = { interface SleeveClassTask extends BaseTask
type: "CLASS";
classType: UniversityClassType | GymType;
location: LocationName;
};
``` ```
**References:** [UniversityClassType](./bitburner.universityclasstype.md)<!-- -->, [GymType](./bitburner.gymtype.md)<!-- -->, [LocationName](./bitburner.locationname.md) **Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[classType](./bitburner.sleeveclasstask.classtype.md)
</td><td>
</td><td>
[UniversityClassType](./bitburner.universityclasstype.md) \| [GymType](./bitburner.gymtype.md)
</td><td>
</td></tr>
<tr><td>
[location](./bitburner.sleeveclasstask.location.md)
</td><td>
</td><td>
[LocationName](./bitburner.locationname.md)
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleeveclasstask.type.md)
</td><td>
</td><td>
"CLASS"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveClassTask](./bitburner.sleeveclasstask.md) &gt; [type](./bitburner.sleeveclasstask.type.md)
## SleeveClassTask.type property
**Signature:**
```typescript
type: "CLASS";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCompanyTask](./bitburner.sleevecompanytask.md) &gt; [companyName](./bitburner.sleevecompanytask.companyname.md)
## SleeveCompanyTask.companyName property
**Signature:**
```typescript
companyName: CompanyName;
```
+62 -3
View File
@@ -2,13 +2,72 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCompanyTask](./bitburner.sleevecompanytask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCompanyTask](./bitburner.sleevecompanytask.md)
## SleeveCompanyTask type ## SleeveCompanyTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveCompanyTask = { type: "COMPANY"; companyName: CompanyName }; interface SleeveCompanyTask extends BaseTask
``` ```
**References:** [CompanyName](./bitburner.companyname.md) **Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[companyName](./bitburner.sleevecompanytask.companyname.md)
</td><td>
</td><td>
[CompanyName](./bitburner.companyname.md)
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleevecompanytask.type.md)
</td><td>
</td><td>
"COMPANY"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCompanyTask](./bitburner.sleevecompanytask.md) &gt; [type](./bitburner.sleevecompanytask.type.md)
## SleeveCompanyTask.type property
**Signature:**
```typescript
type: "COMPANY";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) &gt; [crimeType](./bitburner.sleevecrimetask.crimetype.md)
## SleeveCrimeTask.crimeType property
**Signature:**
```typescript
crimeType: CrimeType;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) &gt; [cyclesNeeded](./bitburner.sleevecrimetask.cyclesneeded.md)
## SleeveCrimeTask.cyclesNeeded property
**Signature:**
```typescript
cyclesNeeded: number;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) &gt; [cyclesWorked](./bitburner.sleevecrimetask.cyclesworked.md)
## SleeveCrimeTask.cyclesWorked property
**Signature:**
```typescript
cyclesWorked: number;
```
+113 -9
View File
@@ -2,19 +2,123 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md)
## SleeveCrimeTask type ## SleeveCrimeTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveCrimeTask = { interface SleeveCrimeTask extends BaseTask
type: "CRIME";
crimeType: CrimeType;
cyclesWorked: number;
cyclesNeeded: number;
tasksCompleted: number;
};
``` ```
**References:** [CrimeType](./bitburner.crimetype.md) **Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[crimeType](./bitburner.sleevecrimetask.crimetype.md)
</td><td>
</td><td>
[CrimeType](./bitburner.crimetype.md)
</td><td>
</td></tr>
<tr><td>
[cyclesNeeded](./bitburner.sleevecrimetask.cyclesneeded.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[cyclesWorked](./bitburner.sleevecrimetask.cyclesworked.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[tasksCompleted](./bitburner.sleevecrimetask.taskscompleted.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleevecrimetask.type.md)
</td><td>
</td><td>
"CRIME"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) &gt; [tasksCompleted](./bitburner.sleevecrimetask.taskscompleted.md)
## SleeveCrimeTask.tasksCompleted property
**Signature:**
```typescript
tasksCompleted: number;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveCrimeTask](./bitburner.sleevecrimetask.md) &gt; [type](./bitburner.sleevecrimetask.type.md)
## SleeveCrimeTask.type property
**Signature:**
```typescript
type: "CRIME";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveFactionTask](./bitburner.sleevefactiontask.md) &gt; [factionName](./bitburner.sleevefactiontask.factionname.md)
## SleeveFactionTask.factionName property
**Signature:**
```typescript
factionName: FactionName;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveFactionTask](./bitburner.sleevefactiontask.md) &gt; [factionWorkType](./bitburner.sleevefactiontask.factionworktype.md)
## SleeveFactionTask.factionWorkType property
**Signature:**
```typescript
factionWorkType: FactionWorkType;
```
+79 -7
View File
@@ -2,17 +2,89 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveFactionTask](./bitburner.sleevefactiontask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveFactionTask](./bitburner.sleevefactiontask.md)
## SleeveFactionTask type ## SleeveFactionTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveFactionTask = { interface SleeveFactionTask extends BaseTask
type: "FACTION";
factionWorkType: FactionWorkType;
factionName: FactionName;
};
``` ```
**References:** [FactionWorkType](./bitburner.factionworktype.md)<!-- -->, [FactionName](./bitburner.factionname.md) **Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[factionName](./bitburner.sleevefactiontask.factionname.md)
</td><td>
</td><td>
[FactionName](./bitburner.factionname.md)
</td><td>
</td></tr>
<tr><td>
[factionWorkType](./bitburner.sleevefactiontask.factionworktype.md)
</td><td>
</td><td>
[FactionWorkType](./bitburner.factionworktype.md)
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleevefactiontask.type.md)
</td><td>
</td><td>
"FACTION"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveFactionTask](./bitburner.sleevefactiontask.md) &gt; [type](./bitburner.sleevefactiontask.type.md)
## SleeveFactionTask.type property
**Signature:**
```typescript
type: "FACTION";
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md) &gt; [cyclesNeeded](./bitburner.sleeveinfiltratetask.cyclesneeded.md)
## SleeveInfiltrateTask.cyclesNeeded property
**Signature:**
```typescript
cyclesNeeded: number;
```
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md) &gt; [cyclesWorked](./bitburner.sleeveinfiltratetask.cyclesworked.md)
## SleeveInfiltrateTask.cyclesWorked property
**Signature:**
```typescript
cyclesWorked: number;
```
+80 -7
View File
@@ -2,16 +2,89 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md)
## SleeveInfiltrateTask type ## SleeveInfiltrateTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveInfiltrateTask = { interface SleeveInfiltrateTask extends BaseTask
type: "INFILTRATE";
cyclesWorked: number;
cyclesNeeded: number;
nextCompletion: Promise<void>;
};
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[cyclesNeeded](./bitburner.sleeveinfiltratetask.cyclesneeded.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[cyclesWorked](./bitburner.sleeveinfiltratetask.cyclesworked.md)
</td><td>
</td><td>
number
</td><td>
</td></tr>
<tr><td>
[type](./bitburner.sleeveinfiltratetask.type.md)
</td><td>
</td><td>
"INFILTRATE"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveInfiltrateTask](./bitburner.sleeveinfiltratetask.md) &gt; [type](./bitburner.sleeveinfiltratetask.type.md)
## SleeveInfiltrateTask.type property
**Signature:**
```typescript
type: "INFILTRATE";
```
+46 -2
View File
@@ -2,11 +2,55 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveRecoveryTask](./bitburner.sleeverecoverytask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveRecoveryTask](./bitburner.sleeverecoverytask.md)
## SleeveRecoveryTask type ## SleeveRecoveryTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveRecoveryTask = { type: "RECOVERY" }; interface SleeveRecoveryTask extends BaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[type](./bitburner.sleeverecoverytask.type.md)
</td><td>
</td><td>
"RECOVERY"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveRecoveryTask](./bitburner.sleeverecoverytask.md) &gt; [type](./bitburner.sleeverecoverytask.type.md)
## SleeveRecoveryTask.type property
**Signature:**
```typescript
type: "RECOVERY";
```
+46 -2
View File
@@ -2,11 +2,55 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSupportTask](./bitburner.sleevesupporttask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSupportTask](./bitburner.sleevesupporttask.md)
## SleeveSupportTask type ## SleeveSupportTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveSupportTask = { type: "SUPPORT" }; interface SleeveSupportTask extends BaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[type](./bitburner.sleevesupporttask.type.md)
</td><td>
</td><td>
"SUPPORT"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSupportTask](./bitburner.sleevesupporttask.md) &gt; [type](./bitburner.sleevesupporttask.type.md)
## SleeveSupportTask.type property
**Signature:**
```typescript
type: "SUPPORT";
```
+46 -2
View File
@@ -2,11 +2,55 @@
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSynchroTask](./bitburner.sleevesynchrotask.md) [Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSynchroTask](./bitburner.sleevesynchrotask.md)
## SleeveSynchroTask type ## SleeveSynchroTask interface
**Signature:** **Signature:**
```typescript ```typescript
type SleeveSynchroTask = { type: "SYNCHRO" }; interface SleeveSynchroTask extends BaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md)
## Properties
<table><thead><tr><th>
Property
</th><th>
Modifiers
</th><th>
Type
</th><th>
Description
</th></tr></thead>
<tbody><tr><td>
[type](./bitburner.sleevesynchrotask.type.md)
</td><td>
</td><td>
"SYNCHRO"
</td><td>
</td></tr>
</tbody></table>
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [SleeveSynchroTask](./bitburner.sleevesynchrotask.md) &gt; [type](./bitburner.sleevesynchrotask.type.md)
## SleeveSynchroTask.type property
**Signature:**
```typescript
type: "SYNCHRO";
```
+1 -1
View File
@@ -19,7 +19,7 @@ Promise that resolves to the number of milliseconds of Stock Market time that we
## Remarks ## Remarks
RAM cost: 1 GB RAM cost: 0 GB
The amount of real time spent asleep between updates can vary due to "bonus time" (usually 4 seconds - 6 seconds). The amount of real time spent asleep between updates can vary due to "bonus time" (usually 4 seconds - 6 seconds).
+2 -2
View File
@@ -9,9 +9,9 @@ Study
**Signature:** **Signature:**
```typescript ```typescript
export interface StudyTask extends BaseTask interface StudyTask extends PlayerBaseTask
``` ```
**Extends:** [BaseTask](./bitburner.basetask.md) **Extends:** [PlayerBaseTask](./bitburner.playerbasetask.md)
## Remarks ## Remarks
@@ -104,3 +104,11 @@ void
RAM cost: 20 GB RAM cost: 20 GB
This limit applies only to output; it does not affect input consumption.
For example, in Agriculture, assume the division's raw production is 1000. You need to consume 500 Water and 200 Chemicals to produce 1000 Plants and 1000 Food. If you set the limits for Plants and Food to 200 and 100 respectively, you will still consume 500 Water and 200 Chemicals, but only produce 200 Plants and 100 Food.
With industries that produce both materials and products, the material production limits do not affect product production.
You can set a limit on any material, but only limits on output materials are enforced. Limits on other materials are stored but ignored during production calculations. For example, in Agriculture, only limits on Plants and Food are enforced.
+1 -1
View File
@@ -384,7 +384,7 @@
"SLEEVE_8": { "SLEEVE_8": {
"ID": "SLEEVE_8", "ID": "SLEEVE_8",
"Name": "You and what army?", "Name": "You and what army?",
"Description": "Purchase all duplicate sleeves from The Covenant." "Description": "Acquire all 8 sleeves."
}, },
"INDECISIVE": { "INDECISIVE": {
"ID": "INDECISIVE", "ID": "INDECISIVE",
+1 -10
View File
@@ -4,19 +4,10 @@ import { AchievementList } from "./AchievementList";
import { achievements } from "./Achievements"; import { achievements } from "./Achievements";
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { Player } from "@player"; import { Player } from "@player";
import { makeStyles } from "tss-react/mui";
const useStyles = makeStyles()({
root: {
width: 50,
userSelect: "none",
},
});
export function AchievementsRoot(): JSX.Element { export function AchievementsRoot(): JSX.Element {
const { classes } = useStyles();
return ( return (
<div className={classes.root} style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography variant="h4">Achievements</Typography> <Typography variant="h4">Achievements</Typography>
<Box mx={2}> <Box mx={2}>
<Typography> <Typography>
+15 -19
View File
@@ -37,7 +37,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"triggers feelings of admiration, approval, and respect in others.", "triggers feelings of admiration, approval, and respect in others.",
company_rep: 1.2, company_rep: 1.2,
faction_rep: 1.2, faction_rep: 1.2,
charisma: 1.2, charisma: 1.1,
factions: [ factions: [
FactionName.Silhouette, FactionName.Silhouette,
FactionName.FourSigma, FactionName.FourSigma,
@@ -517,7 +517,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"millions of nanobots capable of projecting high-density muon beams, " + "millions of nanobots capable of projecting high-density muon beams, " +
"creating an energy barrier around the user.", "creating an energy barrier around the user.",
defense: 1.4, defense: 1.4,
charisma: 1.1, charisma: 1.05,
factions: [FactionName.Volhaven], factions: [FactionName.Volhaven],
}, },
// === E === // // === E === //
@@ -528,7 +528,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"A neural implant that enhances the user's ability to resonate with others. " + "A neural implant that enhances the user's ability to resonate with others. " +
"It is capable of analyzing and interpreting the emotions of those nearby, allowing " + "It is capable of analyzing and interpreting the emotions of those nearby, allowing " +
"the user to better understand and influence them.", "the user to better understand and influence them.",
charisma: 1.1, charisma: 1.05,
crime_success: 1.1, crime_success: 1.1,
work_money: 1.2, work_money: 1.2,
factions: [FactionName.SpeakersForTheDead], factions: [FactionName.SpeakersForTheDead],
@@ -772,7 +772,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"An aural implant that enhances the user's ability to communicate and persuade others. " + "An aural implant that enhances the user's ability to communicate and persuade others. " +
"The implant uses a predictive model that lets the user say precisely what their audience " + "The implant uses a predictive model that lets the user say precisely what their audience " +
"wants to hear. This implant is commonly used by many high-level executives and government officials.", "wants to hear. This implant is commonly used by many high-level executives and government officials.",
charisma: 1.2, charisma: 1.1,
charisma_exp: 1.3, charisma_exp: 1.3,
factions: [FactionName.SpeakersForTheDead], factions: [FactionName.SpeakersForTheDead],
}, },
@@ -945,7 +945,6 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"Even though it contains no weapons, the advanced tungsten titanium " + "Even though it contains no weapons, the advanced tungsten titanium " +
"alloy increases the user's strength to unbelievable levels.", "alloy increases the user's strength to unbelievable levels.",
strength: 2.8, strength: 2.8,
charisma: 1.4,
factions: [FactionName.NWO], factions: [FactionName.NWO],
}, },
[AugmentationName.HyperionV1]: { [AugmentationName.HyperionV1]: {
@@ -985,7 +984,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
dexterity: 1.4, dexterity: 1.4,
hacking_speed: 1.03, hacking_speed: 1.03,
hacking_money: 1.1, hacking_money: 1.1,
charisma: 1.05, charisma: 1.03,
factions: [FactionName.BladeIndustries, FactionName.KuaiGongInternational], factions: [FactionName.BladeIndustries, FactionName.KuaiGongInternational],
}, },
// === I === // // === I === //
@@ -1033,7 +1032,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"cells, when powered, have a negative refractive index. As a result, they bend light " + "cells, when powered, have a negative refractive index. As a result, they bend light " +
"around the skin, making the user much harder to see with the naked eye.", "around the skin, making the user much harder to see with the naked eye.",
agility: 1.05, agility: 1.05,
charisma: 1.05, charisma: 1.03,
crime_money: 1.1, crime_money: 1.1,
factions: [FactionName.SlumSnakes, FactionName.Tetrads], factions: [FactionName.SlumSnakes, FactionName.Tetrads],
}, },
@@ -1057,7 +1056,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
repCost: 1.5e4, repCost: 1.5e4,
moneyCost: 2.5e8, moneyCost: 2.5e8,
info: "A cranial implant that increases the attractive force of the wearer. (Even its inventor isn't quite sure how it works).", info: "A cranial implant that increases the attractive force of the wearer. (Even its inventor isn't quite sure how it works).",
charisma: 1.1, charisma: 1.05,
company_rep: 1.1, company_rep: 1.1,
factions: [FactionName.TheBlackHand, FactionName.TheDarkArmy], factions: [FactionName.TheBlackHand, FactionName.TheDarkArmy],
}, },
@@ -1081,7 +1080,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"which improves its regenerative and extracellular homeostasis abilities.", "which improves its regenerative and extracellular homeostasis abilities.",
strength: 1.2, strength: 1.2,
defense: 1.2, defense: 1.2,
charisma: 1.1, charisma: 1.05,
factions: [ factions: [
FactionName.TheDarkArmy, FactionName.TheDarkArmy,
FactionName.TheSyndicate, FactionName.TheSyndicate,
@@ -1134,7 +1133,6 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
hacking_speed: 1.02, hacking_speed: 1.02,
hacking_chance: 1.1, hacking_chance: 1.1,
hacking_exp: 1.12, hacking_exp: 1.12,
charisma: 1.05,
factions: [ factions: [
FactionName.TheBlackHand, FactionName.TheBlackHand,
FactionName.Chongqing, FactionName.Chongqing,
@@ -1294,7 +1292,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"the bloodstream to improve memory, increase focus, and provide other " + "the bloodstream to improve memory, increase focus, and provide other " +
"cognitive enhancements.", "cognitive enhancements.",
company_rep: 1.2, company_rep: 1.2,
charisma: 1.05, charisma: 1.03,
factions: [ factions: [
FactionName.TianDiHui, FactionName.TianDiHui,
FactionName.Volhaven, FactionName.Volhaven,
@@ -1432,7 +1430,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
strength: 1.4, strength: 1.4,
defense: 1.4, defense: 1.4,
agility: 1.4, agility: 1.4,
charisma: 1.4, charisma: 1.2,
factions: [FactionName.KuaiGongInternational], factions: [FactionName.KuaiGongInternational],
}, },
[AugmentationName.PowerRecirculator]: { [AugmentationName.PowerRecirculator]: {
@@ -1462,7 +1460,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
info: info:
"A cutting-edge knowledgebase entirely built off of nanotech rod-logic, training the user on social engineering. " + "A cutting-edge knowledgebase entirely built off of nanotech rod-logic, training the user on social engineering. " +
"Thought to be stolen technology, its existance has been a secret until recently.", "Thought to be stolen technology, its existance has been a secret until recently.",
charisma: 1.2, charisma: 1.1,
charisma_exp: 1.4, charisma_exp: 1.4,
factions: [FactionName.TheDarkArmy, FactionName.TheSyndicate], factions: [FactionName.TheDarkArmy, FactionName.TheSyndicate],
}, },
@@ -1500,7 +1498,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
info: info:
"Makes the wearer a better leader and mentor by greatly increasing their awareness of social dynamics. " + "Makes the wearer a better leader and mentor by greatly increasing their awareness of social dynamics. " +
"Not actually a standard implant, but rather a series of training courses and seminars, led by a famous speaker named Denis.", "Not actually a standard implant, but rather a series of training courses and seminars, led by a famous speaker named Denis.",
charisma: 1.3, charisma: 1.1,
company_rep: 1.3, company_rep: 1.3,
factions: [FactionName.MegaCorp, FactionName.ECorp, FactionName.OmniTekIncorporated], factions: [FactionName.MegaCorp, FactionName.ECorp, FactionName.OmniTekIncorporated],
}, },
@@ -1528,7 +1526,6 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"criminal organizations and allows the user to project and control holographic " + "criminal organizations and allows the user to project and control holographic " +
"simulacrums within a large radius. These simulacrums are commonly used for " + "simulacrums within a large radius. These simulacrums are commonly used for " +
"espionage and surveillance work.", "espionage and surveillance work.",
charisma: 1.15,
company_rep: 1.15, company_rep: 1.15,
faction_rep: 1.15, faction_rep: 1.15,
factions: [FactionName.TheSyndicate, FactionName.TheDarkArmy, FactionName.SpeakersForTheDead], factions: [FactionName.TheSyndicate, FactionName.TheDarkArmy, FactionName.SpeakersForTheDead],
@@ -1743,7 +1740,6 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"Scientists have named these artificially enhanced units 'synfibrils'.", "Scientists have named these artificially enhanced units 'synfibrils'.",
strength: 1.3, strength: 1.3,
defense: 1.3, defense: 1.3,
charisma: 1.15,
factions: [ factions: [
FactionName.KuaiGongInternational, FactionName.KuaiGongInternational,
FactionName.FulcrumSecretTechnologies, FactionName.FulcrumSecretTechnologies,
@@ -1763,7 +1759,7 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
"more efficiently than an organic heart.", "more efficiently than an organic heart.",
agility: 1.5, agility: 1.5,
strength: 1.5, strength: 1.5,
charisma: 1.5, charisma: 1.3,
factions: [ factions: [
FactionName.KuaiGongInternational, FactionName.KuaiGongInternational,
FactionName.FulcrumSecretTechnologies, FactionName.FulcrumSecretTechnologies,
@@ -2042,8 +2038,8 @@ export const Augmentations: Record<AugmentationName, Augmentation> = (() => {
info: info:
"A connective brain implant that greatly increases the user's speech reaction time. " + "A connective brain implant that greatly increases the user's speech reaction time. " +
"This allows the user to think faster and respond quicker in negotiations, and always have the last word.", "This allows the user to think faster and respond quicker in negotiations, and always have the last word.",
charisma: 1.08, charisma: 1.03,
charisma_exp: 1.1, charisma_exp: 1.05,
company_rep: 1.05, company_rep: 1.05,
factions: [FactionName.SlumSnakes, FactionName.BitRunners], factions: [FactionName.SlumSnakes, FactionName.BitRunners],
}, },
+3 -3
View File
@@ -271,13 +271,13 @@ function IntelligenceOverride({
disabled={!enabled} disabled={!enabled}
value={intelligenceOverride !== undefined ? intelligenceOverride : ""} value={intelligenceOverride !== undefined ? intelligenceOverride : ""}
onChange={(event) => { onChange={(event) => {
// Empty string will be automatically changed to "0". // Empty string will be automatically changed to "1".
if (event.target.value === "") { if (event.target.value === "") {
callbacks.setIntelligenceOverride(0); callbacks.setIntelligenceOverride(1);
return; return;
} }
const value = Number.parseInt(event.target.value); const value = Number.parseInt(event.target.value);
if (!Number.isInteger(value) || value < 0) { if (!Number.isInteger(value) || value < 1) {
return; return;
} }
callbacks.setIntelligenceOverride(value); callbacks.setIntelligenceOverride(value);
+25 -4
View File
@@ -6,6 +6,8 @@ import { ActionClass, ActionParams } from "./Action";
import { operationSkillSuccessBonus, operationTeamSuccessBonus } from "./Operation"; import { operationSkillSuccessBonus, operationTeamSuccessBonus } from "./Operation";
import { getEnumHelper } from "../../utils/EnumHelper"; import { getEnumHelper } from "../../utils/EnumHelper";
import type { TeamActionWithCasualties } from "./TeamCasualties"; import type { TeamActionWithCasualties } from "./TeamCasualties";
import { constructorsForReviver, Generic_fromJSON, type IReviverValue } from "../../utils/JSONReviver";
import { clampInteger } from "../../utils/helpers/clampNumber";
interface BlackOpParams { interface BlackOpParams {
name: BladeburnerBlackOpName; name: BladeburnerBlackOpName;
@@ -32,11 +34,11 @@ export class BlackOperation extends ActionClass implements TeamActionWithCasualt
return getEnumHelper("BladeburnerBlackOpName").isMember(name); return getEnumHelper("BladeburnerBlackOpName").isMember(name);
} }
constructor(params: ActionParams & BlackOpParams) { constructor(params: (ActionParams & BlackOpParams) | null = null) {
super(params); super(params);
this.name = params.name; this.name = params?.name ?? BladeburnerBlackOpName.OperationTyphoon;
this.reqdRank = params.reqdRank; this.reqdRank = params?.reqdRank ?? 0;
this.n = params.n; this.n = params?.n ?? 0;
} }
getAvailability(bladeburner: Bladeburner): Availability { getAvailability(bladeburner: Bladeburner): Availability {
@@ -65,4 +67,23 @@ export class BlackOperation extends ActionClass implements TeamActionWithCasualt
getTeamSuccessBonus = operationTeamSuccessBonus; getTeamSuccessBonus = operationTeamSuccessBonus;
getActionTypeSkillSuccessBonus = operationSkillSuccessBonus; getActionTypeSkillSuccessBonus = operationSkillSuccessBonus;
toJSON(): IReviverValue {
return {
ctor: "BlackOperation",
data: {
teamCount: this.teamCount,
},
};
}
loadData(loadedObject: BlackOperation): void {
this.teamCount = clampInteger(loadedObject.teamCount, 0);
}
static fromJSON(value: IReviverValue): BlackOperation {
return Generic_fromJSON(BlackOperation, value.data);
}
} }
constructorsForReviver.BlackOperation = BlackOperation;
+10 -4
View File
@@ -44,12 +44,18 @@ export function resolveTeamCasualties(action: TeamActionWithCasualties, team: Op
*/ */
const losses = const losses =
minCasualties <= maxCasualties ? team.getTeamCasualtiesRoll(minCasualties, maxCasualties) : minCasualties; minCasualties <= maxCasualties ? team.getTeamCasualtiesRoll(minCasualties, maxCasualties) : minCasualties;
team.teamSize -= losses; // Calculate the new teamSize in a temporary variable and call the setter team.teamSize ONCE.
if (team.teamSize < team.sleeveSize) { // Note that it's important to call the setter only once; otherwise, the team count of each operation won't be reset
team.killRandomSupportingSleeves(team.sleeveSize - team.teamSize); // correctly.
// For example, if _teamSize is 9 (1 team member + 8 support sleeves) and "losses" is 9, calling the setter with
// (team.teamSize - losses) will set teamCount of ops/blackOps to 0 while it should be 8.
let newTeamSize = team.teamSize - losses;
if (newTeamSize < team.sleeveSize) {
team.killRandomSupportingSleeves(team.sleeveSize - newTeamSize);
// If this happens, all team members died and some sleeves took damage. In this case, teamSize = sleeveSize. // If this happens, all team members died and some sleeves took damage. In this case, teamSize = sleeveSize.
team.teamSize = team.sleeveSize; newTeamSize = team.sleeveSize;
} }
team.teamSize = newTeamSize;
team.teamLost += losses; team.teamLost += losses;
return losses; return losses;
+50 -9
View File
@@ -47,7 +47,7 @@ import { createContracts, loadContractsData } from "./data/Contracts";
import { createOperations, loadOperationsData } from "./data/Operations"; import { createOperations, loadOperationsData } from "./data/Operations";
import { clampInteger, clampNumber } from "../utils/helpers/clampNumber"; import { clampInteger, clampNumber } from "../utils/helpers/clampNumber";
import { parseCommand } from "../Terminal/Parser"; import { parseCommand } from "../Terminal/Parser";
import { BlackOperations } from "./data/BlackOperations"; import { createBlackOperations, loadBlackOperationsData } from "./data/BlackOperations";
import { GeneralActions } from "./data/GeneralActions"; import { GeneralActions } from "./data/GeneralActions";
import { PlayerObject } from "../PersonObjects/Player/PlayerObject"; import { PlayerObject } from "../PersonObjects/Player/PlayerObject";
import { Sleeve } from "../PersonObjects/Sleeve/Sleeve"; import { Sleeve } from "../PersonObjects/Sleeve/Sleeve";
@@ -72,7 +72,31 @@ export class Bladeburner implements OperationTeam {
skillPoints = 0; skillPoints = 0;
totalSkillPoints = 0; totalSkillPoints = 0;
teamSize = 0; /**
* Do NOT directly read and write this field. You must use the getter/setter.
* We use _teamSize instead of a private field #teamSize to reduce the complexity of saving/loading code.
*/
_teamSize = 0;
get teamSize() {
return this._teamSize;
}
set teamSize(value: number) {
// Ensure teamSize is a non-negative integer.
let newSize = value;
if (!Number.isInteger(newSize) || newSize < 0) {
newSize = 0;
}
// Early return if there is no change.
if (this._teamSize === newSize) {
return;
}
this._teamSize = newSize;
// Reduce teamCount of actions if it's greater than the team size.
for (const action of [...Object.values(this.operations), ...Object.values(this.blackOperations)]) {
action.teamCount = Math.min(action.teamCount, this._teamSize);
}
}
get sleeveSize() { get sleeveSize() {
return Player.sleevesSupportingBladeburner().length; return Player.sleevesSupportingBladeburner().length;
} }
@@ -96,9 +120,13 @@ export class Bladeburner implements OperationTeam {
staminaBonus = 0; staminaBonus = 0;
maxStamina = 1; maxStamina = 1;
stamina = 1; stamina = 1;
// Contracts and operations are stored on the Bladeburner object even though they are global so that they can utilize save/load of the main bladeburner object // Contracts, operations and blackOps are stored on the Bladeburner object even though they are global so that they
// can utilize save/load of the main bladeburner object
contracts: Record<BladeburnerContractName, Contract>; contracts: Record<BladeburnerContractName, Contract>;
operations: Record<BladeburnerOperationName, Operation>; operations: Record<BladeburnerOperationName, Operation>;
blackOperations: Record<BladeburnerBlackOpName, BlackOperation>;
// Array for quick lookup by BlackOp number
blackOperationArray: BlackOperation[];
numBlackOpsComplete = 0; numBlackOpsComplete = 0;
logging = { logging = {
general: true, general: true,
@@ -119,6 +147,11 @@ export class Bladeburner implements OperationTeam {
constructor() { constructor() {
this.contracts = createContracts(); this.contracts = createContracts();
this.operations = createOperations(); this.operations = createOperations();
this.blackOperations = createBlackOperations();
this.blackOperationArray = Object.values(this.blackOperations).sort((a, b) => (a.n < b.n ? -1 : 1));
if (!this.blackOperationArray.every((blackOp, i) => blackOp.n === i)) {
throw new Error("blackOperationArray is not initialized with correct indices");
}
} }
// Initialization code that is dependent on Player is here instead of in the constructor // Initialization code that is dependent on Player is here instead of in the constructor
@@ -1407,7 +1440,7 @@ export class Bladeburner implements OperationTeam {
case BladeburnerActionType.Operation: case BladeburnerActionType.Operation:
return this.operations[actionId.name]; return this.operations[actionId.name];
case BladeburnerActionType.BlackOp: case BladeburnerActionType.BlackOp:
return BlackOperations[actionId.name]; return this.blackOperations[actionId.name];
case BladeburnerActionType.General: case BladeburnerActionType.General:
return GeneralActions[actionId.name]; return GeneralActions[actionId.name];
} }
@@ -1426,7 +1459,7 @@ export class Bladeburner implements OperationTeam {
case BladeburnerActionType.Operation: case BladeburnerActionType.Operation:
return this.operations[name as BladeburnerOperationName]; return this.operations[name as BladeburnerOperationName];
case BladeburnerActionType.BlackOp: case BladeburnerActionType.BlackOp:
return BlackOperations[name as BladeburnerBlackOpName]; return this.blackOperations[name as BladeburnerBlackOpName];
} }
} }
@@ -1437,9 +1470,11 @@ export class Bladeburner implements OperationTeam {
return id ? this.getActionObject(id) : null; return id ? this.getActionObject(id) : null;
} }
static keysToSave = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers"] }); static keysToSave = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers", "blackOperationArray"] });
// Don't load contracts or operations because of the special loading method they use, see fromJSON // Don't load contracts or operations because of the special loading method they use, see fromJSON
static keysToLoad = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers", "contracts", "operations"] }); static keysToLoad = getKeyList(Bladeburner, {
removedKeys: ["skillMultipliers", "contracts", "operations", "blackOperations", "blackOperationArray"],
});
/** Serialize the current object to a JSON save state. */ /** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue { toJSON(): IReviverValue {
@@ -1449,9 +1484,10 @@ export class Bladeburner implements OperationTeam {
/** Initializes a Bladeburner object from a JSON save state. */ /** Initializes a Bladeburner object from a JSON save state. */
static fromJSON(value: IReviverValue): Bladeburner { static fromJSON(value: IReviverValue): Bladeburner {
assertObject(value.data); assertObject(value.data);
// operations and contracts are not loaded directly from the save, we load them in using a different method // Contracts, operations, and black ops are not loaded directly from the save; they are loaded via a different method.
const contractsData = value.data.contracts; const contractsData = value.data.contracts;
const operationsData = value.data.operations; const operationsData = value.data.operations;
const blackOperationsData = value.data.blackOperations;
const bladeburner = Generic_fromJSON(Bladeburner, value.data, Bladeburner.keysToLoad); const bladeburner = Generic_fromJSON(Bladeburner, value.data, Bladeburner.keysToLoad);
/** /**
@@ -1472,10 +1508,11 @@ export class Bladeburner implements OperationTeam {
bladeburner.automateActionLow = loadActionIdentifier(bladeburner.automateActionLow); bladeburner.automateActionLow = loadActionIdentifier(bladeburner.automateActionLow);
} }
} }
// Loading this way allows better typesafety and also allows faithfully reconstructing contracts/operations // Loading this way allows better typesafety and also allows faithfully reconstructing contracts/operations/blackOps
// even from save data that is missing a lot of static info about the objects. // even from save data that is missing a lot of static info about the objects.
loadContractsData(contractsData, bladeburner.contracts); loadContractsData(contractsData, bladeburner.contracts);
loadOperationsData(operationsData, bladeburner.operations); loadOperationsData(operationsData, bladeburner.operations);
loadBlackOperationsData(blackOperationsData, bladeburner.blackOperations);
// Regenerate skill multiplier data, which is not included in savedata // Regenerate skill multiplier data, which is not included in savedata
bladeburner.updateSkillMultipliers(); bladeburner.updateSkillMultipliers();
// If stamina or maxStamina is invalid, we set both of them to 1 and recalculate them. // If stamina or maxStamina is invalid, we set both of them to 1 and recalculate them.
@@ -1488,6 +1525,10 @@ export class Bladeburner implements OperationTeam {
bladeburner.maxStamina = 1; bladeburner.maxStamina = 1;
bladeburner.calculateMaxStamina(); bladeburner.calculateMaxStamina();
} }
// "_teamSize" was "teamSize" in pre-v3 versions.
if ("teamSize" in value.data && Number.isFinite(value.data.teamSize)) {
bladeburner.teamSize = value.data.teamSize as number;
}
return bladeburner; return bladeburner;
} }
} }
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -113,7 +113,9 @@ export function createContracts(): Record<BladeburnerContractName, Contract> {
export function loadContractsData(data: unknown, contracts: Record<BladeburnerContractName, Contract>) { export function loadContractsData(data: unknown, contracts: Record<BladeburnerContractName, Contract>) {
// loading data as "unknown" and typechecking it down is probably not necessary // loading data as "unknown" and typechecking it down is probably not necessary
// but this will prevent crashes even with malformed savedata // but this will prevent crashes even with malformed savedata
if (!data || typeof data !== "object") return; if (data == null || typeof data !== "object" || Array.isArray(data)) {
return;
}
assertLoadingType<Record<BladeburnerContractName, unknown>>(data); assertLoadingType<Record<BladeburnerContractName, unknown>>(data);
for (const contractName of Object.values(BladeburnerContractName)) { for (const contractName of Object.values(BladeburnerContractName)) {
const loadedContract = data[contractName]; const loadedContract = data[contractName];
+3 -1
View File
@@ -230,7 +230,9 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
export function loadOperationsData(data: unknown, operations: Record<BladeburnerOperationName, Operation>) { export function loadOperationsData(data: unknown, operations: Record<BladeburnerOperationName, Operation>) {
// loading data as "unknown" and typechecking it down is probably not necessary // loading data as "unknown" and typechecking it down is probably not necessary
// but this will prevent crashes even with malformed savedata // but this will prevent crashes even with malformed savedata
if (!data || typeof data !== "object") return; if (data == null || typeof data !== "object" || Array.isArray(data)) {
return;
}
assertLoadingType<Record<BladeburnerOperationName, unknown>>(data); assertLoadingType<Record<BladeburnerOperationName, unknown>>(data);
for (const operationName of Object.values(BladeburnerOperationName)) { for (const operationName of Object.values(BladeburnerOperationName)) {
const loadedOperation = data[operationName]; const loadedOperation = data[operationName];
+4 -4
View File
@@ -7,7 +7,7 @@ import { BlackOpElem } from "./BlackOpElem";
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router"; import { Page } from "../../ui/Router";
import { CorruptibleText } from "../../ui/React/CorruptibleText"; import { CorruptibleText } from "../../ui/React/CorruptibleText";
import { blackOpsArray } from "../data/BlackOperations"; import { numberOfBlackOperations } from "../data/BlackOperations";
import { finishBitNode } from "../../BitNode/BitNodeUtils"; import { finishBitNode } from "../../BitNode/BitNodeUtils";
import { Player } from "@player"; import { Player } from "@player";
@@ -16,7 +16,7 @@ interface BlackOpPageProps {
} }
export function BlackOpPage({ bladeburner }: BlackOpPageProps): React.ReactElement { export function BlackOpPage({ bladeburner }: BlackOpPageProps): React.ReactElement {
const blackOperations = blackOpsArray.slice(0, bladeburner.numBlackOpsComplete + 1).reverse(); const blackOperations = bladeburner.blackOperationArray.slice(0, bladeburner.numBlackOpsComplete + 1).reverse();
return ( return (
<> <>
@@ -36,11 +36,11 @@ export function BlackOpPage({ bladeburner }: BlackOpPageProps): React.ReactEleme
Unaffected by Charisma. Unaffected by Charisma.
</Typography> </Typography>
{bladeburner.numBlackOpsComplete >= blackOpsArray.length && ( {bladeburner.numBlackOpsComplete >= numberOfBlackOperations && (
<Button <Button
sx={{ my: 1, p: 1 }} sx={{ my: 1, p: 1 }}
onClick={() => { onClick={() => {
if (!Player.bladeburner || Player.bladeburner.numBlackOpsComplete < blackOpsArray.length) { if (!Player.bladeburner || Player.bladeburner.numBlackOpsComplete < numberOfBlackOperations) {
return; return;
} }
finishBitNode(); finishBitNode();
+11 -10
View File
@@ -15,25 +15,26 @@ interface TeamSizeModalProps {
} }
export function TeamSizeModal({ bladeburner, action, open, onClose }: TeamSizeModalProps): React.ReactElement { export function TeamSizeModal({ bladeburner, action, open, onClose }: TeamSizeModalProps): React.ReactElement {
const [teamSize, setTeamSize] = useState<number | undefined>(); const [teamSize, setTeamSize] = useState(0);
function confirmTeamSize(event: React.FormEvent): void { function confirmTeamSize(event: React.FormEvent): void {
// Prevent reloading page when submitting form // Prevent reloading page when submitting form
event.preventDefault(); event.preventDefault();
if (teamSize === undefined) return; if (!Number.isInteger(teamSize) || teamSize < 0) {
const num = Math.round(teamSize); dialogBoxCreate("Invalid value entered for number of Team Members (must be a non-negative integer)");
if (isNaN(num) || num < 0) { return;
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric and non-negative)");
} else {
action.teamCount = num;
} }
action.teamCount = teamSize;
onClose(); onClose();
} }
function onTeamSize(event: React.ChangeEvent<HTMLInputElement>): void { function onTeamSize(event: React.ChangeEvent<HTMLInputElement>): void {
const x = parseFloat(event.target.value); const newTeamSize = Number(event.target.value);
if (x > bladeburner.teamSize) setTeamSize(bladeburner.teamSize); if (newTeamSize > bladeburner.teamSize) {
else setTeamSize(x); setTeamSize(bladeburner.teamSize);
} else {
setTeamSize(newTeamSize);
}
} }
return ( return (
+26 -3
View File
@@ -7,7 +7,7 @@ export const CONSTANTS = {
VersionString: "3.0.0dev", VersionString: "3.0.0dev",
isDevBranch: true, isDevBranch: true,
isInTestEnvironment: globalThis.process?.env?.JEST_WORKER_ID !== undefined, isInTestEnvironment: globalThis.process?.env?.JEST_WORKER_ID !== undefined,
VersionNumber: 48, VersionNumber: 49,
/** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience /** Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
* and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then * and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@@ -111,7 +111,7 @@ export const CONSTANTS = {
// Also update Documentation/doc/en/changelog.md when appropriate (when doing a release) // Also update Documentation/doc/en/changelog.md when appropriate (when doing a release)
LatestUpdate: ` LatestUpdate: `
## v3.0.0 development version: last updated 18 February 2026 ## v3.0.0 development version: last updated 13 April 2026
### BREAKING CHANGES ### BREAKING CHANGES
@@ -143,13 +143,14 @@ export const CONSTANTS = {
- Cancel sleeve's current task when calling ns.sleeve.travel() (#2559) (@catloversg) - Cancel sleeve's current task when calling ns.sleeve.travel() (#2559) (@catloversg)
- Make ns.cloud.purchaseServer() and ns.cloud.deleteServer() use hostname as provided (#2560) (@catloversg) - Make ns.cloud.purchaseServer() and ns.cloud.deleteServer() use hostname as provided (#2560) (@catloversg)
- Make implicit string conversion consistent across all coding contracts (#2608) (@catloversg) - Make implicit string conversion consistent across all coding contracts (#2608) (@catloversg)
- Rename ns.gang.getOtherGangInformation to getAllGangInformation (#2635) (@lstutzman)
### MAJOR CHANGES ### MAJOR CHANGES
- Added Darknet, a new mechanic based on spreading through an unstable network and cracking passwords. Purchase DarkscapeNavigator.exe in the terminal to unlock access. (#2139) (@ficocelliguy)
- Balance change: IPvGO: Improve favor gain from wins to balance around the rep value of favor (#2131) (@ficocelliguy) - Balance change: IPvGO: Improve favor gain from wins to balance around the rep value of favor (#2131) (@ficocelliguy)
- Search and read NS API docs in editor tab and documentation tab (#2163) (@catloversg) - Search and read NS API docs in editor tab and documentation tab (#2163) (@catloversg)
- Balance change: Infiltration: Rebalance rewards, add min stat requirement, add market demand (#2210) (@ficocelliguy, @d0sboots, @catloversg) - Balance change: Infiltration: Rebalance rewards, add min stat requirement, add market demand (#2210) (@ficocelliguy, @d0sboots, @catloversg)
- Add Dark Net (#2139) (@ficocelliguy)
### UI ### UI
@@ -224,6 +225,10 @@ export const CONSTANTS = {
- Fix: Import save comparison popup shows wrong BN level (#2595) (@catloversg) - Fix: Import save comparison popup shows wrong BN level (#2595) (@catloversg)
- Fix: Cannot type in text boxes rendered by players' scripts when terminal tab is shown (#2615, #2622) (@lstutzman, @catloversg) - Fix: Cannot type in text boxes rendered by players' scripts when terminal tab is shown (#2615, #2622) (@lstutzman, @catloversg)
- Navigate to gym/university instead of city when stopping focusing on gym/class work (#2613) (@lstutzman) - Navigate to gym/university instead of city when stopping focusing on gym/class work (#2613) (@lstutzman)
- Ensure prompts shown by ns.prompt do not lose focus in the terminal tab (#2631) (@catloversg)
- Remove unnecessary max-width of tab list in in-game editor (#2643) (@catloversg)
- Add hooks to sidebar for players to attach custom content (#2651) (@catloversg)
- Use exponential notation when formatting very small HP or thread values (#2656) (@catloversg)
### MISC ### MISC
@@ -325,6 +330,12 @@ export const CONSTANTS = {
- Dnet: Remove packet capture (#2594) (@ficocelliguy) - Dnet: Remove packet capture (#2594) (@ficocelliguy)
- Generate more frequent and lower-reward coding contracts (#2603) (@ficocelliguy) - Generate more frequent and lower-reward coding contracts (#2603) (@ficocelliguy)
- Electron: Fix issues in edge cases of using --export-save (#2590) (@catloversg) - Electron: Fix issues in edge cases of using --export-save (#2590) (@catloversg)
- Fix recursive alias detection causing infinite recursion (#2610) (@lstutzman)
- Add "hidden" mkdir command (#2646) (@catloversg)
- Dnet: Remove bonus time effect on authentication and heartbleed speed; fix ram rounding (#2627) (@ficocelliguy)
- Fix tab completion for multi-word quoted autocomplete options (#2612) (@lstutzman)
- Add weakenEffect to formulas.hacking namespace (#2626) (@lstutzman)
- Update description of "cat" in "help" command (#2654) (@catloversg)
### DOCUMENTATION ### DOCUMENTATION
@@ -378,6 +389,9 @@ export const CONSTANTS = {
- Update mention of outdated getStockForecast API (#2578) (@catloversg) - Update mention of outdated getStockForecast API (#2578) (@catloversg)
- Fix newline issues in IPvGO docs and add missing RAM cost (#2602) (@catloversg) - Fix newline issues in IPvGO docs and add missing RAM cost (#2602) (@catloversg)
- Document coding contract's generation and rewards (#2624) (@catloversg) - Document coding contract's generation and rewards (#2624) (@catloversg)
- Clarify scp and exec darknet permissions in API docs (#2634) (@lstutzman)
- Update RAM cost of hacknet APIs and remove unnecessary RAM cost docs (#2639) (@catloversg)
- Update tutorial script for buying cloud servers (#2653) (@catloversg)
### SPOILER CHANGES - UI ### SPOILER CHANGES - UI
@@ -389,6 +403,8 @@ export const CONSTANTS = {
- Prevent ending BNs through reuse of Bladeburner UI event handler (#2574) (@catloversg) - Prevent ending BNs through reuse of Bladeburner UI event handler (#2574) (@catloversg)
- Always show Black Operations list (#2592) (@catloversg) - Always show Black Operations list (#2592) (@catloversg)
- Show hints of Sleeves mechanic in pre-endgame (#2605) (@catloversg) - Show hints of Sleeves mechanic in pre-endgame (#2605) (@catloversg)
- Consistently calculate BitNode "level" (#2645) (@catloversg)
- Add tooltips explaining why Bladeburner skill upgrades are disabled (#2648) (@catloversg)
### SPOILER CHANGES - MISC ### SPOILER CHANGES - MISC
@@ -416,6 +432,9 @@ export const CONSTANTS = {
- Add APIs to get rank gain and rank loss of an action (#2572) (@catloversg) - Add APIs to get rank gain and rank loss of an action (#2572) (@catloversg)
- Reduce RAM cost of inGang and inBladeburner APIs (#2582) (@catloversg) - Reduce RAM cost of inGang and inBladeburner APIs (#2582) (@catloversg)
- Fix skillMaxUpgradeCount returning 1 at extreme skill levels (#2611) (@lstutzman) - Fix skillMaxUpgradeCount returning 1 at extreme skill levels (#2611) (@lstutzman)
- API: Expose charged effects of Stanek's Gift active fragments (#2638) (@catloversg)
- Apply SF override to charisma calculations (#2642) (@catloversg)
- Update description of "BN9: Challenge" achievement (#2647) (@catloversg)
### SPOILER CHANGES - DOCUMENTATION ### SPOILER CHANGES - DOCUMENTATION
@@ -519,5 +538,9 @@ export const CONSTANTS = {
- Refactor and fix issues in db.ts (#2623) (@catloversg) - Refactor and fix issues in db.ts (#2623) (@catloversg)
- Add dependency array to TerminalInput keydown useEffect (#2620) (@lstutzman) - Add dependency array to TerminalInput keydown useEffect (#2620) (@lstutzman)
- Add dependency array to GameRoot useEffect (#2617) (@lstutzman) - Add dependency array to GameRoot useEffect (#2617) (@lstutzman)
- Dev menu: Initialize dark net data when setting SF15 level (#2632) (@catloversg)
- Use type-only imports in ArrayHelpers.ts (#2630) (@catloversg)
- Remove redundant "$" from JS/TS regex in webpack config (#2649) (@catloversg)
- Allow specifying commit hash id when building artifacts (#2652) (@catloversg)
`, `,
} as const; } as const;
+37 -43
View File
@@ -215,32 +215,25 @@ export class Division {
} }
} }
// Process change in demand and competition for this industry's materials // Process demand, competition, and market price changes for this division's materials
processMaterialMarket(): void { processMaterialMarket(): void {
//References to prodMats and reqMats // Relevant materials:
const reqMats = this.requiredMaterials, // - All materials this division requires or produces
prodMats = this.producedMaterials; // - Boost materials
const materials = new Set([
...getRecordKeys(this.requiredMaterials),
...this.producedMaterials,
...corpConstants.boostMaterials,
]);
//Only 'process the market' for materials that this industry deals with
for (const city of Object.values(CityName)) { for (const city of Object.values(CityName)) {
//If this industry has a warehouse in this city, process the market const warehouse = this.warehouses[city];
//for every material this industry requires or produces // If this division has a warehouse in this city, process the relevant materials
if (this.warehouses[city]) { if (warehouse == null) {
const wh = this.warehouses[city]; continue;
for (const name of Object.keys(reqMats) as CorpMaterialName[]) { }
if (Object.hasOwn(reqMats, name)) { for (const materialName of materials) {
wh.materials[name].processMarket(); warehouse.materials[materialName].processMarket();
}
}
//Produced materials are stored in an array
for (const matName of prodMats) wh.materials[matName].processMarket();
//Process these twice because these boost production ??????
wh.materials.Hardware.processMarket();
wh.materials.Robots.processMarket();
wh.materials["AI Cores"].processMarket();
wh.materials["Real Estate"].processMarket();
} }
} }
} }
@@ -592,20 +585,16 @@ export class Division {
/* Process production of materials */ /* Process production of materials */
if (this.producedMaterials.length > 0) { if (this.producedMaterials.length > 0) {
const mat = warehouse.materials[this.producedMaterials[0]];
//Calculate the maximum production of this material based //Calculate the maximum production of this material based
//on the office's productivity //on the office's productivity
const maxProd = const maxProd =
this.getOfficeProductivity(office) * this.getOfficeProductivity(office) *
this.productionMult * // Multiplier from materials this.productionMult * // Multiplier from boost materials
corporation.getProductionMultiplier() * corporation.getProductionMultiplier() *
this.getProductionMultiplier(); // Multiplier from Research this.getProductionMultiplier(); // Multiplier from Research
let prod;
// If there is a limit set on production, apply the limit // Convert production from per second to per market cycle
prod = mat.productionLimit === null ? maxProd : Math.min(maxProd, mat.productionLimit); let prod = maxProd * corpConstants.secondsPerMarketCycle * marketCycles;
prod *= corpConstants.secondsPerMarketCycle * marketCycles; //Convert production from per second to per market cycle
// Calculate net change in warehouse storage making the produced materials will cost // Calculate net change in warehouse storage making the produced materials will cost
let totalMatSize = 0; let totalMatSize = 0;
@@ -677,6 +666,14 @@ export class Division {
} }
avgQlt = Math.max(avgQlt, 1); avgQlt = Math.max(avgQlt, 1);
for (let j = 0; j < this.producedMaterials.length; ++j) { for (let j = 0; j < this.producedMaterials.length; ++j) {
let outputAmount = prod * producableFrac;
const productionLimit = warehouse.materials[this.producedMaterials[j]].productionLimit;
if (productionLimit !== null) {
// productionLimit is per second, so we need to convert it to per market cycle.
const effectiveLimitValue = productionLimit * corpConstants.secondsPerMarketCycle * marketCycles;
outputAmount = Math.min(outputAmount, effectiveLimitValue);
}
let tempQlt = let tempQlt =
office.employeeProductionByJob[CorpEmployeeJob.Engineer] / 90 + office.employeeProductionByJob[CorpEmployeeJob.Engineer] / 90 +
Math.pow(this.researchPoints, this.researchFactor) + Math.pow(this.researchPoints, this.researchFactor) +
@@ -687,27 +684,24 @@ export class Division {
1, 1,
(warehouse.materials[this.producedMaterials[j]].quality * (warehouse.materials[this.producedMaterials[j]].quality *
warehouse.materials[this.producedMaterials[j]].stored + warehouse.materials[this.producedMaterials[j]].stored +
tempQlt * prod * producableFrac) / tempQlt * outputAmount) /
(warehouse.materials[this.producedMaterials[j]].stored + prod * producableFrac), (warehouse.materials[this.producedMaterials[j]].stored + outputAmount),
); );
warehouse.materials[this.producedMaterials[j]].averagePrice = warehouse.materials[this.producedMaterials[j]].averagePrice =
(warehouse.materials[this.producedMaterials[j]].averagePrice * (warehouse.materials[this.producedMaterials[j]].averagePrice *
warehouse.materials[this.producedMaterials[j]].stored + warehouse.materials[this.producedMaterials[j]].stored +
warehouse.materials[this.producedMaterials[j]].marketPrice * prod * producableFrac) / warehouse.materials[this.producedMaterials[j]].marketPrice * outputAmount) /
(warehouse.materials[this.producedMaterials[j]].stored + prod * producableFrac); (warehouse.materials[this.producedMaterials[j]].stored + outputAmount);
warehouse.materials[this.producedMaterials[j]].stored += prod * producableFrac;
warehouse.materials[this.producedMaterials[j]].stored += outputAmount;
warehouse.materials[this.producedMaterials[j]].productionAmount =
outputAmount / (corpConstants.secondsPerMarketCycle * marketCycles);
} }
} else { } else {
for (const reqMatName of getRecordKeys(this.requiredMaterials)) { for (const reqMatName of getRecordKeys(this.requiredMaterials)) {
warehouse.materials[reqMatName].productionAmount = 0; warehouse.materials[reqMatName].productionAmount = 0;
} }
} }
//Per second
const materialProduction = (prod * producableFrac) / (corpConstants.secondsPerMarketCycle * marketCycles);
for (const prodMatName of this.producedMaterials) {
warehouse.materials[prodMatName].productionAmount = materialProduction;
}
} else { } else {
//If this doesn't produce any materials, then it only creates //If this doesn't produce any materials, then it only creates
//Products. Creating products will consume materials. The //Products. Creating products will consume materials. The
@@ -860,12 +854,12 @@ export class Division {
if (!warehouse) continue; if (!warehouse) continue;
switch (state) { switch (state) {
case "PRODUCTION": { case "PRODUCTION": {
//Calculate the maximum production of this material based //Calculate the maximum production of this product based
//on the office's productivity //on the office's productivity
const maxProd = const maxProd =
this.getOfficeProductivity(office, { forProduct: true }) * this.getOfficeProductivity(office, { forProduct: true }) *
corporation.getProductionMultiplier() * corporation.getProductionMultiplier() *
this.productionMult * // Multiplier from materials this.productionMult * // Multiplier from boost materials
this.getProductionMultiplier() * // Multiplier from research this.getProductionMultiplier() * // Multiplier from research
this.getProductProductionMultiplier(); // Multiplier from research this.getProductProductionMultiplier(); // Multiplier from research
let prod; let prod;
+3 -1
View File
@@ -19,7 +19,7 @@ import {
CorpBaseResearchName, CorpBaseResearchName,
CorpProductResearchName, CorpProductResearchName,
} from "@enums"; } from "@enums";
import { PositiveInteger } from "../../types"; import type { PositiveInteger } from "../../types";
/** Names of all corporation game states */ /** Names of all corporation game states */
export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", "EXPORT", "SALE"], export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", "EXPORT", "SALE"],
@@ -30,6 +30,8 @@ export const stateNames: CorpStateName[] = ["START", "PURCHASE", "PRODUCTION", "
industryNames: CorpIndustryName[] = Object.values(IndustryType), industryNames: CorpIndustryName[] = Object.values(IndustryType),
/** Names of all materials */ /** Names of all materials */
materialNames: APIMaterialName[] = Object.values(CorpMaterialName), materialNames: APIMaterialName[] = Object.values(CorpMaterialName),
/** Names of all boost materials */
boostMaterials: CorpMaterialName[] = ["Hardware", "Robots", "AI Cores", "Real Estate"],
/** Names of all one-time corporation-wide unlocks */ /** Names of all one-time corporation-wide unlocks */
unlockNames: APIUnlockName[] = Object.values(CorpUnlockName), unlockNames: APIUnlockName[] = Object.values(CorpUnlockName),
upgradeNames: APIUpgradeName[] = Object.values(CorpUpgradeName), upgradeNames: APIUpgradeName[] = Object.values(CorpUpgradeName),
+1 -1
View File
@@ -27,7 +27,7 @@ export function CorporationRoot(): React.ReactElement {
return ( return (
<Context.Corporation.Provider value={corporation}> <Context.Corporation.Provider value={corporation}>
<Tabs variant="scrollable" value={divisionName} onChange={handleChange} sx={{ maxWidth: "65vw" }} scrollButtons> <Tabs variant="scrollable" value={divisionName} onChange={handleChange} scrollButtons>
<Tab label={corporation.name} value={"Overview"} /> <Tab label={corporation.name} value={"Overview"} />
{[...corporation.divisions.values()].map((div) => ( {[...corporation.divisions.values()].map((div) => (
<Tab key={div.name} label={div.name} value={div.name} /> <Tab key={div.name} label={div.name} value={div.name} />
+2
View File
@@ -73,6 +73,7 @@ function WarehouseRoot(props: WarehouseProps): React.ReactElement {
const isInStock = props.warehouse.materials[matName].stored > 0; const isInStock = props.warehouse.materials[matName].stored > 0;
const isRelevant = isRelevantMaterial(matName, division); const isRelevant = isRelevantMaterial(matName, division);
if (!isInStock && !isRelevant) continue; if (!isInStock && !isRelevant) continue;
const isOutputMaterial = division.producedMaterials.includes(matName);
mats.push( mats.push(
<MaterialElem <MaterialElem
rerender={props.rerender} rerender={props.rerender}
@@ -80,6 +81,7 @@ function WarehouseRoot(props: WarehouseProps): React.ReactElement {
key={matName} key={matName}
mat={props.warehouse.materials[matName]} mat={props.warehouse.materials[matName]}
warehouse={props.warehouse} warehouse={props.warehouse}
isOutputMaterial={isOutputMaterial}
/>, />,
); );
} }
+2 -4
View File
@@ -1,15 +1,13 @@
import { CorpMaterialName } from "@nsdefs"; import { CorpMaterialName } from "@nsdefs";
import { Division } from "../Division"; import { Division } from "../Division";
import { boostMaterials } from "../data/Constants";
// Returns a boolean indicating whether the given material is relevant for the // Returns a boolean indicating whether the given material is relevant for the
// current industry. // current industry.
export function isRelevantMaterial(matName: CorpMaterialName, division: Division): boolean { export function isRelevantMaterial(matName: CorpMaterialName, division: Division): boolean {
// Materials that affect Production multiplier
const prodMultiplierMats: CorpMaterialName[] = ["Hardware", "Robots", "AI Cores", "Real Estate"];
if (Object.keys(division.requiredMaterials).includes(matName)) return true; if (Object.keys(division.requiredMaterials).includes(matName)) return true;
if (division.producedMaterials.includes(matName)) return true; if (division.producedMaterials.includes(matName)) return true;
if (prodMultiplierMats.includes(matName)) return true; if (boostMaterials.includes(matName)) return true;
return false; return false;
} }
+14 -9
View File
@@ -19,6 +19,7 @@ interface IMaterialProps {
city: CityName; city: CityName;
mat: Material; mat: Material;
rerender: () => void; rerender: () => void;
isOutputMaterial: boolean;
} }
// Creates the UI for a single Material type // Creates the UI for a single Material type
@@ -74,7 +75,7 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
} }
// Limit Production button // Limit Production button
let limitMaterialButtonText = "Limit Material"; let limitMaterialButtonText = "Limit Material Production";
if (mat.productionLimit !== null) { if (mat.productionLimit !== null) {
limitMaterialButtonText += " (" + formatCorpStat(mat.productionLimit) + ")"; limitMaterialButtonText += " (" + formatCorpStat(mat.productionLimit) + ")";
} }
@@ -158,14 +159,18 @@ export function MaterialElem(props: IMaterialProps): React.ReactElement {
open={sellMaterialOpen} open={sellMaterialOpen}
onClose={() => setSellMaterialOpen(false)} onClose={() => setSellMaterialOpen(false)}
/> />
<Button color={tutorial ? "error" : "primary"} onClick={() => setLimitProductionOpen(true)}> {props.isOutputMaterial && (
{limitMaterialButtonText} <>
</Button> <Button color={tutorial ? "error" : "primary"} onClick={() => setLimitProductionOpen(true)}>
<LimitMaterialProductionModal {limitMaterialButtonText}
material={mat} </Button>
open={limitProductionOpen} <LimitMaterialProductionModal
onClose={() => setLimitProductionOpen(false)} material={mat}
/> open={limitProductionOpen}
onClose={() => setLimitProductionOpen(false)}
/>
</>
)}
</Box> </Box>
</Box> </Box>
</Paper> </Paper>
@@ -45,7 +45,16 @@ export function LimitMaterialProductionModal(props: IProps): React.ReactElement
<Typography> <Typography>
Enter a limit to the amount of this material you would like to produce per second. Leave the box empty to set no Enter a limit to the amount of this material you would like to produce per second. Leave the box empty to set no
limit. limit.
<br />
<br />
This limit applies only to output; it does not affect input consumption.
<br />
<br />
For example, in Agriculture, assume the division's raw production is 1000. You need to consume 500 Water and 200
Chemicals to produce 1000 Plants and 1000 Food. If you set the limits for Plants and Food to 200 and 100
respectively, you will still consume 500 Water and 200 Chemicals, but only produce 200 Plants and 100 Food.
</Typography> </Typography>
<br />
<TextField autoFocus={true} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} /> <TextField autoFocus={true} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} />
<Button onClick={limitMaterialProduction}>Limit production</Button> <Button onClick={limitMaterialProduction}>Limit production</Button>
</Modal> </Modal>
+1 -1
View File
@@ -77,7 +77,7 @@ export function NetworkDisplayWrapper(): React.ReactElement {
useEffect(() => { useEffect(() => {
const clearSubscription = DarknetEvents.subscribe(() => updateDisplay()); const clearSubscription = DarknetEvents.subscribe(() => updateDisplay());
draggableBackground.current?.addEventListener("wheel", (e) => e.preventDefault()); draggableBackground.current?.addEventListener("wheel", (e) => e.preventDefault(), { passive: false });
scrollTo(DarknetState.netViewTopScroll, DarknetState.netViewLeftScroll); scrollTo(DarknetState.netViewTopScroll, DarknetState.netViewLeftScroll);
updateDisplay(); updateDisplay();
@@ -142,8 +142,23 @@ same as the string `['foo', 'bar']`.
Internally, we use `JSON.parse` to convert the string answer, and `['foo', 'bar']` is not a valid string representation Internally, we use `JSON.parse` to convert the string answer, and `['foo', 'bar']` is not a valid string representation
of an array. In JSON, a string needs to be enclosed by double quotes. Using single quotes or backticks is not allowed. of an array. In JSON, a string needs to be enclosed by double quotes. Using single quotes or backticks is not allowed.
This is another example of why you should not convert your answer to a string when not requested. If you submit your This is one reason why you should not convert your answer to a string unless requested. If you submit your array as is,
array as it is, you do not need to care about the quote types. you do not need to worry about quote types.
Let's check another example:
```js
const firstString = "foo";
const secondString = "bar";
const answer = [firstString, secondString];
ns.codingcontract.attempt(answer.toString(), "filename.cct");
ns.codingcontract.attempt(String(answer), "filename.cct");
```
Do NOT call toString() or use similar methods to convert your string array to a string. `["foo", "bar"]` will be
converted to `foo,bar`. For contracts that expect a string array, submitting this string causes it to be interpreted as
`[foo,bar]`, which is then passed to `JSON.parse`. However, `[foo,bar]` is not valid JSON (it lacks double quotes), so
your answer will be invalid.
## Rewards ## Rewards
+56 -4
View File
@@ -91,8 +91,8 @@ import nsDoc_bitburner_autocompletedata_txts_md from "../../markdown/bitburner.a
import nsDoc_bitburner_backdoorrequirement_md from "../../markdown/bitburner.backdoorrequirement.md?raw"; import nsDoc_bitburner_backdoorrequirement_md from "../../markdown/bitburner.backdoorrequirement.md?raw";
import nsDoc_bitburner_backdoorrequirement_server_md from "../../markdown/bitburner.backdoorrequirement.server.md?raw"; import nsDoc_bitburner_backdoorrequirement_server_md from "../../markdown/bitburner.backdoorrequirement.server.md?raw";
import nsDoc_bitburner_backdoorrequirement_type_md from "../../markdown/bitburner.backdoorrequirement.type.md?raw"; import nsDoc_bitburner_backdoorrequirement_type_md from "../../markdown/bitburner.backdoorrequirement.type.md?raw";
import nsDoc_bitburner_basetask_cyclesworked_md from "../../markdown/bitburner.basetask.cyclesworked.md?raw";
import nsDoc_bitburner_basetask_md from "../../markdown/bitburner.basetask.md?raw"; import nsDoc_bitburner_basetask_md from "../../markdown/bitburner.basetask.md?raw";
import nsDoc_bitburner_basetask_nextcompletion_md from "../../markdown/bitburner.basetask.nextcompletion.md?raw";
import nsDoc_bitburner_basichgwoptions_additionalmsec_md from "../../markdown/bitburner.basichgwoptions.additionalmsec.md?raw"; import nsDoc_bitburner_basichgwoptions_additionalmsec_md from "../../markdown/bitburner.basichgwoptions.additionalmsec.md?raw";
import nsDoc_bitburner_basichgwoptions_md from "../../markdown/bitburner.basichgwoptions.md?raw"; import nsDoc_bitburner_basichgwoptions_md from "../../markdown/bitburner.basichgwoptions.md?raw";
import nsDoc_bitburner_basichgwoptions_stock_md from "../../markdown/bitburner.basichgwoptions.stock.md?raw"; import nsDoc_bitburner_basichgwoptions_stock_md from "../../markdown/bitburner.basichgwoptions.stock.md?raw";
@@ -730,7 +730,6 @@ import nsDoc_bitburner_grafting_graftaugmentation_md from "../../markdown/bitbur
import nsDoc_bitburner_grafting_md from "../../markdown/bitburner.grafting.md?raw"; import nsDoc_bitburner_grafting_md from "../../markdown/bitburner.grafting.md?raw";
import nsDoc_bitburner_grafting_waitforongoinggrafting_md from "../../markdown/bitburner.grafting.waitforongoinggrafting.md?raw"; import nsDoc_bitburner_grafting_waitforongoinggrafting_md from "../../markdown/bitburner.grafting.waitforongoinggrafting.md?raw";
import nsDoc_bitburner_graftingtask_augmentation_md from "../../markdown/bitburner.graftingtask.augmentation.md?raw"; import nsDoc_bitburner_graftingtask_augmentation_md from "../../markdown/bitburner.graftingtask.augmentation.md?raw";
import nsDoc_bitburner_graftingtask_completion_md from "../../markdown/bitburner.graftingtask.completion.md?raw";
import nsDoc_bitburner_graftingtask_md from "../../markdown/bitburner.graftingtask.md?raw"; import nsDoc_bitburner_graftingtask_md from "../../markdown/bitburner.graftingtask.md?raw";
import nsDoc_bitburner_graftingtask_type_md from "../../markdown/bitburner.graftingtask.type.md?raw"; import nsDoc_bitburner_graftingtask_type_md from "../../markdown/bitburner.graftingtask.type.md?raw";
import nsDoc_bitburner_gymenumtype_md from "../../markdown/bitburner.gymenumtype.md?raw"; import nsDoc_bitburner_gymenumtype_md from "../../markdown/bitburner.gymenumtype.md?raw";
@@ -1172,6 +1171,8 @@ import nsDoc_bitburner_player_md from "../../markdown/bitburner.player.md?raw";
import nsDoc_bitburner_player_money_md from "../../markdown/bitburner.player.money.md?raw"; import nsDoc_bitburner_player_money_md from "../../markdown/bitburner.player.money.md?raw";
import nsDoc_bitburner_player_numpeoplekilled_md from "../../markdown/bitburner.player.numpeoplekilled.md?raw"; import nsDoc_bitburner_player_numpeoplekilled_md from "../../markdown/bitburner.player.numpeoplekilled.md?raw";
import nsDoc_bitburner_player_totalplaytime_md from "../../markdown/bitburner.player.totalplaytime.md?raw"; import nsDoc_bitburner_player_totalplaytime_md from "../../markdown/bitburner.player.totalplaytime.md?raw";
import nsDoc_bitburner_playerbasetask_cyclesworked_md from "../../markdown/bitburner.playerbasetask.cyclesworked.md?raw";
import nsDoc_bitburner_playerbasetask_md from "../../markdown/bitburner.playerbasetask.md?raw";
import nsDoc_bitburner_playerrequirement_md from "../../markdown/bitburner.playerrequirement.md?raw"; import nsDoc_bitburner_playerrequirement_md from "../../markdown/bitburner.playerrequirement.md?raw";
import nsDoc_bitburner_positionenumtype_md from "../../markdown/bitburner.positionenumtype.md?raw"; import nsDoc_bitburner_positionenumtype_md from "../../markdown/bitburner.positionenumtype.md?raw";
import nsDoc_bitburner_positiontype_md from "../../markdown/bitburner.positiontype.md?raw"; import nsDoc_bitburner_positiontype_md from "../../markdown/bitburner.positiontype.md?raw";
@@ -1384,20 +1385,45 @@ import nsDoc_bitburner_sleeve_settosynchronize_md from "../../markdown/bitburner
import nsDoc_bitburner_sleeve_settouniversitycourse_md from "../../markdown/bitburner.sleeve.settouniversitycourse.md?raw"; import nsDoc_bitburner_sleeve_settouniversitycourse_md from "../../markdown/bitburner.sleeve.settouniversitycourse.md?raw";
import nsDoc_bitburner_sleeve_travel_md from "../../markdown/bitburner.sleeve.travel.md?raw"; import nsDoc_bitburner_sleeve_travel_md from "../../markdown/bitburner.sleeve.travel.md?raw";
import nsDoc_bitburner_sleeve_upgradememory_md from "../../markdown/bitburner.sleeve.upgradememory.md?raw"; import nsDoc_bitburner_sleeve_upgradememory_md from "../../markdown/bitburner.sleeve.upgradememory.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_actionname_md from "../../markdown/bitburner.sleevebladeburnertask.actionname.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_actiontype_md from "../../markdown/bitburner.sleevebladeburnertask.actiontype.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_cyclesneeded_md from "../../markdown/bitburner.sleevebladeburnertask.cyclesneeded.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_cyclesworked_md from "../../markdown/bitburner.sleevebladeburnertask.cyclesworked.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_md from "../../markdown/bitburner.sleevebladeburnertask.md?raw"; import nsDoc_bitburner_sleevebladeburnertask_md from "../../markdown/bitburner.sleevebladeburnertask.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_taskscompleted_md from "../../markdown/bitburner.sleevebladeburnertask.taskscompleted.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_type_md from "../../markdown/bitburner.sleevebladeburnertask.type.md?raw";
import nsDoc_bitburner_sleeveclasstask_classtype_md from "../../markdown/bitburner.sleeveclasstask.classtype.md?raw";
import nsDoc_bitburner_sleeveclasstask_location_md from "../../markdown/bitburner.sleeveclasstask.location.md?raw";
import nsDoc_bitburner_sleeveclasstask_md from "../../markdown/bitburner.sleeveclasstask.md?raw"; import nsDoc_bitburner_sleeveclasstask_md from "../../markdown/bitburner.sleeveclasstask.md?raw";
import nsDoc_bitburner_sleeveclasstask_type_md from "../../markdown/bitburner.sleeveclasstask.type.md?raw";
import nsDoc_bitburner_sleevecompanytask_companyname_md from "../../markdown/bitburner.sleevecompanytask.companyname.md?raw";
import nsDoc_bitburner_sleevecompanytask_md from "../../markdown/bitburner.sleevecompanytask.md?raw"; import nsDoc_bitburner_sleevecompanytask_md from "../../markdown/bitburner.sleevecompanytask.md?raw";
import nsDoc_bitburner_sleevecompanytask_type_md from "../../markdown/bitburner.sleevecompanytask.type.md?raw";
import nsDoc_bitburner_sleevecrimetask_crimetype_md from "../../markdown/bitburner.sleevecrimetask.crimetype.md?raw";
import nsDoc_bitburner_sleevecrimetask_cyclesneeded_md from "../../markdown/bitburner.sleevecrimetask.cyclesneeded.md?raw";
import nsDoc_bitburner_sleevecrimetask_cyclesworked_md from "../../markdown/bitburner.sleevecrimetask.cyclesworked.md?raw";
import nsDoc_bitburner_sleevecrimetask_md from "../../markdown/bitburner.sleevecrimetask.md?raw"; import nsDoc_bitburner_sleevecrimetask_md from "../../markdown/bitburner.sleevecrimetask.md?raw";
import nsDoc_bitburner_sleevecrimetask_taskscompleted_md from "../../markdown/bitburner.sleevecrimetask.taskscompleted.md?raw";
import nsDoc_bitburner_sleevecrimetask_type_md from "../../markdown/bitburner.sleevecrimetask.type.md?raw";
import nsDoc_bitburner_sleevefactiontask_factionname_md from "../../markdown/bitburner.sleevefactiontask.factionname.md?raw";
import nsDoc_bitburner_sleevefactiontask_factionworktype_md from "../../markdown/bitburner.sleevefactiontask.factionworktype.md?raw";
import nsDoc_bitburner_sleevefactiontask_md from "../../markdown/bitburner.sleevefactiontask.md?raw"; import nsDoc_bitburner_sleevefactiontask_md from "../../markdown/bitburner.sleevefactiontask.md?raw";
import nsDoc_bitburner_sleevefactiontask_type_md from "../../markdown/bitburner.sleevefactiontask.type.md?raw";
import nsDoc_bitburner_sleeveinfiltratetask_cyclesneeded_md from "../../markdown/bitburner.sleeveinfiltratetask.cyclesneeded.md?raw";
import nsDoc_bitburner_sleeveinfiltratetask_cyclesworked_md from "../../markdown/bitburner.sleeveinfiltratetask.cyclesworked.md?raw";
import nsDoc_bitburner_sleeveinfiltratetask_md from "../../markdown/bitburner.sleeveinfiltratetask.md?raw"; import nsDoc_bitburner_sleeveinfiltratetask_md from "../../markdown/bitburner.sleeveinfiltratetask.md?raw";
import nsDoc_bitburner_sleeveinfiltratetask_type_md from "../../markdown/bitburner.sleeveinfiltratetask.type.md?raw";
import nsDoc_bitburner_sleeveperson_md from "../../markdown/bitburner.sleeveperson.md?raw"; import nsDoc_bitburner_sleeveperson_md from "../../markdown/bitburner.sleeveperson.md?raw";
import nsDoc_bitburner_sleeveperson_memory_md from "../../markdown/bitburner.sleeveperson.memory.md?raw"; import nsDoc_bitburner_sleeveperson_memory_md from "../../markdown/bitburner.sleeveperson.memory.md?raw";
import nsDoc_bitburner_sleeveperson_shock_md from "../../markdown/bitburner.sleeveperson.shock.md?raw"; import nsDoc_bitburner_sleeveperson_shock_md from "../../markdown/bitburner.sleeveperson.shock.md?raw";
import nsDoc_bitburner_sleeveperson_storedcycles_md from "../../markdown/bitburner.sleeveperson.storedcycles.md?raw"; import nsDoc_bitburner_sleeveperson_storedcycles_md from "../../markdown/bitburner.sleeveperson.storedcycles.md?raw";
import nsDoc_bitburner_sleeveperson_sync_md from "../../markdown/bitburner.sleeveperson.sync.md?raw"; import nsDoc_bitburner_sleeveperson_sync_md from "../../markdown/bitburner.sleeveperson.sync.md?raw";
import nsDoc_bitburner_sleeverecoverytask_md from "../../markdown/bitburner.sleeverecoverytask.md?raw"; import nsDoc_bitburner_sleeverecoverytask_md from "../../markdown/bitburner.sleeverecoverytask.md?raw";
import nsDoc_bitburner_sleeverecoverytask_type_md from "../../markdown/bitburner.sleeverecoverytask.type.md?raw";
import nsDoc_bitburner_sleevesupporttask_md from "../../markdown/bitburner.sleevesupporttask.md?raw"; import nsDoc_bitburner_sleevesupporttask_md from "../../markdown/bitburner.sleevesupporttask.md?raw";
import nsDoc_bitburner_sleevesupporttask_type_md from "../../markdown/bitburner.sleevesupporttask.type.md?raw";
import nsDoc_bitburner_sleevesynchrotask_md from "../../markdown/bitburner.sleevesynchrotask.md?raw"; import nsDoc_bitburner_sleevesynchrotask_md from "../../markdown/bitburner.sleevesynchrotask.md?raw";
import nsDoc_bitburner_sleevesynchrotask_type_md from "../../markdown/bitburner.sleevesynchrotask.type.md?raw";
import nsDoc_bitburner_sleevetask_md from "../../markdown/bitburner.sleevetask.md?raw"; import nsDoc_bitburner_sleevetask_md from "../../markdown/bitburner.sleevetask.md?raw";
import nsDoc_bitburner_somerequirement_conditions_md from "../../markdown/bitburner.somerequirement.conditions.md?raw"; import nsDoc_bitburner_somerequirement_conditions_md from "../../markdown/bitburner.somerequirement.conditions.md?raw";
import nsDoc_bitburner_somerequirement_md from "../../markdown/bitburner.somerequirement.md?raw"; import nsDoc_bitburner_somerequirement_md from "../../markdown/bitburner.somerequirement.md?raw";
@@ -1688,8 +1714,8 @@ AllPages["nsDoc/bitburner.autocompletedata.txts.md"] = nsDoc_bitburner_autocompl
AllPages["nsDoc/bitburner.backdoorrequirement.md"] = nsDoc_bitburner_backdoorrequirement_md; AllPages["nsDoc/bitburner.backdoorrequirement.md"] = nsDoc_bitburner_backdoorrequirement_md;
AllPages["nsDoc/bitburner.backdoorrequirement.server.md"] = nsDoc_bitburner_backdoorrequirement_server_md; AllPages["nsDoc/bitburner.backdoorrequirement.server.md"] = nsDoc_bitburner_backdoorrequirement_server_md;
AllPages["nsDoc/bitburner.backdoorrequirement.type.md"] = nsDoc_bitburner_backdoorrequirement_type_md; AllPages["nsDoc/bitburner.backdoorrequirement.type.md"] = nsDoc_bitburner_backdoorrequirement_type_md;
AllPages["nsDoc/bitburner.basetask.cyclesworked.md"] = nsDoc_bitburner_basetask_cyclesworked_md;
AllPages["nsDoc/bitburner.basetask.md"] = nsDoc_bitburner_basetask_md; AllPages["nsDoc/bitburner.basetask.md"] = nsDoc_bitburner_basetask_md;
AllPages["nsDoc/bitburner.basetask.nextcompletion.md"] = nsDoc_bitburner_basetask_nextcompletion_md;
AllPages["nsDoc/bitburner.basichgwoptions.additionalmsec.md"] = nsDoc_bitburner_basichgwoptions_additionalmsec_md; AllPages["nsDoc/bitburner.basichgwoptions.additionalmsec.md"] = nsDoc_bitburner_basichgwoptions_additionalmsec_md;
AllPages["nsDoc/bitburner.basichgwoptions.md"] = nsDoc_bitburner_basichgwoptions_md; AllPages["nsDoc/bitburner.basichgwoptions.md"] = nsDoc_bitburner_basichgwoptions_md;
AllPages["nsDoc/bitburner.basichgwoptions.stock.md"] = nsDoc_bitburner_basichgwoptions_stock_md; AllPages["nsDoc/bitburner.basichgwoptions.stock.md"] = nsDoc_bitburner_basichgwoptions_stock_md;
@@ -2327,7 +2353,6 @@ AllPages["nsDoc/bitburner.grafting.graftaugmentation.md"] = nsDoc_bitburner_graf
AllPages["nsDoc/bitburner.grafting.md"] = nsDoc_bitburner_grafting_md; AllPages["nsDoc/bitburner.grafting.md"] = nsDoc_bitburner_grafting_md;
AllPages["nsDoc/bitburner.grafting.waitforongoinggrafting.md"] = nsDoc_bitburner_grafting_waitforongoinggrafting_md; AllPages["nsDoc/bitburner.grafting.waitforongoinggrafting.md"] = nsDoc_bitburner_grafting_waitforongoinggrafting_md;
AllPages["nsDoc/bitburner.graftingtask.augmentation.md"] = nsDoc_bitburner_graftingtask_augmentation_md; AllPages["nsDoc/bitburner.graftingtask.augmentation.md"] = nsDoc_bitburner_graftingtask_augmentation_md;
AllPages["nsDoc/bitburner.graftingtask.completion.md"] = nsDoc_bitburner_graftingtask_completion_md;
AllPages["nsDoc/bitburner.graftingtask.md"] = nsDoc_bitburner_graftingtask_md; AllPages["nsDoc/bitburner.graftingtask.md"] = nsDoc_bitburner_graftingtask_md;
AllPages["nsDoc/bitburner.graftingtask.type.md"] = nsDoc_bitburner_graftingtask_type_md; AllPages["nsDoc/bitburner.graftingtask.type.md"] = nsDoc_bitburner_graftingtask_type_md;
AllPages["nsDoc/bitburner.gymenumtype.md"] = nsDoc_bitburner_gymenumtype_md; AllPages["nsDoc/bitburner.gymenumtype.md"] = nsDoc_bitburner_gymenumtype_md;
@@ -2769,6 +2794,8 @@ AllPages["nsDoc/bitburner.player.md"] = nsDoc_bitburner_player_md;
AllPages["nsDoc/bitburner.player.money.md"] = nsDoc_bitburner_player_money_md; AllPages["nsDoc/bitburner.player.money.md"] = nsDoc_bitburner_player_money_md;
AllPages["nsDoc/bitburner.player.numpeoplekilled.md"] = nsDoc_bitburner_player_numpeoplekilled_md; AllPages["nsDoc/bitburner.player.numpeoplekilled.md"] = nsDoc_bitburner_player_numpeoplekilled_md;
AllPages["nsDoc/bitburner.player.totalplaytime.md"] = nsDoc_bitburner_player_totalplaytime_md; AllPages["nsDoc/bitburner.player.totalplaytime.md"] = nsDoc_bitburner_player_totalplaytime_md;
AllPages["nsDoc/bitburner.playerbasetask.cyclesworked.md"] = nsDoc_bitburner_playerbasetask_cyclesworked_md;
AllPages["nsDoc/bitburner.playerbasetask.md"] = nsDoc_bitburner_playerbasetask_md;
AllPages["nsDoc/bitburner.playerrequirement.md"] = nsDoc_bitburner_playerrequirement_md; AllPages["nsDoc/bitburner.playerrequirement.md"] = nsDoc_bitburner_playerrequirement_md;
AllPages["nsDoc/bitburner.positionenumtype.md"] = nsDoc_bitburner_positionenumtype_md; AllPages["nsDoc/bitburner.positionenumtype.md"] = nsDoc_bitburner_positionenumtype_md;
AllPages["nsDoc/bitburner.positiontype.md"] = nsDoc_bitburner_positiontype_md; AllPages["nsDoc/bitburner.positiontype.md"] = nsDoc_bitburner_positiontype_md;
@@ -2981,20 +3008,45 @@ AllPages["nsDoc/bitburner.sleeve.settosynchronize.md"] = nsDoc_bitburner_sleeve_
AllPages["nsDoc/bitburner.sleeve.settouniversitycourse.md"] = nsDoc_bitburner_sleeve_settouniversitycourse_md; AllPages["nsDoc/bitburner.sleeve.settouniversitycourse.md"] = nsDoc_bitburner_sleeve_settouniversitycourse_md;
AllPages["nsDoc/bitburner.sleeve.travel.md"] = nsDoc_bitburner_sleeve_travel_md; AllPages["nsDoc/bitburner.sleeve.travel.md"] = nsDoc_bitburner_sleeve_travel_md;
AllPages["nsDoc/bitburner.sleeve.upgradememory.md"] = nsDoc_bitburner_sleeve_upgradememory_md; AllPages["nsDoc/bitburner.sleeve.upgradememory.md"] = nsDoc_bitburner_sleeve_upgradememory_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.actionname.md"] = nsDoc_bitburner_sleevebladeburnertask_actionname_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.actiontype.md"] = nsDoc_bitburner_sleevebladeburnertask_actiontype_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.cyclesneeded.md"] = nsDoc_bitburner_sleevebladeburnertask_cyclesneeded_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.cyclesworked.md"] = nsDoc_bitburner_sleevebladeburnertask_cyclesworked_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.md"] = nsDoc_bitburner_sleevebladeburnertask_md; AllPages["nsDoc/bitburner.sleevebladeburnertask.md"] = nsDoc_bitburner_sleevebladeburnertask_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.taskscompleted.md"] = nsDoc_bitburner_sleevebladeburnertask_taskscompleted_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.type.md"] = nsDoc_bitburner_sleevebladeburnertask_type_md;
AllPages["nsDoc/bitburner.sleeveclasstask.classtype.md"] = nsDoc_bitburner_sleeveclasstask_classtype_md;
AllPages["nsDoc/bitburner.sleeveclasstask.location.md"] = nsDoc_bitburner_sleeveclasstask_location_md;
AllPages["nsDoc/bitburner.sleeveclasstask.md"] = nsDoc_bitburner_sleeveclasstask_md; AllPages["nsDoc/bitburner.sleeveclasstask.md"] = nsDoc_bitburner_sleeveclasstask_md;
AllPages["nsDoc/bitburner.sleeveclasstask.type.md"] = nsDoc_bitburner_sleeveclasstask_type_md;
AllPages["nsDoc/bitburner.sleevecompanytask.companyname.md"] = nsDoc_bitburner_sleevecompanytask_companyname_md;
AllPages["nsDoc/bitburner.sleevecompanytask.md"] = nsDoc_bitburner_sleevecompanytask_md; AllPages["nsDoc/bitburner.sleevecompanytask.md"] = nsDoc_bitburner_sleevecompanytask_md;
AllPages["nsDoc/bitburner.sleevecompanytask.type.md"] = nsDoc_bitburner_sleevecompanytask_type_md;
AllPages["nsDoc/bitburner.sleevecrimetask.crimetype.md"] = nsDoc_bitburner_sleevecrimetask_crimetype_md;
AllPages["nsDoc/bitburner.sleevecrimetask.cyclesneeded.md"] = nsDoc_bitburner_sleevecrimetask_cyclesneeded_md;
AllPages["nsDoc/bitburner.sleevecrimetask.cyclesworked.md"] = nsDoc_bitburner_sleevecrimetask_cyclesworked_md;
AllPages["nsDoc/bitburner.sleevecrimetask.md"] = nsDoc_bitburner_sleevecrimetask_md; AllPages["nsDoc/bitburner.sleevecrimetask.md"] = nsDoc_bitburner_sleevecrimetask_md;
AllPages["nsDoc/bitburner.sleevecrimetask.taskscompleted.md"] = nsDoc_bitburner_sleevecrimetask_taskscompleted_md;
AllPages["nsDoc/bitburner.sleevecrimetask.type.md"] = nsDoc_bitburner_sleevecrimetask_type_md;
AllPages["nsDoc/bitburner.sleevefactiontask.factionname.md"] = nsDoc_bitburner_sleevefactiontask_factionname_md;
AllPages["nsDoc/bitburner.sleevefactiontask.factionworktype.md"] = nsDoc_bitburner_sleevefactiontask_factionworktype_md;
AllPages["nsDoc/bitburner.sleevefactiontask.md"] = nsDoc_bitburner_sleevefactiontask_md; AllPages["nsDoc/bitburner.sleevefactiontask.md"] = nsDoc_bitburner_sleevefactiontask_md;
AllPages["nsDoc/bitburner.sleevefactiontask.type.md"] = nsDoc_bitburner_sleevefactiontask_type_md;
AllPages["nsDoc/bitburner.sleeveinfiltratetask.cyclesneeded.md"] = nsDoc_bitburner_sleeveinfiltratetask_cyclesneeded_md;
AllPages["nsDoc/bitburner.sleeveinfiltratetask.cyclesworked.md"] = nsDoc_bitburner_sleeveinfiltratetask_cyclesworked_md;
AllPages["nsDoc/bitburner.sleeveinfiltratetask.md"] = nsDoc_bitburner_sleeveinfiltratetask_md; AllPages["nsDoc/bitburner.sleeveinfiltratetask.md"] = nsDoc_bitburner_sleeveinfiltratetask_md;
AllPages["nsDoc/bitburner.sleeveinfiltratetask.type.md"] = nsDoc_bitburner_sleeveinfiltratetask_type_md;
AllPages["nsDoc/bitburner.sleeveperson.md"] = nsDoc_bitburner_sleeveperson_md; AllPages["nsDoc/bitburner.sleeveperson.md"] = nsDoc_bitburner_sleeveperson_md;
AllPages["nsDoc/bitburner.sleeveperson.memory.md"] = nsDoc_bitburner_sleeveperson_memory_md; AllPages["nsDoc/bitburner.sleeveperson.memory.md"] = nsDoc_bitburner_sleeveperson_memory_md;
AllPages["nsDoc/bitburner.sleeveperson.shock.md"] = nsDoc_bitburner_sleeveperson_shock_md; AllPages["nsDoc/bitburner.sleeveperson.shock.md"] = nsDoc_bitburner_sleeveperson_shock_md;
AllPages["nsDoc/bitburner.sleeveperson.storedcycles.md"] = nsDoc_bitburner_sleeveperson_storedcycles_md; AllPages["nsDoc/bitburner.sleeveperson.storedcycles.md"] = nsDoc_bitburner_sleeveperson_storedcycles_md;
AllPages["nsDoc/bitburner.sleeveperson.sync.md"] = nsDoc_bitburner_sleeveperson_sync_md; AllPages["nsDoc/bitburner.sleeveperson.sync.md"] = nsDoc_bitburner_sleeveperson_sync_md;
AllPages["nsDoc/bitburner.sleeverecoverytask.md"] = nsDoc_bitburner_sleeverecoverytask_md; AllPages["nsDoc/bitburner.sleeverecoverytask.md"] = nsDoc_bitburner_sleeverecoverytask_md;
AllPages["nsDoc/bitburner.sleeverecoverytask.type.md"] = nsDoc_bitburner_sleeverecoverytask_type_md;
AllPages["nsDoc/bitburner.sleevesupporttask.md"] = nsDoc_bitburner_sleevesupporttask_md; AllPages["nsDoc/bitburner.sleevesupporttask.md"] = nsDoc_bitburner_sleevesupporttask_md;
AllPages["nsDoc/bitburner.sleevesupporttask.type.md"] = nsDoc_bitburner_sleevesupporttask_type_md;
AllPages["nsDoc/bitburner.sleevesynchrotask.md"] = nsDoc_bitburner_sleevesynchrotask_md; AllPages["nsDoc/bitburner.sleevesynchrotask.md"] = nsDoc_bitburner_sleevesynchrotask_md;
AllPages["nsDoc/bitburner.sleevesynchrotask.type.md"] = nsDoc_bitburner_sleevesynchrotask_type_md;
AllPages["nsDoc/bitburner.sleevetask.md"] = nsDoc_bitburner_sleevetask_md; AllPages["nsDoc/bitburner.sleevetask.md"] = nsDoc_bitburner_sleevetask_md;
AllPages["nsDoc/bitburner.somerequirement.conditions.md"] = nsDoc_bitburner_somerequirement_conditions_md; AllPages["nsDoc/bitburner.somerequirement.conditions.md"] = nsDoc_bitburner_somerequirement_conditions_md;
AllPages["nsDoc/bitburner.somerequirement.md"] = nsDoc_bitburner_somerequirement_md; AllPages["nsDoc/bitburner.somerequirement.md"] = nsDoc_bitburner_somerequirement_md;
+34 -18
View File
@@ -4,6 +4,8 @@ import { TextField } from "@mui/material";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import InfoIcon from "@mui/icons-material/Info";
import { Player } from "@player"; import { Player } from "@player";
import { import {
@@ -24,6 +26,7 @@ export function ShareOption({ rerender }: { rerender: () => void }): React.React
const home = Player.getHomeComputer(); const home = Player.getHomeComputer();
const threads = Math.floor(ram / 4); const threads = Math.floor(ram / 4);
const ramUsage = roundToTwo(4 * threads);
function onShare(): void { function onShare(): void {
if (threads === 0) { if (threads === 0) {
@@ -34,7 +37,6 @@ export function ShareOption({ rerender }: { rerender: () => void }): React.React
return; return;
} }
const freeRAM = home.maxRam - home.ramUsed; const freeRAM = home.maxRam - home.ramUsed;
const ramUsage = roundToTwo(4 * threads);
if (ramUsage > freeRAM + 0.001) { if (ramUsage > freeRAM + 0.001) {
dialogBoxCreate("Not enough RAM."); dialogBoxCreate("Not enough RAM.");
return; return;
@@ -50,6 +52,7 @@ export function ShareOption({ rerender }: { rerender: () => void }): React.React
rerender(); rerender();
}, ShareBonusTime); }, ShareBonusTime);
pendingUIShareJobIds.push(jobId); pendingUIShareJobIds.push(jobId);
rerender();
} }
return ( return (
@@ -62,27 +65,40 @@ export function ShareOption({ rerender }: { rerender: () => void }): React.React
<br /> <br />
Free RAM on home computer: {formatRam(home.maxRam - home.ramUsed)}. Free RAM on home computer: {formatRam(home.maxRam - home.ramUsed)}.
<br /> <br />
Current bonus: {formatNumber(calculateCurrentShareBonus(), 6)}. Bonus with {formatRam(ram)}:{" "} Current bonus: {formatNumber(calculateCurrentShareBonus(), 6)}. Bonus with {formatRam(ramUsage)}:{" "}
{formatNumber(calculateShareBonusWithAdditionalThreads(threads, home.cpuCores), 6)} {formatNumber(calculateShareBonusWithAdditionalThreads(threads, home.cpuCores), 6)}
</Typography> </Typography>
<TextField <Typography component="div" style={{ display: "flex" }}>
value={ram} <TextField
onChange={(event) => { value={ram}
if (event.target.value === "") { onChange={(event) => {
setRam(0); if (event.target.value === "") {
return; setRam(0);
return;
}
const value = Number.parseFloat(event.target.value);
if (!Number.isFinite(value) || value < 0) {
return;
}
setRam(value);
}}
/>
<Tooltip
title={
<Typography>
RAM shared via this tool is rounded down to the nearest multiple of 4.
<br />
For example, a value of 18 GB results in 16 GB.
</Typography>
} }
const value = Number.parseFloat(event.target.value); >
if (!Number.isFinite(value) || value < 0) { <Typography component="div" style={{ display: "flex", alignItems: "center" }}>
return; <Button onClick={onShare}>Share</Button>
} <InfoIcon sx={{ fontSize: "1.5em", marginLeft: "10px" }} />
setRam(value); </Typography>
}} </Tooltip>
InputProps={{ </Typography>
endAdornment: <Button onClick={onShare}>Share</Button>,
}}
/>
</Paper> </Paper>
); );
} }
+25 -6
View File
@@ -9,6 +9,10 @@ import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab"; import Tab from "@mui/material/Tab";
import { useCycleRerender } from "../../ui/React/hooks"; import { useCycleRerender } from "../../ui/React/hooks";
import Button from "@mui/material/Button";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Factions } from "../../Faction/Factions";
/** React Component for all the gang stuff. */ /** React Component for all the gang stuff. */
export function GangRoot(): React.ReactElement { export function GangRoot(): React.ReactElement {
@@ -18,7 +22,7 @@ export function GangRoot(): React.ReactElement {
})(); })();
const [value, setValue] = React.useState(0); const [value, setValue] = React.useState(0);
function handleChange(event: React.SyntheticEvent, tab: number): void { function handleChange(__event: React.SyntheticEvent, tab: number): void {
setValue(tab); setValue(tab);
} }
@@ -26,11 +30,26 @@ export function GangRoot(): React.ReactElement {
return ( return (
<Context.Gang.Provider value={gang}> <Context.Gang.Provider value={gang}>
<Tabs variant="fullWidth" value={value} onChange={handleChange} sx={{ minWidth: "fit-content", maxWidth: "45%" }}> <div style={{ display: "flex" }}>
<Tab label="Management" /> <Tabs
<Tab label="Equipment" /> variant="fullWidth"
<Tab label="Territory" /> value={value}
</Tabs> onChange={handleChange}
sx={{ minWidth: "fit-content", maxWidth: "45%" }}
>
<Tab label="Management" />
<Tab label="Equipment" />
<Tab label="Territory" />
</Tabs>
<Button
style={{ marginLeft: "20px" }}
onClick={() => {
Router.toPage(Page.Faction, { faction: Factions[gang.facName] });
}}
>
Faction
</Button>
</div>
{value === 0 && <ManagementSubpage />} {value === 0 && <ManagementSubpage />}
{value === 1 && <EquipmentsSubpage />} {value === 1 && <EquipmentsSubpage />}
{value === 2 && <TerritorySubpage />} {value === 2 && <TerritorySubpage />}
+5 -5
View File
@@ -16,7 +16,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
return 0; return 0;
} }
if (startingLevel >= HacknetNodeConstants.MaxLevel) { if (startingLevel + sanitizedLevels > HacknetNodeConstants.MaxLevel) {
return Infinity; return Infinity;
} }
@@ -37,7 +37,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
return 0; return 0;
} }
if (startingRam >= HacknetNodeConstants.MaxRam) { if (startingRam * Math.pow(2, sanitizedLevels) > HacknetNodeConstants.MaxRam) {
return Infinity; return Infinity;
} }
@@ -60,20 +60,20 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
return totalCost; return totalCost;
} }
export function calculateCoreUpgradeCost(startingCore: number, extraLevels = 1, costMult = 1): number { export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1, costMult = 1): number {
const sanitizedCores = Math.round(extraLevels); const sanitizedCores = Math.round(extraLevels);
if (isNaN(sanitizedCores) || sanitizedCores < 1) { if (isNaN(sanitizedCores) || sanitizedCores < 1) {
return 0; return 0;
} }
if (startingCore >= HacknetNodeConstants.MaxCores) { if (startingCores + sanitizedCores > HacknetNodeConstants.MaxCores) {
return Infinity; return Infinity;
} }
const coreBaseCost = HacknetNodeConstants.CoreBaseCost; const coreBaseCost = HacknetNodeConstants.CoreBaseCost;
const mult = HacknetNodeConstants.UpgradeCoreMult; const mult = HacknetNodeConstants.UpgradeCoreMult;
let totalCost = 0; let totalCost = 0;
let currentCores = startingCore; let currentCores = startingCores;
for (let i = 0; i < sanitizedCores; ++i) { for (let i = 0; i < sanitizedCores; ++i) {
totalCost += coreBaseCost * Math.pow(mult, currentCores - 1); totalCost += coreBaseCost * Math.pow(mult, currentCores - 1);
++currentCores; ++currentCores;
+4 -4
View File
@@ -22,7 +22,7 @@ export function calculateLevelUpgradeCost(startingLevel: number, extraLevels = 1
return 0; return 0;
} }
if (startingLevel >= HacknetServerConstants.MaxLevel) { if (startingLevel + sanitizedLevels > HacknetServerConstants.MaxLevel) {
return Infinity; return Infinity;
} }
@@ -43,7 +43,7 @@ export function calculateRamUpgradeCost(startingRam: number, extraLevels = 1, co
return 0; return 0;
} }
if (startingRam >= HacknetServerConstants.MaxRam) { if (startingRam * Math.pow(2, sanitizedLevels) > HacknetServerConstants.MaxRam) {
return Infinity; return Infinity;
} }
@@ -70,7 +70,7 @@ export function calculateCoreUpgradeCost(startingCores: number, extraLevels = 1,
return 0; return 0;
} }
if (startingCores >= HacknetServerConstants.MaxCores) { if (startingCores + sanitizedLevels > HacknetServerConstants.MaxCores) {
return Infinity; return Infinity;
} }
@@ -93,7 +93,7 @@ export function calculateCacheUpgradeCost(startingCache: number, extraLevels = 1
return 0; return 0;
} }
if (startingCache >= HacknetServerConstants.MaxCache) { if (startingCache + sanitizedLevels > HacknetServerConstants.MaxCache) {
return Infinity; return Infinity;
} }
+1 -1
View File
@@ -48,7 +48,7 @@ function coloredArrow(difficulty: number): JSX.Element {
} else { } else {
return ( return (
<> <>
{arrowPart(Settings.theme.primary, cappedDifficulty * 13)} {arrowPart(Settings.theme.success, cappedDifficulty * 13)}
{arrowPart(Settings.theme.warning, (cappedDifficulty - 1) * 13)} {arrowPart(Settings.theme.warning, (cappedDifficulty - 1) * 13)}
{arrowPart(Settings.theme.warning, (cappedDifficulty - 2) * 13)} {arrowPart(Settings.theme.warning, (cappedDifficulty - 2) * 13)}
{arrowPart(Settings.theme.error, (cappedDifficulty - 3) * 26)} {arrowPart(Settings.theme.error, (cappedDifficulty - 3) * 26)}
+24 -24
View File
@@ -4,37 +4,37 @@ let pidCounter = 1;
/** Find and return the next available PID for a script */ /** Find and return the next available PID for a script */
export function generateNextPid(): number { export function generateNextPid(): number {
let tempCounter = pidCounter; let pidCandidate = pidCounter;
// Cap the number of search iterations at some arbitrary value to avoid // Cap the number of search iterations at some arbitrary value to avoid
// infinite loops. We'll assume that players wont have 1mil+ running scripts // infinite loops. We'll assume that players won't have a million running scripts.
let found = false; for (let attemptCounter = 0; attemptCounter < 1e6; ++attemptCounter, ++pidCandidate) {
for (let i = 0; i < 1e6; ) { // ensure the candidate PID is a safe integer
if (!workerScripts.has(tempCounter + i)) { if (pidCandidate >= Number.MAX_SAFE_INTEGER) {
found = true; pidCandidate = 1;
tempCounter = tempCounter + i;
break;
} }
// ensure the PID is not in use
if (i === Number.MAX_SAFE_INTEGER - 1) { if (workerScripts.has(pidCandidate)) {
i = 1; continue;
} else {
++i;
} }
// found a PID that's not in use
pidCounter = pidCandidate + 1;
return pidCandidate;
} }
// ran out of attempts without finding an unused PID :-(
if (found) { return -1;
pidCounter = tempCounter + 1;
if (pidCounter >= Number.MAX_SAFE_INTEGER) {
pidCounter = 1;
}
return tempCounter;
} else {
return -1;
}
} }
/**
* Reset the PID counter to 1.
*
* Note that the list of recently finished scripts has to be
* cleared (`recentScripts.splice(0)`) when resetting the PID counter.
* Otherwise scripts which re-use a PID that is still in the
* list of recent scripts do not show up there when they finish
* (if the previous script with that PID is still in the list at that point),
* because the function `AddRecentScript` de-duplicates scripts by PID.
*/
export function resetPidCounter(): void { export function resetPidCounter(): void {
pidCounter = 1; pidCounter = 1;
} }
+2 -2
View File
@@ -77,7 +77,7 @@ export const RamCostConstants = {
InfiltrationCalculateRewards: 2.5, InfiltrationCalculateRewards: 2.5,
InfiltrationGetInfiltrations: 15, InfiltrationGetInfiltrations: 15,
CycleTiming: 1, CycleTiming: 0,
} as const; } as const;
function SF4Cost(cost: number): () => number { function SF4Cost(cost: number): () => number {
@@ -461,7 +461,7 @@ const grafting = {
getAugmentationGraftTime: 3.75, getAugmentationGraftTime: 3.75,
getGraftableAugmentations: 5, getGraftableAugmentations: 5,
graftAugmentation: 7.5, graftAugmentation: 7.5,
waitForOngoingGrafting: 1, waitForOngoingGrafting: 0,
} as const; } as const;
const corporation = { const corporation = {
+7 -6
View File
@@ -16,7 +16,7 @@ import { helpers } from "../Netscript/NetscriptHelpers";
import { getEnumHelper } from "../utils/EnumHelper"; import { getEnumHelper } from "../utils/EnumHelper";
import { Skills } from "../Bladeburner/data/Skills"; import { Skills } from "../Bladeburner/data/Skills";
import { assertStringWithNSContext } from "../Netscript/TypeAssertion"; import { assertStringWithNSContext } from "../Netscript/TypeAssertion";
import { BlackOperations, blackOpsArray } from "../Bladeburner/data/BlackOperations"; import { numberOfBlackOperations } from "../Bladeburner/data/BlackOperations";
import { checkSleeveAPIAccess, checkSleeveNumber } from "../NetscriptFunctions/Sleeve"; import { checkSleeveAPIAccess, checkSleeveNumber } from "../NetscriptFunctions/Sleeve";
import { canAccessBitNodeFeature } from "../BitNode/BitNodeUtils"; import { canAccessBitNodeFeature } from "../BitNode/BitNodeUtils";
import { import {
@@ -81,20 +81,21 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
return Object.values(BladeburnerOperationName); return Object.values(BladeburnerOperationName);
}, },
getBlackOpNames: (ctx) => () => { getBlackOpNames: (ctx) => () => {
getBladeburner(ctx); const bladeburner = getBladeburner(ctx);
// Ensures they are sent in the correct order // Ensures they are sent in the correct order
return blackOpsArray.map((blackOp) => blackOp.name); return bladeburner.blackOperationArray.map((blackOp) => blackOp.name);
}, },
getNextBlackOp: (ctx) => () => { getNextBlackOp: (ctx) => () => {
const bladeburner = getBladeburner(ctx); const bladeburner = getBladeburner(ctx);
if (bladeburner.numBlackOpsComplete >= blackOpsArray.length) return null; if (bladeburner.numBlackOpsComplete >= numberOfBlackOperations) return null;
const blackOp = blackOpsArray[bladeburner.numBlackOpsComplete]; const blackOp = bladeburner.blackOperationArray[bladeburner.numBlackOpsComplete];
return { name: blackOp.name, rank: blackOp.reqdRank }; return { name: blackOp.name, rank: blackOp.reqdRank };
}, },
getBlackOpRank: (ctx) => (_blackOpName) => { getBlackOpRank: (ctx) => (_blackOpName) => {
checkBladeburnerAccess(ctx); checkBladeburnerAccess(ctx);
const blackOpName = getEnumHelper("BladeburnerBlackOpName").nsGetMember(ctx, _blackOpName); const blackOpName = getEnumHelper("BladeburnerBlackOpName").nsGetMember(ctx, _blackOpName);
return BlackOperations[blackOpName].reqdRank; const bladeburner = getBladeburner(ctx);
return bladeburner.blackOperations[blackOpName].reqdRank;
}, },
getGeneralActionNames: (ctx) => () => { getGeneralActionNames: (ctx) => () => {
getBladeburner(ctx); getBladeburner(ctx);
+1 -1
View File
@@ -107,7 +107,7 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
`The current work is not a grafting work. Type of current work: ${Player.currentWork.type}.`, `The current work is not a grafting work. Type of current work: ${Player.currentWork.type}.`,
); );
} }
return Player.currentWork.completion; return Player.currentWork.nextCompletion;
}, },
}; };
} }
+7 -2
View File
@@ -45,7 +45,7 @@ import { ScriptFilePath, resolveScriptFilePath } from "../Paths/ScriptFilePath";
import { getRecordEntries } from "../Types/Record"; import { getRecordEntries } from "../Types/Record";
import { JobTracks } from "../Company/data/JobTracks"; import { JobTracks } from "../Company/data/JobTracks";
import { ServerConstants } from "../Server/data/Constants"; import { ServerConstants } from "../Server/data/Constants";
import { blackOpsArray } from "../Bladeburner/data/BlackOperations"; import { numberOfBlackOperations } from "../Bladeburner/data/BlackOperations";
import { calculateEffectiveRequiredReputation } from "../Company/utils"; import { calculateEffectiveRequiredReputation } from "../Company/utils";
import { addRepToFavor } from "../Faction/formulas/favor"; import { addRepToFavor } from "../Faction/formulas/favor";
import { validBitNodes } from "../BitNode/Constants"; import { validBitNodes } from "../BitNode/Constants";
@@ -779,6 +779,11 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName); const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
if (Player.factions.includes(facName)) {
helpers.log(ctx, () => `You are already a member of faction '${facName}'`);
return false;
}
if (!Player.factionInvitations.includes(facName)) { if (!Player.factionInvitations.includes(facName)) {
helpers.log(ctx, () => `You have not been invited by faction '${facName}'`); helpers.log(ctx, () => `You have not been invited by faction '${facName}'`);
return false; return false;
@@ -1176,7 +1181,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
if (!Player.bladeburner) { if (!Player.bladeburner) {
return false; return false;
} }
return Player.bladeburner.numBlackOpsComplete >= blackOpsArray.length; return Player.bladeburner.numBlackOpsComplete >= numberOfBlackOperations;
}; };
if (!hackingRequirements() && !bladeburnerRequirements()) { if (!hackingRequirements() && !bladeburnerRequirements()) {
+13 -3
View File
@@ -27,7 +27,17 @@ export class Port {
resolver: Resolver | null = null; resolver: Resolver | null = null;
promise: Promise<void> | null = null; promise: Promise<void> | null = null;
add(data: unknown) { add(data: unknown) {
this.data.push(data); let value = data;
if (isObjectLike(data)) {
try {
value = structuredClone(data);
} catch (ex) {
throw new Error("You can't send Functions, Promises, NS, or other unserializable data through ports!", {
cause: ex,
});
}
}
this.data.push(value);
if (!this.resolver) return; if (!this.resolver) return;
this.resolver(); this.resolver();
this.resolver = null; this.resolver = null;
@@ -45,7 +55,7 @@ export class PortHandle implements NetscriptPort {
write(value: unknown): unknown { write(value: unknown): unknown {
const port = getPort(this.n); const port = getPort(this.n);
// Primitives don't need to be cloned. // Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value); port.add(value);
if (port.data.length > Settings.MaxPortCapacity) return port.data.shift(); if (port.data.length > Settings.MaxPortCapacity) return port.data.shift();
return null; return null;
} }
@@ -54,7 +64,7 @@ export class PortHandle implements NetscriptPort {
const port = getPort(this.n); const port = getPort(this.n);
if (port.data.length >= Settings.MaxPortCapacity) return false; if (port.data.length >= Settings.MaxPortCapacity) return false;
// Primitives don't need to be cloned. // Primitives don't need to be cloned.
port.add(isObjectLike(value) ? structuredClone(value) : value); port.add(value);
return true; return true;
} }
+11 -1
View File
@@ -147,6 +147,16 @@ export abstract class Person implements IPerson {
} }
overrideIntelligence(): void { overrideIntelligence(): void {
// Reset intelligence data if the player has not unlocked Intelligence.
// Note that this check cannot reset intelligence data in some edge cases (e.g., bitflume from non-BN5 to BN5). This
// is an accepted limitation.
// For more information, please check https://github.com/bitburner-official/bitburner-src/pull/2666
if (Player.sourceFileLvl(5) === 0 && Player.bitNodeN !== 5) {
this.skills.intelligence = 0;
this.exp.intelligence = 0;
this.persistentIntelligenceData.exp = 0;
return;
}
const persistentIntelligenceSkill = this.calculateSkill(this.persistentIntelligenceData.exp, 1); const persistentIntelligenceSkill = this.calculateSkill(this.persistentIntelligenceData.exp, 1);
// Reset exp and skill to the persistent values if there is no limit (intelligenceOverride) or the limit is greater // Reset exp and skill to the persistent values if there is no limit (intelligenceOverride) or the limit is greater
// than or equal to the persistent skill. // than or equal to the persistent skill.
@@ -172,7 +182,7 @@ export abstract class Person implements IPerson {
* Don't change sourceFileLvl to activeSourceFileLvl. When the player has int level, the ability to gain more int is * Don't change sourceFileLvl to activeSourceFileLvl. When the player has int level, the ability to gain more int is
* a permanent benefit. * a permanent benefit.
*/ */
if (Player.sourceFileLvl(5) > 0 || this.skills.intelligence > 0 || Player.bitNodeN === 5) { if (Player.sourceFileLvl(5) > 0 || Player.bitNodeN === 5) {
this.exp.intelligence += exp; this.exp.intelligence += exp;
this.skills.intelligence = Math.floor(this.calculateSkill(this.exp.intelligence, 1)); this.skills.intelligence = Math.floor(this.calculateSkill(this.exp.intelligence, 1));
this.persistentIntelligenceData.exp += exp; this.persistentIntelligenceData.exp += exp;
+2 -2
View File
@@ -7,7 +7,7 @@ import type { Exploit } from "../../Exploits/Exploit";
import type { Gang } from "../../Gang/Gang"; import type { Gang } from "../../Gang/Gang";
import type { HacknetNode } from "../../Hacknet/HacknetNode"; import type { HacknetNode } from "../../Hacknet/HacknetNode";
import type { Sleeve } from "../Sleeve/Sleeve"; import type { Sleeve } from "../Sleeve/Sleeve";
import type { Work } from "../../Work/Work"; import type { PlayerBaseWork } from "../../Work/Work";
import * as augmentationMethods from "./PlayerObjectAugmentationMethods"; import * as augmentationMethods from "./PlayerObjectAugmentationMethods";
import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods"; import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods";
@@ -73,7 +73,7 @@ export class PlayerObject extends Person implements IPlayer {
lastSave = 0; lastSave = 0;
totalPlaytime = 0; totalPlaytime = 0;
currentWork: Work | null = null; currentWork: PlayerBaseWork | null = null;
focus = false; focus = false;
entropy = 0; entropy = 0;
@@ -135,12 +135,14 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.hp.current = this.hp.max; this.hp.current = this.hp.max;
this.finishWork(true, true); this.finishWork(true, true);
// We need to call overrideIntelligence here instead of prestigeSourceFile to reset intelligence data when installing
// augmentations.
this.overrideIntelligence();
} }
export function prestigeSourceFile(this: PlayerObject): void { export function prestigeSourceFile(this: PlayerObject): void {
this.entropy = 0; this.entropy = 0;
this.prestigeAugmentation(); this.prestigeAugmentation();
this.overrideIntelligence();
this.karma = 0; this.karma = 0;
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists) // Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
this.sleeves.forEach((sleeve) => sleeve.prestige()); this.sleeves.forEach((sleeve) => sleeve.prestige());
@@ -1,8 +1,8 @@
import { Work } from "../../Work/Work"; import type { PlayerBaseWork } from "../../Work/Work";
import type { PlayerObject } from "./PlayerObject"; import type { PlayerObject } from "./PlayerObject";
export function startWork(this: PlayerObject, w: Work): void { export function startWork(this: PlayerObject, w: PlayerBaseWork): void {
if (this.currentWork !== null) { if (this.currentWork !== null) {
this.currentWork.finish(true); this.currentWork.finish(true);
} }
@@ -1,13 +1,11 @@
import type { Sleeve } from "../Sleeve"; import type { Sleeve } from "../Sleeve";
import type { ActionIdentifier } from "../../../Bladeburner/Types"; import type { ActionIdentifier } from "../../../Bladeburner/Types";
import type { PromisePair } from "../../../Types/Promises";
import { Player } from "@player"; import { Player } from "@player";
import { BladeburnerActionType, BladeburnerGeneralActionName } from "@enums"; import { BladeburnerActionType, BladeburnerGeneralActionName } from "@enums";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { applySleeveGains, SleeveWorkClass, SleeveWorkType } from "./Work"; import { applySleeveGains, SleeveBaseWork, SleeveWorkType } from "./Work";
import { CONSTANTS } from "../../../Constants"; import { CONSTANTS } from "../../../Constants";
import { scaleWorkStats } from "../../../Work/WorkStats"; import { scaleWorkStats } from "../../../Work/WorkStats";
import { getKeyList } from "../../../utils/helpers/getKeyList";
import { loadActionIdentifier } from "../../../Bladeburner/utils/loadActionIdentifier"; import { loadActionIdentifier } from "../../../Bladeburner/utils/loadActionIdentifier";
import { invalidWork } from "../../../Work/InvalidWork"; import { invalidWork } from "../../../Work/InvalidWork";
import { assertObject } from "../../../utils/TypeAssertion"; import { assertObject } from "../../../utils/TypeAssertion";
@@ -16,15 +14,14 @@ interface SleeveBladeburnerWorkParams {
actionId: ActionIdentifier & { type: BladeburnerActionType.General | BladeburnerActionType.Contract }; actionId: ActionIdentifier & { type: BladeburnerActionType.General | BladeburnerActionType.Contract };
} }
export const isSleeveBladeburnerWork = (w: SleeveWorkClass | null): w is SleeveBladeburnerWork => export const isSleeveBladeburnerWork = (w: SleeveBaseWork | null): w is SleeveBladeburnerWork =>
w?.type === SleeveWorkType.BLADEBURNER; w?.type === SleeveWorkType.BLADEBURNER;
export class SleeveBladeburnerWork extends SleeveWorkClass { export class SleeveBladeburnerWork extends SleeveBaseWork {
type: SleeveWorkType.BLADEBURNER = SleeveWorkType.BLADEBURNER; type: SleeveWorkType.BLADEBURNER = SleeveWorkType.BLADEBURNER;
tasksCompleted = 0; tasksCompleted = 0;
cyclesWorked = 0; cyclesWorked = 0;
actionId: ActionIdentifier & { type: BladeburnerActionType.General | BladeburnerActionType.Contract }; actionId: ActionIdentifier & { type: BladeburnerActionType.General | BladeburnerActionType.Contract };
nextCompletionPair: PromisePair<void> = { promise: null, resolve: null };
constructor(params?: SleeveBladeburnerWorkParams) { constructor(params?: SleeveBladeburnerWorkParams) {
super(); super();
@@ -41,14 +38,6 @@ export class SleeveBladeburnerWork extends SleeveWorkClass {
return timeInMs / CONSTANTS.MilliPerCycle; return timeInMs / CONSTANTS.MilliPerCycle;
} }
finish() {
if (this.nextCompletionPair.resolve) {
this.nextCompletionPair.resolve();
this.nextCompletionPair.resolve = null;
this.nextCompletionPair.promise = null;
}
}
process(sleeve: Sleeve, cycles: number) { process(sleeve: Sleeve, cycles: number) {
if (!Player.bladeburner) return sleeve.stopWork(); if (!Player.bladeburner) return sleeve.stopWork();
this.cyclesWorked += cycles; this.cyclesWorked += cycles;
@@ -67,17 +56,10 @@ export class SleeveBladeburnerWork extends SleeveWorkClass {
this.tasksCompleted++; this.tasksCompleted++;
this.cyclesWorked -= this.cyclesNeeded(sleeve); this.cyclesWorked -= this.cyclesNeeded(sleeve);
// Resolve and reset nextCompletion promise this.resolveNextCompletion();
this.finish();
} }
} }
get nextCompletion(): Promise<void> {
if (!this.nextCompletionPair.promise)
this.nextCompletionPair.promise = new Promise((r) => (this.nextCompletionPair.resolve = r));
return this.nextCompletionPair.promise;
}
APICopy(sleeve: Sleeve) { APICopy(sleeve: Sleeve) {
return { return {
type: SleeveWorkType.BLADEBURNER as const, type: SleeveWorkType.BLADEBURNER as const,
@@ -90,11 +72,9 @@ export class SleeveBladeburnerWork extends SleeveWorkClass {
}; };
} }
static savedKeys = getKeyList(SleeveBladeburnerWork, { removedKeys: ["nextCompletionPair"] });
/** Serialize the current object to a JSON save state. */ /** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue { toJSON(): IReviverValue {
return Generic_toJSON("SleeveBladeburnerWork", this, SleeveBladeburnerWork.savedKeys); return Generic_toJSON("SleeveBladeburnerWork", this);
} }
/** Initializes a BladeburnerWork object from a JSON save state. */ /** Initializes a BladeburnerWork object from a JSON save state. */
@@ -115,7 +95,7 @@ export class SleeveBladeburnerWork extends SleeveWorkClass {
} }
} }
value.data.actionId = actionId; value.data.actionId = actionId;
return Generic_fromJSON(SleeveBladeburnerWork, value.data, SleeveBladeburnerWork.savedKeys); return Generic_fromJSON(SleeveBladeburnerWork, value.data);
} }
} }
@@ -1,6 +1,6 @@
import { ClassType, LocationName, UniversityClassType } from "@enums"; import { ClassType, LocationName, UniversityClassType } from "@enums";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { applySleeveGains, SleeveWorkClass, SleeveWorkType } from "./Work"; import { applySleeveGains, SleeveBaseWork, SleeveWorkType } from "./Work";
import { Classes } from "../../../Work/ClassWork"; import { Classes } from "../../../Work/ClassWork";
import { calculateClassEarnings } from "../../../Work/Formulas"; import { calculateClassEarnings } from "../../../Work/Formulas";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
@@ -9,7 +9,7 @@ import { Locations } from "../../../Locations/Locations";
import { isMember } from "../../../utils/EnumHelper"; import { isMember } from "../../../utils/EnumHelper";
import { assertObject } from "../../../utils/TypeAssertion"; import { assertObject } from "../../../utils/TypeAssertion";
export const isSleeveClassWork = (w: SleeveWorkClass | null): w is SleeveClassWork => export const isSleeveClassWork = (w: SleeveBaseWork | null): w is SleeveClassWork =>
w !== null && w.type === SleeveWorkType.CLASS; w !== null && w.type === SleeveWorkType.CLASS;
interface ClassWorkParams { interface ClassWorkParams {
@@ -17,7 +17,7 @@ interface ClassWorkParams {
location: LocationName; location: LocationName;
} }
export class SleeveClassWork extends SleeveWorkClass { export class SleeveClassWork extends SleeveBaseWork {
type: SleeveWorkType.CLASS = SleeveWorkType.CLASS; type: SleeveWorkType.CLASS = SleeveWorkType.CLASS;
classType: ClassType; classType: ClassType;
location: LocationName; location: LocationName;
@@ -46,6 +46,7 @@ export class SleeveClassWork extends SleeveWorkClass {
type: SleeveWorkType.CLASS as const, type: SleeveWorkType.CLASS as const,
classType: this.classType, classType: this.classType,
location: this.location, location: this.location,
nextCompletion: this.nextCompletion,
}; };
} }
/** Serialize the current object to a JSON save state. */ /** Serialize the current object to a JSON save state. */
@@ -2,7 +2,7 @@ import { Player } from "@player";
import { CompanyName, JobName } from "@enums"; import { CompanyName, JobName } from "@enums";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { applySleeveGains, SleeveWorkClass, SleeveWorkType } from "./Work"; import { applySleeveGains, SleeveBaseWork, SleeveWorkType } from "./Work";
import { Companies } from "../../../Company/Companies"; import { Companies } from "../../../Company/Companies";
import { Company } from "../../../Company/Company"; import { Company } from "../../../Company/Company";
import { calculateCompanyWorkStats } from "../../../Work/Formulas"; import { calculateCompanyWorkStats } from "../../../Work/Formulas";
@@ -12,10 +12,10 @@ import { CompanyPositions } from "../../../Company/CompanyPositions";
import { isMember } from "../../../utils/EnumHelper"; import { isMember } from "../../../utils/EnumHelper";
import { invalidWork } from "../../../Work/InvalidWork"; import { invalidWork } from "../../../Work/InvalidWork";
export const isSleeveCompanyWork = (w: SleeveWorkClass | null): w is SleeveCompanyWork => export const isSleeveCompanyWork = (w: SleeveBaseWork | null): w is SleeveCompanyWork =>
w !== null && w.type === SleeveWorkType.COMPANY; w !== null && w.type === SleeveWorkType.COMPANY;
export class SleeveCompanyWork extends SleeveWorkClass { export class SleeveCompanyWork extends SleeveBaseWork {
type: SleeveWorkType.COMPANY = SleeveWorkType.COMPANY; type: SleeveWorkType.COMPANY = SleeveWorkType.COMPANY;
companyName: CompanyName; companyName: CompanyName;
@@ -51,6 +51,7 @@ export class SleeveCompanyWork extends SleeveWorkClass {
return { return {
type: SleeveWorkType.COMPANY as const, type: SleeveWorkType.COMPANY as const,
companyName: this.companyName, companyName: this.companyName,
nextCompletion: this.nextCompletion,
}; };
} }
@@ -1,7 +1,7 @@
import { Player } from "@player"; import { Player } from "@player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { applySleeveGains, SleeveWorkClass, SleeveWorkType } from "./Work"; import { applySleeveGains, SleeveBaseWork, SleeveWorkType } from "./Work";
import { CrimeType } from "@enums"; import { CrimeType } from "@enums";
import { Crimes } from "../../../Crime/Crimes"; import { Crimes } from "../../../Crime/Crimes";
import { Crime } from "../../../Crime/Crime"; import { Crime } from "../../../Crime/Crime";
@@ -9,10 +9,10 @@ import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { CONSTANTS } from "../../../Constants"; import { CONSTANTS } from "../../../Constants";
import { calculateCrimeWorkStats } from "../../../Work/Formulas"; import { calculateCrimeWorkStats } from "../../../Work/Formulas";
export const isSleeveCrimeWork = (w: SleeveWorkClass | null): w is SleeveCrimeWork => export const isSleeveCrimeWork = (w: SleeveBaseWork | null): w is SleeveCrimeWork =>
w !== null && w.type === SleeveWorkType.CRIME; w !== null && w.type === SleeveWorkType.CRIME;
export class SleeveCrimeWork extends SleeveWorkClass { export class SleeveCrimeWork extends SleeveBaseWork {
type: SleeveWorkType.CRIME = SleeveWorkType.CRIME; type: SleeveWorkType.CRIME = SleeveWorkType.CRIME;
crimeType: CrimeType; crimeType: CrimeType;
tasksCompleted = 0; tasksCompleted = 0;
@@ -49,6 +49,7 @@ export class SleeveCrimeWork extends SleeveWorkClass {
applySleeveGains(sleeve, gains, success ? 1 : 0.25); applySleeveGains(sleeve, gains, success ? 1 : 0.25);
this.tasksCompleted++; this.tasksCompleted++;
this.cyclesWorked -= this.cyclesNeeded(); this.cyclesWorked -= this.cyclesNeeded();
this.resolveNextCompletion();
} }
} }
@@ -59,6 +60,7 @@ export class SleeveCrimeWork extends SleeveWorkClass {
tasksCompleted: this.tasksCompleted, tasksCompleted: this.tasksCompleted,
cyclesWorked: this.cyclesWorked, cyclesWorked: this.cyclesWorked,
cyclesNeeded: this.cyclesNeeded(), cyclesNeeded: this.cyclesNeeded(),
nextCompletion: this.nextCompletion,
}; };
} }
@@ -1,7 +1,7 @@
import { Player } from "@player"; import { Player } from "@player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { applySleeveGains, SleeveWorkClass, SleeveWorkType } from "./Work"; import { applySleeveGains, SleeveBaseWork, SleeveWorkType } from "./Work";
import { FactionName, FactionWorkType } from "@enums"; import { FactionName, FactionWorkType } from "@enums";
import { Factions } from "../../../Faction/Factions"; import { Factions } from "../../../Faction/Factions";
import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas"; import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas";
@@ -14,10 +14,10 @@ interface SleeveFactionWorkParams {
factionName: FactionName; factionName: FactionName;
} }
export const isSleeveFactionWork = (w: SleeveWorkClass | null): w is SleeveFactionWork => export const isSleeveFactionWork = (w: SleeveBaseWork | null): w is SleeveFactionWork =>
w !== null && w.type === SleeveWorkType.FACTION; w !== null && w.type === SleeveWorkType.FACTION;
export class SleeveFactionWork extends SleeveWorkClass { export class SleeveFactionWork extends SleeveBaseWork {
type: SleeveWorkType.FACTION = SleeveWorkType.FACTION; type: SleeveWorkType.FACTION = SleeveWorkType.FACTION;
factionWorkType: FactionWorkType; factionWorkType: FactionWorkType;
factionName: FactionName; factionName: FactionName;
@@ -56,6 +56,7 @@ export class SleeveFactionWork extends SleeveWorkClass {
type: SleeveWorkType.FACTION as const, type: SleeveWorkType.FACTION as const,
factionWorkType: this.factionWorkType, factionWorkType: this.factionWorkType,
factionName: this.factionName, factionName: this.factionName,
nextCompletion: this.nextCompletion,
}; };
} }

Some files were not shown because too many files have changed in this diff Show More