mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-21 00:32:51 +02:00
Compare commits
42 Commits
63aa4d2a45
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 2aa5092d85 | |||
| a7409a01cc | |||
| a99109d9c7 | |||
| 95af138c39 | |||
| f5bbc26495 | |||
| f8ec7f4294 | |||
| c06c6590c9 | |||
| 45bce6e45e | |||
| c21d1f44b2 | |||
| 956e00f789 | |||
| c5536d252b | |||
| a99ca64455 | |||
| cb14655325 | |||
| 9ab3e0bcb4 | |||
| cc9144c01b | |||
| fb3fa00b3d | |||
| 8cbd6ff9e1 | |||
| 00a1bc2f6e | |||
| be6fcd206f | |||
| a6a112198e | |||
| 732aadb2d6 | |||
| 85c9ac0181 | |||
| e232f37550 | |||
| 6074721c59 | |||
| 09e46d757b | |||
| 5cb0d559df | |||
| 54287e5f7f | |||
| d25b1676ab | |||
| d6299becd6 | |||
| 19b137e2fb | |||
| ee2949418f | |||
| fbd7930ab2 | |||
| 8b3c7c13c5 | |||
| 996bb01075 | |||
| eb4e193fac | |||
| 0c39fc3720 | |||
| 44741a7795 | |||
| 2818969c8a | |||
| de9311f820 | |||
| 15d463d583 | |||
| 2819947378 | |||
| 48fad72b6a |
@@ -2,7 +2,17 @@ name: Build artifacts
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
git-sha:
|
||||||
|
description: "Commit SHA-1 to checkout"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
git-sha:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
@@ -13,6 +23,8 @@ jobs:
|
|||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.git-sha || inputs.git-sha || github.sha }}
|
||||||
- name: Use Node.js 24
|
- name: Use Node.js 24
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
@@ -46,6 +58,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.git-sha || inputs.git-sha || github.sha }}
|
||||||
- name: Use Node.js 24
|
- name: Use Node.js 24
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
@@ -77,6 +91,8 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.git-sha || inputs.git-sha || github.sha }}
|
||||||
- name: Use Node.js 24
|
- name: Use Node.js 24
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [ActiveFragment](./bitburner.activefragment.md) > [chargedEffect](./bitburner.activefragment.chargedeffect.md)
|
||||||
|
|
||||||
|
## ActiveFragment.chargedEffect property
|
||||||
|
|
||||||
|
This is the raw value of the modifier used to calculate the effect on your multipliers. It may not be a multiplier.
|
||||||
|
|
||||||
|
With fragments that increase a multiplier, this value is a multiplier. For example, with "+x% hacknet production" fragment, a value of 1.25 will multiply the "hacknet\_node\_money" multiplier by 1.25. The UI will show "+25% hacknet production".
|
||||||
|
|
||||||
|
With fragments that decrease a multiplier, you need to invert this value. For example, with "-x% cheaper hacknet costs" fragment, a value of 1.25 means the "hacknet\_node\_purchase\_cost" (and other relevant cost multipliers) will be multiplied by 0.8 (1 / 1.25). The UI will show "20% cheaper hacknet costs".
|
||||||
|
|
||||||
|
With booster fragments, this value is always 1. Booster fragments only boost non-booster fragments. They don't directly boost your multipliers.
|
||||||
|
|
||||||
|
**Signature:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
chargedEffect: number;
|
||||||
|
```
|
||||||
@@ -37,6 +37,31 @@ Description
|
|||||||
</th></tr></thead>
|
</th></tr></thead>
|
||||||
<tbody><tr><td>
|
<tbody><tr><td>
|
||||||
|
|
||||||
|
[chargedEffect](./bitburner.activefragment.chargedeffect.md)
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
number
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
This is the raw value of the modifier used to calculate the effect on your multipliers. It may not be a multiplier.
|
||||||
|
|
||||||
|
With fragments that increase a multiplier, this value is a multiplier. For example, with "+x% hacknet production" fragment, a value of 1.25 will multiply the "hacknet\_node\_money" multiplier by 1.25. The UI will show "+25% hacknet production".
|
||||||
|
|
||||||
|
With fragments that decrease a multiplier, you need to invert this value. For example, with "-x% cheaper hacknet costs" fragment, a value of 1.25 means the "hacknet\_node\_purchase\_cost" (and other relevant cost multipliers) will be multiplied by 0.8 (1 / 1.25). The UI will show "20% cheaper hacknet costs".
|
||||||
|
|
||||||
|
With booster fragments, this value is always 1. Booster fragments only boost non-booster fragments. They don't directly boost your multipliers.
|
||||||
|
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
<tr><td>
|
||||||
|
|
||||||
[highestCharge](./bitburner.activefragment.highestcharge.md)
|
[highestCharge](./bitburner.activefragment.highestcharge.md)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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:**
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,15 +1,15 @@
|
|||||||
<!-- 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) > [bitburner](./bitburner.md) > [Gang](./bitburner.gang.md) > [getOtherGangInformation](./bitburner.gang.getotherganginformation.md)
|
[Home](./index.md) > [bitburner](./bitburner.md) > [Gang](./bitburner.gang.md) > [getAllGangInformation](./bitburner.gang.getallganginformation.md)
|
||||||
|
|
||||||
## Gang.getOtherGangInformation() method
|
## Gang.getAllGangInformation() method
|
||||||
|
|
||||||
Get information about all gangs.
|
Get information about all gangs.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
getOtherGangInformation(): Record<string, GangOtherInfoObject>;
|
getAllGangInformation(): Record<string, GangOtherInfoObject>;
|
||||||
```
|
```
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
+11
-11
@@ -61,6 +61,17 @@ Check if you can recruit a new gang member.
|
|||||||
Create a gang.
|
Create a gang.
|
||||||
|
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
<tr><td>
|
||||||
|
|
||||||
|
[getAllGangInformation()](./bitburner.gang.getallganginformation.md)
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
Get information about all gangs.
|
||||||
|
|
||||||
|
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
|
|
||||||
@@ -182,17 +193,6 @@ Get information about a specific gang member.
|
|||||||
List all gang members.
|
List all gang members.
|
||||||
|
|
||||||
|
|
||||||
</td></tr>
|
|
||||||
<tr><td>
|
|
||||||
|
|
||||||
[getOtherGangInformation()](./bitburner.gang.getotherganginformation.md)
|
|
||||||
|
|
||||||
|
|
||||||
</td><td>
|
|
||||||
|
|
||||||
Get information about all gangs.
|
|
||||||
|
|
||||||
|
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,17 @@ Calculate hack percent for one thread. (Ex: 0.25 would steal 25% of the server's
|
|||||||
Calculate hack time.
|
Calculate hack time.
|
||||||
|
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
<tr><td>
|
||||||
|
|
||||||
|
[weakenEffect(threads, cores)](./bitburner.hackingformulas.weakeneffect.md)
|
||||||
|
|
||||||
|
|
||||||
|
</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 .
|
||||||
|
|
||||||
|
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [HackingFormulas](./bitburner.hackingformulas.md) > [weakenEffect](./bitburner.hackingformulas.weakeneffect.md)
|
||||||
|
|
||||||
|
## 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 .
|
||||||
|
|
||||||
|
**Signature:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
weakenEffect(threads: number, cores?: number): number;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
<table><thead><tr><th>
|
||||||
|
|
||||||
|
Parameter
|
||||||
|
|
||||||
|
|
||||||
|
</th><th>
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
|
||||||
|
</th><th>
|
||||||
|
|
||||||
|
Description
|
||||||
|
|
||||||
|
|
||||||
|
</th></tr></thead>
|
||||||
|
<tbody><tr><td>
|
||||||
|
|
||||||
|
threads
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
number
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
Number of threads running weaken.
|
||||||
|
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
<tr><td>
|
||||||
|
|
||||||
|
cores
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
number
|
||||||
|
|
||||||
|
|
||||||
|
</td><td>
|
||||||
|
|
||||||
|
_(Optional)_ Number of cores on the host server. Default 1.
|
||||||
|
|
||||||
|
|
||||||
|
</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
|
||||||
|
number
|
||||||
|
|
||||||
|
The security decrease amount.
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ Cost of upgrading the specified Hacknet Node's cache.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Cost of upgrading the specified Hacknet Node's number of cores.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns the cost of upgrading the number of cores of the specified Hacknet Node by n.
|
Returns the cost of upgrading the number of cores of the specified Hacknet Node by n.
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ Level of the upgrade.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ An array containing the available upgrades
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Cost of upgrading the specified Hacknet Node.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns the cost of upgrading the specified Hacknet Node by n levels.
|
Returns the cost of upgrading the specified Hacknet Node by n levels.
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ Object containing a variety of stats about the specified Hacknet Node.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns an object containing a variety of stats about the specified Hacknet Node.
|
Returns an object containing a variety of stats about the specified Hacknet Node.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Cost of purchasing a new Hacknet Node.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns the cost of purchasing a new Hacknet Node.
|
Returns the cost of purchasing a new Hacknet Node.
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Cost of upgrading the specified Hacknet Node's RAM.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns the cost of upgrading the RAM of the specified Hacknet Node n times.
|
Returns the cost of upgrading the RAM of the specified Hacknet Node n times.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Multiplier.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Multiplier.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Number of hashes you can store.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Number of hashes required for the specified upgrade.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ Maximum number of hacknet nodes.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Number of hashes you have.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Number of hacknet nodes.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Returns the number of Hacknet Nodes you own.
|
Returns the number of Hacknet Nodes you own.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ The index of the Hacknet Node or if the player cannot afford to purchase a new H
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number at the end of the Hacknet Node’s name (e.g. The Hacknet Node named `hacknet-node-4` will have an index of 4).
|
Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number at the end of the Hacknet Node’s name (e.g. The Hacknet Node named `hacknet-node-4` will have an index of 4).
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ True if the upgrade is successfully purchased, and false otherwise.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ True if the Hacknet Node’s cache level is successfully upgraded, false otherwi
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ True if the Hacknet Node’s cores are successfully purchased, false otherwise.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Tries to purchase n cores for the specified Hacknet Node.
|
Tries to purchase n cores for the specified Hacknet Node.
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ True if the Hacknet Node’s level is successfully upgraded, false otherwise.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Tries to upgrade the level of the specified Hacknet Node by n.
|
Tries to upgrade the level of the specified Hacknet Node by n.
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ True if the Hacknet Node’s RAM is successfully upgraded, false otherwise.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
RAM cost: 0 GB
|
RAM cost: 0.5 GB
|
||||||
|
|
||||||
Tries to upgrade the specified Hacknet Node’s RAM n times. Note that each upgrade doubles the Node’s RAM. So this is equivalent to multiplying the Node’s RAM by 2 n.
|
Tries to upgrade the specified Hacknet Node’s RAM n times. Note that each upgrade doubles the Node’s RAM. So this is equivalent to multiplying the Node’s RAM by 2 n.
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -6,18 +6,14 @@
|
|||||||
|
|
||||||
Arguments passed into the script.
|
Arguments passed into the script.
|
||||||
|
|
||||||
|
These arguments can be accessed as a normal array by using the `[]` operator (`args[0]`<!-- -->, `args[1]`<!-- -->, etc...). Arguments can be string, number, or boolean. Use `args.length` to get the number of arguments that were passed into a script.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
readonly args: ScriptArg[];
|
readonly args: ScriptArg[];
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
Arguments passed into a script can be accessed as a normal array by using the `[]` operator (`args[0]`<!-- -->, `args[1]`<!-- -->, etc...). Arguments can be string, number, or boolean. Use `args.length` to get the number of arguments that were passed into a script.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
`run example.js 7 text true`
|
`run example.js 7 text true`
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [Bladeburner](./bitburner.bladeburner.md) functions. Contains spoi
|
|||||||
```typescript
|
```typescript
|
||||||
readonly bladeburner: Bladeburner;
|
readonly bladeburner: Bladeburner;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [cloud](./bitburner.cloud.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly cloud: Cloud;
|
readonly cloud: Cloud;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [coding contract](./bitburner.codingcontract.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly codingcontract: CodingContract;
|
readonly codingcontract: CodingContract;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [corporation](./bitburner.corporation.md) functions. Contains spoi
|
|||||||
```typescript
|
```typescript
|
||||||
readonly corporation: Corporation;
|
readonly corporation: Corporation;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for darknet functions. Contains spoilers.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly dnet: Darknet;
|
readonly dnet: Darknet;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -132,4 +132,5 @@ ns.exec("generic-hack.js", "joesguns", {threads: 10});
|
|||||||
// arguments to the script.
|
// arguments to the script.
|
||||||
ns.exec("foo.js", "foodnstuff", 5, 1, "test");
|
ns.exec("foo.js", "foodnstuff", 5, 1, "test");
|
||||||
```
|
```
|
||||||
|
For darknet servers: A session must be established with the target server, and the script must be running on a server that is directly connected to the target, or the target must have a backdoor or stasis link installed.
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [formatting](./bitburner.format.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly format: Format;
|
readonly format: Format;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [formulas](./bitburner.formulas.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly formulas: Formulas;
|
readonly formulas: Formulas;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [gang](./bitburner.gang.md) functions. Contains spoilers.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly gang: Gang;
|
readonly gang: Gang;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [Go](./bitburner.go.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly go: Go;
|
readonly go: Go;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [grafting](./bitburner.grafting.md) functions. Contains spoilers.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly grafting: Grafting;
|
readonly grafting: Grafting;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [hacknet](./bitburner.hacknet.md) functions. Some of this API cont
|
|||||||
```typescript
|
```typescript
|
||||||
readonly hacknet: Hacknet;
|
readonly hacknet: Hacknet;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 4 GB.
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [infiltration](./bitburner.infiltration.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly infiltration: Infiltration;
|
readonly infiltration: Infiltration;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ Description
|
|||||||
|
|
||||||
Arguments passed into the script.
|
Arguments passed into the script.
|
||||||
|
|
||||||
|
These arguments can be accessed as a normal array by using the `[]` operator (`args[0]`<!-- -->, `args[1]`<!-- -->, etc...). Arguments can be string, number, or boolean. Use `args.length` to get the number of arguments that were passed into a script.
|
||||||
|
|
||||||
|
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td>
|
<tr><td>
|
||||||
|
|||||||
@@ -112,5 +112,5 @@ const server = ns.args[0];
|
|||||||
const files = ["hack.js", "weaken.js", "grow.js"];
|
const files = ["hack.js", "weaken.js", "grow.js"];
|
||||||
ns.scp(files, server, "home");
|
ns.scp(files, server, "home");
|
||||||
```
|
```
|
||||||
For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. (The source server does not require a session.)
|
For darknet servers: The destination requires a session, but unlike [exec](./bitburner.ns.exec.md)<!-- -->, does not require a direct connection — scp works at any distance. The source server has no darknet requirements (no session or connection needed). Use [dnet.authenticate](./bitburner.darknet.authenticate.md) (requires direct connection) or [dnet.connectToSession](./bitburner.darknet.connecttosession.md) (at any distance) to establish a session.
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [singularity](./bitburner.singularity.md) functions. Contains spoi
|
|||||||
```typescript
|
```typescript
|
||||||
readonly singularity: Singularity;
|
readonly singularity: Singularity;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [sleeve](./bitburner.sleeve.md) functions. Contains spoilers.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly sleeve: Sleeve;
|
readonly sleeve: Sleeve;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [Stanek](./bitburner.stanek.md) functions. Contains spoilers.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly stanek: Stanek;
|
readonly stanek: Stanek;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [stock](./bitburner.stock.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly stock: Stock;
|
readonly stock: Stock;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,3 @@ Namespace for [user interface](./bitburner.userinterface.md) functions.
|
|||||||
```typescript
|
```typescript
|
||||||
readonly ui: UserInterface;
|
readonly ui: UserInterface;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
RAM cost: 0 GB
|
|
||||||
|
|
||||||
|
|||||||
@@ -454,7 +454,7 @@
|
|||||||
"CHALLENGE_BN9": {
|
"CHALLENGE_BN9": {
|
||||||
"ID": "CHALLENGE_BN9",
|
"ID": "CHALLENGE_BN9",
|
||||||
"Name": "BN9: Challenge",
|
"Name": "BN9: Challenge",
|
||||||
"Description": "Destroy BN9 without using hacknet servers."
|
"Description": "Destroy BN9 without using hacknet servers or hacknet nodes."
|
||||||
},
|
},
|
||||||
"CHALLENGE_BN10": {
|
"CHALLENGE_BN10": {
|
||||||
"ID": "CHALLENGE_BN10",
|
"ID": "CHALLENGE_BN10",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+2
-2
@@ -93,7 +93,7 @@ function applyAliases(origCommand: string, depth = 0, currentlyProcessingAliases
|
|||||||
// First get non-global aliases, and recursively apply them
|
// First get non-global aliases, and recursively apply them
|
||||||
// (unless there are any reference loops or the reference chain is too deep)
|
// (unless there are any reference loops or the reference chain is too deep)
|
||||||
const localAlias = Aliases.get(commandArray[0]);
|
const localAlias = Aliases.get(commandArray[0]);
|
||||||
if (localAlias && !currentlyProcessingAliases.includes(localAlias)) {
|
if (localAlias && !currentlyProcessingAliases.includes(commandArray[0])) {
|
||||||
const appliedAlias = applyAliases(localAlias, depth + 1, [commandArray[0], ...currentlyProcessingAliases]);
|
const appliedAlias = applyAliases(localAlias, depth + 1, [commandArray[0], ...currentlyProcessingAliases]);
|
||||||
commandArray.splice(0, 1, ...appliedAlias.split(" "));
|
commandArray.splice(0, 1, ...appliedAlias.split(" "));
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ function applyAliases(origCommand: string, depth = 0, currentlyProcessingAliases
|
|||||||
// Once local aliasing is complete (or if none are present) handle any global aliases
|
// Once local aliasing is complete (or if none are present) handle any global aliases
|
||||||
const processedCommands = commandArray.reduce((resolvedCommandArray: string[], command) => {
|
const processedCommands = commandArray.reduce((resolvedCommandArray: string[], command) => {
|
||||||
const globalAlias = GlobalAliases.get(command);
|
const globalAlias = GlobalAliases.get(command);
|
||||||
if (globalAlias && !currentlyProcessingAliases.includes(globalAlias)) {
|
if (globalAlias && !currentlyProcessingAliases.includes(command)) {
|
||||||
const appliedAlias = applyAliases(globalAlias, depth + 1, [command, ...currentlyProcessingAliases]);
|
const appliedAlias = applyAliases(globalAlias, depth + 1, [command, ...currentlyProcessingAliases]);
|
||||||
resolvedCommandArray.push(appliedAlias);
|
resolvedCommandArray.push(appliedAlias);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -93,3 +93,12 @@ export function finishBitNode() {
|
|||||||
}
|
}
|
||||||
wd.backdoorInstalled = true;
|
wd.backdoorInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BitNode level is not something that is stored, but rather calculated from the current BN and SF level. The concept
|
||||||
|
* appeared because saying "Enter BN1.2" is shorter than saying "Enter BN1 with SF1.1". This is how we display it in the
|
||||||
|
* BitVerse UI and other places. This function is used to consistently calculate this "level".
|
||||||
|
*/
|
||||||
|
export function getBitNodeLevel(bn = Player.bitNodeN, sfLevel = Player.activeSourceFileLvl(bn)): number {
|
||||||
|
return Math.min(sfLevel + 1, bn === 12 ? Number.MAX_VALUE : 3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { StatsRow } from "../../ui/React/StatsRow";
|
|||||||
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
|
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
|
||||||
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../BitNodeMultipliers";
|
||||||
import { PartialRecord, getRecordEntries } from "../../Types/Record";
|
import { PartialRecord, getRecordEntries } from "../../Types/Record";
|
||||||
import { canAccessBitNodeFeature } from "../BitNodeUtils";
|
import { canAccessBitNodeFeature, getBitNodeLevel } from "../BitNodeUtils";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
n: number;
|
n: number;
|
||||||
@@ -56,8 +56,7 @@ export const BitNodeMultipliersDisplay = ({ n, level, hideMultsIfCannotAccessFea
|
|||||||
// If not, then we have to assume that we want the next level up from the
|
// If not, then we have to assume that we want the next level up from the
|
||||||
// current node's source file, so we get the min of that, the SF's max level,
|
// current node's source file, so we get the min of that, the SF's max level,
|
||||||
// or if it's BN12, ∞
|
// or if it's BN12, ∞
|
||||||
const maxSfLevel = n === 12 ? Number.MAX_VALUE : 3;
|
const mults = getBitNodeMultipliers(n, level ?? getBitNodeLevel(n));
|
||||||
const mults = getBitNodeMultipliers(n, level ?? Math.min(Player.activeSourceFileLvl(n) + 1, maxSfLevel));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ columnCount: 2, columnGap: 1, mb: n === 1 ? 0 : -2 }}>
|
<Box sx={{ columnCount: 2, columnGap: 1, mb: n === 1 ? 0 : -2 }}>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Button from "@mui/material/Button";
|
|||||||
import { BitNodeMultiplierDescription } from "./BitnodeMultipliersDescription";
|
import { BitNodeMultiplierDescription } from "./BitnodeMultipliersDescription";
|
||||||
import { BitNodeAdvancedOptions } from "./BitNodeAdvancedOptions";
|
import { BitNodeAdvancedOptions } from "./BitNodeAdvancedOptions";
|
||||||
import { JSONMap } from "../../Types/Jsonable";
|
import { JSONMap } from "../../Types/Jsonable";
|
||||||
|
import { getBitNodeLevel } from "../BitNodeUtils";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -37,7 +38,7 @@ export function PortalModal(props: IProps): React.ReactElement {
|
|||||||
const bitNode = BitNodes[bitNodeKey];
|
const bitNode = BitNodes[bitNodeKey];
|
||||||
if (bitNode == null) throw new Error(`Could not find BitNode object for number: ${props.n}`);
|
if (bitNode == null) throw new Error(`Could not find BitNode object for number: ${props.n}`);
|
||||||
const maxSourceFileLevel = props.n === 12 ? "∞" : "3";
|
const maxSourceFileLevel = props.n === 12 ? "∞" : "3";
|
||||||
const newLevel = Math.min(props.level + 1, props.n === 12 ? Number.MAX_VALUE : 3);
|
const newLevel = getBitNodeLevel(props.n, props.level);
|
||||||
|
|
||||||
let currentSourceFiles = new Map(Player.sourceFiles);
|
let currentSourceFiles = new Map(Player.sourceFiles);
|
||||||
if (!props.flume) {
|
if (!props.flume) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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];
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Bladeburner } from "../Bladeburner";
|
|||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { CopyableText } from "../../ui/React/CopyableText";
|
import { CopyableText } from "../../ui/React/CopyableText";
|
||||||
import { formatBigNumber } from "../../ui/formatNumber";
|
import { formatBigNumber } from "../../ui/formatNumber";
|
||||||
import { Box, IconButton, Paper, Typography } from "@mui/material";
|
import { Box, IconButton, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { Skill } from "../Skill";
|
import { Skill } from "../Skill";
|
||||||
@@ -18,10 +18,8 @@ export function SkillElem({ skill, bladeburner, onUpgrade }: SkillElemProps): Re
|
|||||||
const skillName = skill.name;
|
const skillName = skill.name;
|
||||||
const skillLevel = bladeburner.getSkillLevel(skillName);
|
const skillLevel = bladeburner.getSkillLevel(skillName);
|
||||||
const pointCost = useMemo(() => skill.calculateCost(skillLevel), [skill, skillLevel]);
|
const pointCost = useMemo(() => skill.calculateCost(skillLevel), [skill, skillLevel]);
|
||||||
// No need to support "+1" button when the skill level reaches Number.MAX_SAFE_INTEGER.
|
|
||||||
const isSupported = skillLevel < Number.MAX_SAFE_INTEGER;
|
|
||||||
// Use skill.canUpgrade() instead of reimplementing all conditional checks.
|
// Use skill.canUpgrade() instead of reimplementing all conditional checks.
|
||||||
const canLevel = isSupported && skill.canUpgrade(bladeburner, 1).available;
|
const check = skill.canUpgrade(bladeburner, 1);
|
||||||
/**
|
/**
|
||||||
* maxLvl is only useful when we check if we should show "MAX LEVEL". For the check of the icon button, we don't need
|
* maxLvl is only useful when we check if we should show "MAX LEVEL". For the check of the icon button, we don't need
|
||||||
* it. This condition is checked in skill.canUpgrade().
|
* it. This condition is checked in skill.canUpgrade().
|
||||||
@@ -37,10 +35,14 @@ export function SkillElem({ skill, bladeburner, onUpgrade }: SkillElemProps): Re
|
|||||||
<Paper sx={{ my: 1, p: 1 }}>
|
<Paper sx={{ my: 1, p: 1 }}>
|
||||||
<Box display="flex" flexDirection="row" alignItems="center">
|
<Box display="flex" flexDirection="row" alignItems="center">
|
||||||
<CopyableText variant="h6" color="primary" value={skillName} />
|
<CopyableText variant="h6" color="primary" value={skillName} />
|
||||||
{!canLevel ? (
|
{!check.available ? (
|
||||||
<IconButton disabled>
|
<Tooltip title={check.error}>
|
||||||
<CloseIcon />
|
<span>
|
||||||
</IconButton>
|
<IconButton disabled>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<IconButton onClick={onClick}>
|
<IconButton onClick={onClick}>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
@@ -51,7 +53,7 @@ export function SkillElem({ skill, bladeburner, onUpgrade }: SkillElemProps): Re
|
|||||||
{maxLvl ? (
|
{maxLvl ? (
|
||||||
<Typography>MAX LEVEL</Typography>
|
<Typography>MAX LEVEL</Typography>
|
||||||
) : (
|
) : (
|
||||||
<Typography>Skill Points required: {isSupported ? formatBigNumber(pointCost) : "N/A"}</Typography>
|
<Typography>Skill Points required: {formatBigNumber(pointCost)}</Typography>
|
||||||
)}
|
)}
|
||||||
<Typography>{skill.desc}</Typography>
|
<Typography>{skill.desc}</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
+95
-2
@@ -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: 47,
|
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
|
||||||
|
|
||||||
@@ -140,6 +140,10 @@ export const CONSTANTS = {
|
|||||||
- Generate test contracts on executing host by default. Add support for optional parameter to specify the server (#2417) (@1337JiveTurkey)
|
- Generate test contracts on executing host by default. Add support for optional parameter to specify the server (#2417) (@1337JiveTurkey)
|
||||||
- The "darkweb" server becomes a darknet server (Check new Dark Net feature in #2139) (@ficocelliguy)
|
- The "darkweb" server becomes a darknet server (Check new Dark Net feature in #2139) (@ficocelliguy)
|
||||||
- Remove RAM cost of hacknet namespace and set RAM cost of each hacknet API (#2502) (@catloversg)
|
- Remove RAM cost of hacknet namespace and set RAM cost of each hacknet API (#2502) (@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 implicit string conversion consistent across all coding contracts (#2608) (@catloversg)
|
||||||
|
- Rename ns.gang.getOtherGangInformation to getAllGangInformation (#2635) (@lstutzman)
|
||||||
|
|
||||||
### MAJOR CHANGES
|
### MAJOR CHANGES
|
||||||
|
|
||||||
@@ -209,6 +213,22 @@ export const CONSTANTS = {
|
|||||||
- Improve navigation system of in-game documentation viewer (#2499) (@catloversg)
|
- Improve navigation system of in-game documentation viewer (#2499) (@catloversg)
|
||||||
- Use font family setting when rendering MUI Link component (#2511) (@catloversg)
|
- Use font family setting when rendering MUI Link component (#2511) (@catloversg)
|
||||||
- Show hints of BitNode documentation and allow opening it in BitVerse (#2513) (@catloversg)
|
- Show hints of BitNode documentation and allow opening it in BitVerse (#2513) (@catloversg)
|
||||||
|
- Show errors if using nano/vim with patterns that do not match any files (#2515) (@catloversg)
|
||||||
|
- Tweak CSS/Position of Darknet Docs link (#2517) (@d0sboots)
|
||||||
|
- Add indicator of RFA connection status to overview panel (#2497) (@catloversg)
|
||||||
|
- Fix issues with RFA auto-reconnecting feature (#2535) (@catloversg)
|
||||||
|
- Add inline script RAM usage text to each active script (#2546) (@vadien)
|
||||||
|
- Update toolbar of in-game editor (#2551) (@catloversg)
|
||||||
|
- Show "undefined" instead of -1 as pid in error popup when catching promise errors (#2555) (@catloversg)
|
||||||
|
- Add option to autosave scripts on focus change (#2565) (@catloversg)
|
||||||
|
- Prevent joining banned factions via UI (#2573) (@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)
|
||||||
|
- 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
|
||||||
|
|
||||||
@@ -291,6 +311,31 @@ export const CONSTANTS = {
|
|||||||
- More fixes and feedback in darknet (#2489) (@ficocelliguy)
|
- More fixes and feedback in darknet (#2489) (@ficocelliguy)
|
||||||
- Fix missed cases in offline server handling (#2495) (@d0sboots)
|
- Fix missed cases in offline server handling (#2495) (@d0sboots)
|
||||||
- Adjust darknet balance from player feedback (#2512) (@ficocelliguy)
|
- Adjust darknet balance from player feedback (#2512) (@ficocelliguy)
|
||||||
|
- Add "Find Largest Rectangle in a Matrix" coding contract (#2519) (@Misha279-UA)
|
||||||
|
- Tweak Dnet based on player feedback (#2533, #2545, #2593) (@ficocelliguy)
|
||||||
|
- Allow parsing unknown options with data.flags in autocomplete (#2539) (@catloversg)
|
||||||
|
- Fix webstorm by using a mutationLock (#2542) (@d0sboots)
|
||||||
|
- Print error message when calling ns.ui.closeTail with nonexistent pid or pid of stopped scripts (#2557) (@catloversg)
|
||||||
|
- Add minimum width/height constraints to ns.ui.resizeTail (#2558) (@catloversg)
|
||||||
|
- Add API to minimize and expand tail windows (#2556) (@catloversg)
|
||||||
|
- Improve error messages for invalid sleeve numbers (#2567) (@catloversg)
|
||||||
|
- Improve help text of expr command (#2561) (@catloversg)
|
||||||
|
- Rework faction rumor (#2569) (@catloversg)
|
||||||
|
- Fix: hacknetNodeCost formula API throws when using documented optional parameter (#2577) (@catloversg)
|
||||||
|
- Rework intelligence override (#2575) (@catloversg)
|
||||||
|
- Electron: Allow opening dev tools via CLI arguments (#2589) (@catloversg)
|
||||||
|
- Support importing Steam Cloud save file manually (#2583) (@catloversg)
|
||||||
|
- Electron: Add UI menus and CLI flags to change log levels (#2596) (@catloversg)
|
||||||
|
- Import correct cloud file when multiple exist (#2599) (@catloversg)
|
||||||
|
- Dnet: Remove packet capture (#2594) (@ficocelliguy)
|
||||||
|
- Generate more frequent and lower-reward coding contracts (#2603) (@ficocelliguy)
|
||||||
|
- 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
|
||||||
|
|
||||||
@@ -336,6 +381,17 @@ export const CONSTANTS = {
|
|||||||
- Add a note to CONTRIBUTING.md about the npm peer dep issue (#2474) (@d0sboots)
|
- Add a note to CONTRIBUTING.md about the npm peer dep issue (#2474) (@d0sboots)
|
||||||
- Update darknet documentation (#2483) (@ficocelliguy)
|
- Update darknet documentation (#2483) (@ficocelliguy)
|
||||||
- Fix invalid links in ns.sleep and ns.asleep (#2496) (@catloversg)
|
- Fix invalid links in ns.sleep and ns.asleep (#2496) (@catloversg)
|
||||||
|
- Use relative links instead of absolute links (#2521) (@catloversg)
|
||||||
|
- Document quirky behavior of ns.flags when default value is nullish (#2528) (@catloversg)
|
||||||
|
- Clarify how share power affects reputation gain rate of non-hacking work (#2544) (@catloversg)
|
||||||
|
- Update guides (#2550) (@catloversg)
|
||||||
|
- Add missing newline after RAM cost (#2570) (@catloversg)
|
||||||
|
- Update mention of outdated getStockForecast API (#2578) (@catloversg)
|
||||||
|
- Fix newline issues in IPvGO docs and add missing RAM cost (#2602) (@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
|
||||||
|
|
||||||
@@ -344,6 +400,11 @@ export const CONSTANTS = {
|
|||||||
- Fix: Bladeburner console prints main body's HP instead of sleeve's HP (#2390) (@catloversg)
|
- Fix: Bladeburner console prints main body's HP instead of sleeve's HP (#2390) (@catloversg)
|
||||||
- Reduce threshold of showing warning of low population (#2450) (@catloversg)
|
- Reduce threshold of showing warning of low population (#2450) (@catloversg)
|
||||||
- Fix: Hacknet server UI shows NaN hash rate when 100% RAM is being used (#2500) (@catloversg)
|
- Fix: Hacknet server UI shows NaN hash rate when 100% RAM is being used (#2500) (@catloversg)
|
||||||
|
- Prevent ending BNs through reuse of Bladeburner UI event handler (#2574) (@catloversg)
|
||||||
|
- Always show Black Operations list (#2592) (@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
|
||||||
|
|
||||||
@@ -366,6 +427,14 @@ export const CONSTANTS = {
|
|||||||
- Fix: Sleeves can earn exp and purchase augmentations when enabling disableSleeveExpAndAugmentation (#2467) (@catloversg)
|
- Fix: Sleeves can earn exp and purchase augmentations when enabling disableSleeveExpAndAugmentation (#2467) (@catloversg)
|
||||||
- Add improved challenge achievement for BN15 (#2479) (@ficocelliguy)
|
- Add improved challenge achievement for BN15 (#2479) (@ficocelliguy)
|
||||||
- Stop randomizing Bladeburner's action difficulty (#2491) (@catloversg)
|
- Stop randomizing Bladeburner's action difficulty (#2491) (@catloversg)
|
||||||
|
- Adjusted Bladeburner's team bonus computation to make one member help (#2541) (@JoshuaCF)
|
||||||
|
- Rebalance charisma exp gain of Recruitment action (#2549) (@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)
|
||||||
|
- 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
|
||||||
|
|
||||||
@@ -382,6 +451,7 @@ export const CONSTANTS = {
|
|||||||
- Update type of Player.factions, GangGenInfo.faction and CorpMaterialConstantData.name (#2347) (@catloversg)
|
- Update type of Player.factions, GangGenInfo.faction and CorpMaterialConstantData.name (#2347) (@catloversg)
|
||||||
- Clarification of Singularity costs inside BN4 (#2403) (@gmcew)
|
- Clarification of Singularity costs inside BN4 (#2403) (@gmcew)
|
||||||
- Update math notations in corporation docs (#2452) (@catloversg)
|
- Update math notations in corporation docs (#2452) (@catloversg)
|
||||||
|
- Update BitNode recommendation short guide (#2523, #2529) (@catloversg)
|
||||||
|
|
||||||
### CODEBASE/REFACTOR/WORKFLOW/JEST/TOOL/DEPS
|
### CODEBASE/REFACTOR/WORKFLOW/JEST/TOOL/DEPS
|
||||||
|
|
||||||
@@ -449,5 +519,28 @@ export const CONSTANTS = {
|
|||||||
- Refactor/adjust getPixelPosition in darknet UI code (#2501) (@d0sboots)
|
- Refactor/adjust getPixelPosition in darknet UI code (#2501) (@d0sboots)
|
||||||
- Add tests for checking getAnswer and solver of coding contracts (#2503) (@catloversg)
|
- Add tests for checking getAnswer and solver of coding contracts (#2503) (@catloversg)
|
||||||
- Refactor ImportSave component (#2505) (@catloversg)
|
- Refactor ImportSave component (#2505) (@catloversg)
|
||||||
|
- Show coding contract names when their tests failed (#2520) (@catloversg)
|
||||||
|
- Workflow: Fix wrong instruction of generating docs (#2522) (@catloversg)
|
||||||
|
- Update comment of LoadingScreen of ComplexPage enum (#2527) (@catloversg)
|
||||||
|
- Make getPlayer 10x faster (#2548) (@d0sboots)
|
||||||
|
- Create monaco editor instance with null model (#2563) (@catloversg)
|
||||||
|
- Update dependencies (#2576) (@catloversg)
|
||||||
|
- Remove barrel imports in Bladeburner code (#2580) (@catloversg)
|
||||||
|
- Fix React warning in IPvGO scoring explanation popup (#2581) (@catloversg)
|
||||||
|
- Update Babel core, presets and module loader for webpack (#2585) (@catloversg)
|
||||||
|
- Add script to generate webpack bundle report (#2587) (@catloversg)
|
||||||
|
- Update Electron (#2591) (@catloversg)
|
||||||
|
- Mitigate issue of forcefullyCrashRenderer (#2597) (@catloversg)
|
||||||
|
- Split Settings.ts to reduce number of imports (#2600) (@catloversg)
|
||||||
|
- Remove duplicate random alphanumeric string functions (#2601) (@catloversg)
|
||||||
|
- Update comments to reflect changes in #2603 (#2606) (@catloversg)
|
||||||
|
- Replace ipExists() linear scan with O(1) Map.has() (#2621) (@lstutzman)
|
||||||
|
- Refactor and fix issues in db.ts (#2623) (@catloversg)
|
||||||
|
- Add dependency array to TerminalInput keydown useEffect (#2620) (@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;
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ export const getTimingAttackConfig = (difficulty: number): ServerConfig => {
|
|||||||
"I spent some time on it, but that's not the password",
|
"I spent some time on it, but that's not the password",
|
||||||
];
|
];
|
||||||
const alphanumeric = difficulty > 16 && Math.random() < 0.3;
|
const alphanumeric = difficulty > 16 && Math.random() < 0.3;
|
||||||
const length = (alphanumeric ? 0 : 3) + difficulty / 4;
|
const length = Math.min((alphanumeric ? 0 : 3) + difficulty / 4, 8);
|
||||||
return {
|
return {
|
||||||
modelId: ModelIds.TimingAttack,
|
modelId: ModelIds.TimingAttack,
|
||||||
password: getPassword(length, alphanumeric),
|
password: getPassword(length, alphanumeric),
|
||||||
|
|||||||
@@ -79,17 +79,9 @@ export const calculateAuthenticationTime = (
|
|||||||
const underleveledFactor = applyUnderleveledFactor ? 1.5 + (chaRequired + 50) / (person.skills.charisma + 50) : 1;
|
const underleveledFactor = applyUnderleveledFactor ? 1.5 + (chaRequired + 50) / (person.skills.charisma + 50) : 1;
|
||||||
const hasBootsFactor = Player.hasAugmentation(AugmentationName.TheBoots) ? 0.8 : 1;
|
const hasBootsFactor = Player.hasAugmentation(AugmentationName.TheBoots) ? 0.8 : 1;
|
||||||
const hasSf15_2Factor = Player.activeSourceFileLvl(15) > 2 ? 0.8 : 1;
|
const hasSf15_2Factor = Player.activeSourceFileLvl(15) > 2 ? 0.8 : 1;
|
||||||
const bonusTimeFactor = hasDarknetBonusTime() ? 0.75 : 1;
|
|
||||||
|
|
||||||
const time =
|
const time =
|
||||||
baseTime *
|
baseTime * skillFactor * backdoorFactor * underleveledFactor * hasBootsFactor * hasSf15_2Factor * threadsFactor;
|
||||||
skillFactor *
|
|
||||||
backdoorFactor *
|
|
||||||
underleveledFactor *
|
|
||||||
hasBootsFactor *
|
|
||||||
hasSf15_2Factor *
|
|
||||||
bonusTimeFactor *
|
|
||||||
threadsFactor;
|
|
||||||
|
|
||||||
// We need to call GetServer and check if it's a dnet server later because this function can be called by formulas
|
// We need to call GetServer and check if it's a dnet server later because this function can be called by formulas
|
||||||
// APIs (darknetServerData.hostname may be an invalid hostname).
|
// APIs (darknetServerData.hostname may be an invalid hostname).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Player } from "@player";
|
import { Player } from "@player";
|
||||||
import { addClue } from "./effects";
|
import { addClue } from "./effects";
|
||||||
import { formatNumber } from "../../ui/formatNumber";
|
import { formatNumber, formatRam } from "../../ui/formatNumber";
|
||||||
import { logger } from "./offlineServerHandling";
|
import { logger } from "./offlineServerHandling";
|
||||||
import type { NetscriptContext } from "../../Netscript/APIWrapper";
|
import type { NetscriptContext } from "../../Netscript/APIWrapper";
|
||||||
import type { DarknetServer } from "../../Server/DarknetServer";
|
import type { DarknetServer } from "../../Server/DarknetServer";
|
||||||
@@ -12,6 +12,7 @@ import type { DarknetServerData, Person as IPerson } from "@nsdefs";
|
|||||||
import { clampNumber } from "../../utils/helpers/clampNumber";
|
import { clampNumber } from "../../utils/helpers/clampNumber";
|
||||||
import { ResponseCodeEnum } from "../Enums";
|
import { ResponseCodeEnum } from "../Enums";
|
||||||
import { isLabyrinthServer } from "./labyrinth";
|
import { isLabyrinthServer } from "./labyrinth";
|
||||||
|
import { roundToTwo } from "../../utils/helpers/roundToTwo";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the effects of removing some blocked RAM from a Darknet server.
|
* Handles the effects of removing some blocked RAM from a Darknet server.
|
||||||
@@ -21,7 +22,7 @@ export const handleRamBlockRemoved = (ctx: NetscriptContext, server: DarknetServ
|
|||||||
const difficulty = server.difficulty + 1;
|
const difficulty = server.difficulty + 1;
|
||||||
|
|
||||||
const ramBlockRemoved = getRamBlockRemoved(server, threads);
|
const ramBlockRemoved = getRamBlockRemoved(server, threads);
|
||||||
server.blockedRam -= ramBlockRemoved;
|
server.blockedRam = roundToTwo(server.blockedRam - ramBlockRemoved);
|
||||||
server.updateRamUsed(server.ramUsed - ramBlockRemoved);
|
server.updateRamUsed(server.ramUsed - ramBlockRemoved);
|
||||||
|
|
||||||
if (server.blockedRam <= 0) {
|
if (server.blockedRam <= 0) {
|
||||||
@@ -30,10 +31,10 @@ export const handleRamBlockRemoved = (ctx: NetscriptContext, server: DarknetServ
|
|||||||
const xpGained = Player.mults.charisma_exp * threads * 10 * 1.1 ** difficulty;
|
const xpGained = Player.mults.charisma_exp * threads * 10 * 1.1 ** difficulty;
|
||||||
Player.gainCharismaExp(xpGained);
|
Player.gainCharismaExp(xpGained);
|
||||||
|
|
||||||
const result = `Liberated ${formatNumber(
|
const result = `Liberated ${formatRam(
|
||||||
ramBlockRemoved,
|
ramBlockRemoved,
|
||||||
4,
|
4,
|
||||||
)}gb of RAM from the server owner's processes. (Gained ${formatNumber(xpGained, 1)} cha xp.)`;
|
)} of RAM from the server owner's processes. (Gained ${formatNumber(xpGained, 1)} cha xp.)`;
|
||||||
logger(ctx)(result);
|
logger(ctx)(result);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -72,7 +73,7 @@ export const getRamBlockRemoved = (darknetServerData: DarknetServerData, threads
|
|||||||
const charismaFactor = 1 + player.skills.charisma / 100;
|
const charismaFactor = 1 + player.skills.charisma / 100;
|
||||||
const difficultyFactor = 2 * 0.92 ** (difficulty + 1);
|
const difficultyFactor = 2 * 0.92 ** (difficulty + 1);
|
||||||
const baseAmount = 0.02;
|
const baseAmount = 0.02;
|
||||||
return clampNumber(baseAmount * difficultyFactor * threads * charismaFactor, 0, remainingRamBlock);
|
return roundToTwo(clampNumber(baseAmount * difficultyFactor * threads * charismaFactor, 0, remainingRamBlock));
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -100,5 +101,5 @@ export const getRamBlock = (maxRam: number): number => {
|
|||||||
return [16, 32, maxRam - 8][Math.floor(Math.random() * 3)];
|
return [16, 32, maxRam - 8][Math.floor(Math.random() * 3)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [maxRam, maxRam - 8, maxRam - 64, maxRam / 2][Math.floor(Math.random() * 4)];
|
return roundToTwo([maxRam, maxRam - 8, maxRam - 64, maxRam / 2][Math.floor(Math.random() * 4)]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { validBitNodes } from "../../BitNode/Constants";
|
|||||||
import { DeleteServer, GetAllServers } from "../../Server/AllServers";
|
import { DeleteServer, GetAllServers } from "../../Server/AllServers";
|
||||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||||
import { AutoExpandAccordion } from "../../ui/AutoExpand/AutoExpandAccordion";
|
import { AutoExpandAccordion } from "../../ui/AutoExpand/AutoExpandAccordion";
|
||||||
|
import { getDarkscapeNavigator } from "../../DarkNet/effects/effects";
|
||||||
|
|
||||||
const useStyles = makeStyles()({
|
const useStyles = makeStyles()({
|
||||||
group: {
|
group: {
|
||||||
@@ -46,6 +47,9 @@ export function SourceFilesDev({ parentRerender }: { parentRerender: () => void
|
|||||||
Player.hacknetNodes = Player.hacknetNodes.filter((node) => typeof node === "string");
|
Player.hacknetNodes = Player.hacknetNodes.filter((node) => typeof node === "string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sfN === 15 && sfLvl !== 0) {
|
||||||
|
getDarkscapeNavigator();
|
||||||
|
}
|
||||||
if (sfLvl === 0) {
|
if (sfLvl === 0) {
|
||||||
Player.sourceFiles.delete(sfN);
|
Player.sourceFiles.delete(sfN);
|
||||||
Player.bitNodeOptions.sourceFileOverrides.delete(sfN);
|
Player.bitNodeOptions.sourceFileOverrides.delete(sfN);
|
||||||
|
|||||||
@@ -6,11 +6,29 @@ Coding Contracts are files with the `.cct` extension.
|
|||||||
They can be accessed through the [Terminal](terminal.md) or through [Scripts](scripts.md) using the [Coding Contract API](../../../../../markdown/bitburner.codingcontract.md).
|
They can be accessed through the [Terminal](terminal.md) or through [Scripts](scripts.md) using the [Coding Contract API](../../../../../markdown/bitburner.codingcontract.md).
|
||||||
|
|
||||||
Each contract has a limited number of attempts.
|
Each contract has a limited number of attempts.
|
||||||
If you provide the wrong answer too many times and exceed the number of attempts, the contract will self destruct (delete itself).
|
If you provide the wrong answer too many times and exceed the number of attempts, the contract will self-destruct (delete itself).
|
||||||
|
|
||||||
Coding Contracts are randomly generated and spawn over time. Initially, you'll only see a small range of the easier contracts, but as you progress further through the game more challenging ones will unlock.
|
Coding Contracts are randomly generated and spawn over time. Initially, you'll only see a small range of the easier contracts, but as you progress further through the game more challenging ones will unlock.
|
||||||
They can appear on any [server](servers.md) (including your home computer), except for your purchased [servers](servers.md).
|
They can appear on any [server](servers.md) (including your home computer), except for your purchased [servers](servers.md).
|
||||||
|
|
||||||
|
## Contract generation
|
||||||
|
|
||||||
|
### Online
|
||||||
|
|
||||||
|
Every 10 minutes, the game makes three independent attempts to generate a contract on normal servers, each with a base
|
||||||
|
25% chance. This probability decreases based on the total number of contracts across all servers. In most cases, you can
|
||||||
|
assume a ~25% success rate per attempt.
|
||||||
|
|
||||||
|
### Offline
|
||||||
|
|
||||||
|
When the game is launched after being offline, the offline time is used to calculate the number of generation attempts.
|
||||||
|
The same rules and probabilities from the online generation process apply.
|
||||||
|
|
||||||
|
### Dark Net
|
||||||
|
|
||||||
|
Opening cache files on [darknet](../programming/darknet.md) servers also has a chance to generate a contract, but with
|
||||||
|
lower rewards. Contracts generated this way grant 50% lower rewards than those generated randomly on normal servers.
|
||||||
|
|
||||||
## Running in Terminal
|
## Running in Terminal
|
||||||
|
|
||||||
To run a Coding Contract in the [Terminal](terminal.md), simply use the `run` command:
|
To run a Coding Contract in the [Terminal](terminal.md), simply use the `run` command:
|
||||||
@@ -136,7 +154,18 @@ There are currently four possible rewards for solving a Coding Contract:
|
|||||||
- [Company](companies.md) [Reputation](reputation.md) for a specific [Company](companies.md)
|
- [Company](companies.md) [Reputation](reputation.md) for a specific [Company](companies.md)
|
||||||
- Money
|
- Money
|
||||||
|
|
||||||
The `amount` of the reward varies based on the difficulty of the problem posed by the Coding Contract.
|
The reward type is randomly chosen at spawn time. If the chosen reward is invalid upon completion (e.g., requirements
|
||||||
|
are not met), it falls back to an alternative type:
|
||||||
|
|
||||||
|
- Specific faction reputation ⇒ Money
|
||||||
|
- All factions' reputation ⇒ Money
|
||||||
|
- Company reputation ⇒ Specific faction reputation or all factions' reputation (50% chance for each).
|
||||||
|
If the fallback reward is also invalid, the reward defaults to Money.
|
||||||
|
|
||||||
|
For example, if a contract is set to reward "All Factions' Reputation" but you have not joined any factions at the time
|
||||||
|
of submission, you will receive Money instead.
|
||||||
|
|
||||||
|
The amount of the reward varies based on the difficulty of the problem posed by the Coding Contract.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
@@ -100,3 +100,9 @@ with a semicolon (;). For example:
|
|||||||
$ run foo.js; tail foo.js
|
$ run foo.js; tail foo.js
|
||||||
|
|
||||||
Chained commands do **not** wait for functions like `hack` or `wget` to finish executing, and so may not always work as expected.
|
Chained commands do **not** wait for functions like `hack` or `wget` to finish executing, and so may not always work as expected.
|
||||||
|
|
||||||
|
## Quirks
|
||||||
|
|
||||||
|
When your scripts render a text box (e.g., `<input>`, `<textarea>`) with the `autoFocus` attribute in the terminal or
|
||||||
|
the tail log window, it may not focus automatically as expected. To be precise, the text box receives focus, but the
|
||||||
|
terminal may immediately reclaim it. This depends on the specific timing of the render.
|
||||||
|
|||||||
@@ -367,12 +367,11 @@ Paste the following code into the [Script](../basic/scripts.md) editor:
|
|||||||
|
|
||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
// How much RAM each cloud server will have. In this case, it'll
|
// How much RAM each cloud server will have. In this case, it'll be 8GB.
|
||||||
// be 8GB.
|
|
||||||
const ram = 8;
|
const ram = 8;
|
||||||
|
|
||||||
// Iterator we'll use for our loop
|
// Iterator we'll use for our loop
|
||||||
let i = 0;
|
let i = ns.cloud.getServerNames().length;
|
||||||
|
|
||||||
// Continuously try to purchase cloud servers until we've reached the maximum
|
// Continuously try to purchase cloud servers until we've reached the maximum
|
||||||
// amount of servers
|
// amount of servers
|
||||||
@@ -381,16 +380,16 @@ Paste the following code into the [Script](../basic/scripts.md) editor:
|
|||||||
if (ns.getServerMoneyAvailable("home") > ns.cloud.getRamLimit(ram)) {
|
if (ns.getServerMoneyAvailable("home") > ns.cloud.getRamLimit(ram)) {
|
||||||
// If we have enough money, then:
|
// If we have enough money, then:
|
||||||
// 1. Purchase the server
|
// 1. Purchase the server
|
||||||
// 2. Copy our hacking script onto the newly-purchased cloud server
|
// 2. Copy our hacking script onto the newly purchased cloud server
|
||||||
// 3. Run our hacking script on the newly-purchased cloud server with 3 threads
|
// 3. Run our hacking script on the newly purchased cloud server with 3 threads
|
||||||
// 4. Increment our iterator to indicate that we've bought a new server
|
// 4. Increment our iterator to indicate that we've bought a new server
|
||||||
let hostname = ns.cloud.purchaseServer("cloud-server-" + i, ram);
|
const hostname = ns.cloud.purchaseServer("cloud-server-" + i, ram);
|
||||||
ns.scp("early-hack-template.js", hostname);
|
ns.scp("early-hack-template.js", hostname);
|
||||||
ns.exec("early-hack-template.js", hostname, 3);
|
ns.exec("early-hack-template.js", hostname, 3);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
//Make the script wait for a second before looping again.
|
// Make the script wait for a second before looping again.
|
||||||
//Removing this line will cause an infinite loop and crash the game.
|
// Removing this line will cause an infinite loop and crash the game.
|
||||||
await ns.sleep(1000);
|
await ns.sleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ Adding a sleep like in the first example, or changing the code so that the `awai
|
|||||||
|
|
||||||
Common infinite loop when translating the server purchasing script in starting guide to scripts is to have a while loop, where the condition's change is conditional:
|
Common infinite loop when translating the server purchasing script in starting guide to scripts is to have a while loop, where the condition's change is conditional:
|
||||||
|
|
||||||
var ram = 8;
|
const ram = 8;
|
||||||
var i = 0;
|
let i = ns.cloud.getServerNames().length;
|
||||||
|
|
||||||
while (i < ns.cloud.getServerLimit()) {
|
while (i < ns.cloud.getServerLimit()) {
|
||||||
if (ns.getServerMoneyAvailable("home") > ns.cloud.getRamLimit(ram)) {
|
if (ns.getServerMoneyAvailable("home") > ns.cloud.getRamLimit(ram)) {
|
||||||
var hostname = ns.cloud.purchaseServer("cloud-server-" + i, ram);
|
const hostname = ns.cloud.purchaseServer("cloud-server-" + i, ram);
|
||||||
ns.scp("early-hack-template.js", hostname);
|
ns.scp("early-hack-template.js", hostname);
|
||||||
ns.exec("early-hack-template.js", hostname, 3);
|
ns.exec("early-hack-template.js", hostname, 3);
|
||||||
++i;
|
++i;
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import file65 from "./doc/en/programming/remote_api.md?raw";
|
|||||||
import file66 from "./doc/en/programming/typescript_react.md?raw";
|
import file66 from "./doc/en/programming/typescript_react.md?raw";
|
||||||
|
|
||||||
import nsDoc_bitburner__valueof_md from "../../markdown/bitburner._valueof.md?raw";
|
import nsDoc_bitburner__valueof_md from "../../markdown/bitburner._valueof.md?raw";
|
||||||
|
import nsDoc_bitburner_activefragment_chargedeffect_md from "../../markdown/bitburner.activefragment.chargedeffect.md?raw";
|
||||||
import nsDoc_bitburner_activefragment_highestcharge_md from "../../markdown/bitburner.activefragment.highestcharge.md?raw";
|
import nsDoc_bitburner_activefragment_highestcharge_md from "../../markdown/bitburner.activefragment.highestcharge.md?raw";
|
||||||
import nsDoc_bitburner_activefragment_md from "../../markdown/bitburner.activefragment.md?raw";
|
import nsDoc_bitburner_activefragment_md from "../../markdown/bitburner.activefragment.md?raw";
|
||||||
import nsDoc_bitburner_activefragment_numcharge_md from "../../markdown/bitburner.activefragment.numcharge.md?raw";
|
import nsDoc_bitburner_activefragment_numcharge_md from "../../markdown/bitburner.activefragment.numcharge.md?raw";
|
||||||
@@ -560,6 +561,7 @@ import nsDoc_bitburner_gameinfo_versionnumber_md from "../../markdown/bitburner.
|
|||||||
import nsDoc_bitburner_gang_ascendmember_md from "../../markdown/bitburner.gang.ascendmember.md?raw";
|
import nsDoc_bitburner_gang_ascendmember_md from "../../markdown/bitburner.gang.ascendmember.md?raw";
|
||||||
import nsDoc_bitburner_gang_canrecruitmember_md from "../../markdown/bitburner.gang.canrecruitmember.md?raw";
|
import nsDoc_bitburner_gang_canrecruitmember_md from "../../markdown/bitburner.gang.canrecruitmember.md?raw";
|
||||||
import nsDoc_bitburner_gang_creategang_md from "../../markdown/bitburner.gang.creategang.md?raw";
|
import nsDoc_bitburner_gang_creategang_md from "../../markdown/bitburner.gang.creategang.md?raw";
|
||||||
|
import nsDoc_bitburner_gang_getallganginformation_md from "../../markdown/bitburner.gang.getallganginformation.md?raw";
|
||||||
import nsDoc_bitburner_gang_getascensionresult_md from "../../markdown/bitburner.gang.getascensionresult.md?raw";
|
import nsDoc_bitburner_gang_getascensionresult_md from "../../markdown/bitburner.gang.getascensionresult.md?raw";
|
||||||
import nsDoc_bitburner_gang_getbonustime_md from "../../markdown/bitburner.gang.getbonustime.md?raw";
|
import nsDoc_bitburner_gang_getbonustime_md from "../../markdown/bitburner.gang.getbonustime.md?raw";
|
||||||
import nsDoc_bitburner_gang_getchancetowinclash_md from "../../markdown/bitburner.gang.getchancetowinclash.md?raw";
|
import nsDoc_bitburner_gang_getchancetowinclash_md from "../../markdown/bitburner.gang.getchancetowinclash.md?raw";
|
||||||
@@ -571,7 +573,6 @@ import nsDoc_bitburner_gang_getganginformation_md from "../../markdown/bitburner
|
|||||||
import nsDoc_bitburner_gang_getinstallresult_md from "../../markdown/bitburner.gang.getinstallresult.md?raw";
|
import nsDoc_bitburner_gang_getinstallresult_md from "../../markdown/bitburner.gang.getinstallresult.md?raw";
|
||||||
import nsDoc_bitburner_gang_getmemberinformation_md from "../../markdown/bitburner.gang.getmemberinformation.md?raw";
|
import nsDoc_bitburner_gang_getmemberinformation_md from "../../markdown/bitburner.gang.getmemberinformation.md?raw";
|
||||||
import nsDoc_bitburner_gang_getmembernames_md from "../../markdown/bitburner.gang.getmembernames.md?raw";
|
import nsDoc_bitburner_gang_getmembernames_md from "../../markdown/bitburner.gang.getmembernames.md?raw";
|
||||||
import nsDoc_bitburner_gang_getotherganginformation_md from "../../markdown/bitburner.gang.getotherganginformation.md?raw";
|
|
||||||
import nsDoc_bitburner_gang_getrecruitsavailable_md from "../../markdown/bitburner.gang.getrecruitsavailable.md?raw";
|
import nsDoc_bitburner_gang_getrecruitsavailable_md from "../../markdown/bitburner.gang.getrecruitsavailable.md?raw";
|
||||||
import nsDoc_bitburner_gang_gettasknames_md from "../../markdown/bitburner.gang.gettasknames.md?raw";
|
import nsDoc_bitburner_gang_gettasknames_md from "../../markdown/bitburner.gang.gettasknames.md?raw";
|
||||||
import nsDoc_bitburner_gang_gettaskstats_md from "../../markdown/bitburner.gang.gettaskstats.md?raw";
|
import nsDoc_bitburner_gang_gettaskstats_md from "../../markdown/bitburner.gang.gettaskstats.md?raw";
|
||||||
@@ -745,6 +746,7 @@ import nsDoc_bitburner_hackingformulas_hackexp_md from "../../markdown/bitburner
|
|||||||
import nsDoc_bitburner_hackingformulas_hackpercent_md from "../../markdown/bitburner.hackingformulas.hackpercent.md?raw";
|
import nsDoc_bitburner_hackingformulas_hackpercent_md from "../../markdown/bitburner.hackingformulas.hackpercent.md?raw";
|
||||||
import nsDoc_bitburner_hackingformulas_hacktime_md from "../../markdown/bitburner.hackingformulas.hacktime.md?raw";
|
import nsDoc_bitburner_hackingformulas_hacktime_md from "../../markdown/bitburner.hackingformulas.hacktime.md?raw";
|
||||||
import nsDoc_bitburner_hackingformulas_md from "../../markdown/bitburner.hackingformulas.md?raw";
|
import nsDoc_bitburner_hackingformulas_md from "../../markdown/bitburner.hackingformulas.md?raw";
|
||||||
|
import nsDoc_bitburner_hackingformulas_weakeneffect_md from "../../markdown/bitburner.hackingformulas.weakeneffect.md?raw";
|
||||||
import nsDoc_bitburner_hackingformulas_weakentime_md from "../../markdown/bitburner.hackingformulas.weakentime.md?raw";
|
import nsDoc_bitburner_hackingformulas_weakentime_md from "../../markdown/bitburner.hackingformulas.weakentime.md?raw";
|
||||||
import nsDoc_bitburner_hackingmultipliers_chance_md from "../../markdown/bitburner.hackingmultipliers.chance.md?raw";
|
import nsDoc_bitburner_hackingmultipliers_chance_md from "../../markdown/bitburner.hackingmultipliers.chance.md?raw";
|
||||||
import nsDoc_bitburner_hackingmultipliers_growth_md from "../../markdown/bitburner.hackingmultipliers.growth.md?raw";
|
import nsDoc_bitburner_hackingmultipliers_growth_md from "../../markdown/bitburner.hackingmultipliers.growth.md?raw";
|
||||||
@@ -1663,6 +1665,7 @@ AllPages["en/programming/remote_api.md"] = file65;
|
|||||||
AllPages["en/programming/typescript_react.md"] = file66;
|
AllPages["en/programming/typescript_react.md"] = file66;
|
||||||
|
|
||||||
AllPages["nsDoc/bitburner._valueof.md"] = nsDoc_bitburner__valueof_md;
|
AllPages["nsDoc/bitburner._valueof.md"] = nsDoc_bitburner__valueof_md;
|
||||||
|
AllPages["nsDoc/bitburner.activefragment.chargedeffect.md"] = nsDoc_bitburner_activefragment_chargedeffect_md;
|
||||||
AllPages["nsDoc/bitburner.activefragment.highestcharge.md"] = nsDoc_bitburner_activefragment_highestcharge_md;
|
AllPages["nsDoc/bitburner.activefragment.highestcharge.md"] = nsDoc_bitburner_activefragment_highestcharge_md;
|
||||||
AllPages["nsDoc/bitburner.activefragment.md"] = nsDoc_bitburner_activefragment_md;
|
AllPages["nsDoc/bitburner.activefragment.md"] = nsDoc_bitburner_activefragment_md;
|
||||||
AllPages["nsDoc/bitburner.activefragment.numcharge.md"] = nsDoc_bitburner_activefragment_numcharge_md;
|
AllPages["nsDoc/bitburner.activefragment.numcharge.md"] = nsDoc_bitburner_activefragment_numcharge_md;
|
||||||
@@ -2155,6 +2158,7 @@ AllPages["nsDoc/bitburner.gameinfo.versionnumber.md"] = nsDoc_bitburner_gameinfo
|
|||||||
AllPages["nsDoc/bitburner.gang.ascendmember.md"] = nsDoc_bitburner_gang_ascendmember_md;
|
AllPages["nsDoc/bitburner.gang.ascendmember.md"] = nsDoc_bitburner_gang_ascendmember_md;
|
||||||
AllPages["nsDoc/bitburner.gang.canrecruitmember.md"] = nsDoc_bitburner_gang_canrecruitmember_md;
|
AllPages["nsDoc/bitburner.gang.canrecruitmember.md"] = nsDoc_bitburner_gang_canrecruitmember_md;
|
||||||
AllPages["nsDoc/bitburner.gang.creategang.md"] = nsDoc_bitburner_gang_creategang_md;
|
AllPages["nsDoc/bitburner.gang.creategang.md"] = nsDoc_bitburner_gang_creategang_md;
|
||||||
|
AllPages["nsDoc/bitburner.gang.getallganginformation.md"] = nsDoc_bitburner_gang_getallganginformation_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getascensionresult.md"] = nsDoc_bitburner_gang_getascensionresult_md;
|
AllPages["nsDoc/bitburner.gang.getascensionresult.md"] = nsDoc_bitburner_gang_getascensionresult_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getbonustime.md"] = nsDoc_bitburner_gang_getbonustime_md;
|
AllPages["nsDoc/bitburner.gang.getbonustime.md"] = nsDoc_bitburner_gang_getbonustime_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getchancetowinclash.md"] = nsDoc_bitburner_gang_getchancetowinclash_md;
|
AllPages["nsDoc/bitburner.gang.getchancetowinclash.md"] = nsDoc_bitburner_gang_getchancetowinclash_md;
|
||||||
@@ -2166,7 +2170,6 @@ AllPages["nsDoc/bitburner.gang.getganginformation.md"] = nsDoc_bitburner_gang_ge
|
|||||||
AllPages["nsDoc/bitburner.gang.getinstallresult.md"] = nsDoc_bitburner_gang_getinstallresult_md;
|
AllPages["nsDoc/bitburner.gang.getinstallresult.md"] = nsDoc_bitburner_gang_getinstallresult_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getmemberinformation.md"] = nsDoc_bitburner_gang_getmemberinformation_md;
|
AllPages["nsDoc/bitburner.gang.getmemberinformation.md"] = nsDoc_bitburner_gang_getmemberinformation_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getmembernames.md"] = nsDoc_bitburner_gang_getmembernames_md;
|
AllPages["nsDoc/bitburner.gang.getmembernames.md"] = nsDoc_bitburner_gang_getmembernames_md;
|
||||||
AllPages["nsDoc/bitburner.gang.getotherganginformation.md"] = nsDoc_bitburner_gang_getotherganginformation_md;
|
|
||||||
AllPages["nsDoc/bitburner.gang.getrecruitsavailable.md"] = nsDoc_bitburner_gang_getrecruitsavailable_md;
|
AllPages["nsDoc/bitburner.gang.getrecruitsavailable.md"] = nsDoc_bitburner_gang_getrecruitsavailable_md;
|
||||||
AllPages["nsDoc/bitburner.gang.gettasknames.md"] = nsDoc_bitburner_gang_gettasknames_md;
|
AllPages["nsDoc/bitburner.gang.gettasknames.md"] = nsDoc_bitburner_gang_gettasknames_md;
|
||||||
AllPages["nsDoc/bitburner.gang.gettaskstats.md"] = nsDoc_bitburner_gang_gettaskstats_md;
|
AllPages["nsDoc/bitburner.gang.gettaskstats.md"] = nsDoc_bitburner_gang_gettaskstats_md;
|
||||||
@@ -2340,6 +2343,7 @@ AllPages["nsDoc/bitburner.hackingformulas.hackexp.md"] = nsDoc_bitburner_hacking
|
|||||||
AllPages["nsDoc/bitburner.hackingformulas.hackpercent.md"] = nsDoc_bitburner_hackingformulas_hackpercent_md;
|
AllPages["nsDoc/bitburner.hackingformulas.hackpercent.md"] = nsDoc_bitburner_hackingformulas_hackpercent_md;
|
||||||
AllPages["nsDoc/bitburner.hackingformulas.hacktime.md"] = nsDoc_bitburner_hackingformulas_hacktime_md;
|
AllPages["nsDoc/bitburner.hackingformulas.hacktime.md"] = nsDoc_bitburner_hackingformulas_hacktime_md;
|
||||||
AllPages["nsDoc/bitburner.hackingformulas.md"] = nsDoc_bitburner_hackingformulas_md;
|
AllPages["nsDoc/bitburner.hackingformulas.md"] = nsDoc_bitburner_hackingformulas_md;
|
||||||
|
AllPages["nsDoc/bitburner.hackingformulas.weakeneffect.md"] = nsDoc_bitburner_hackingformulas_weakeneffect_md;
|
||||||
AllPages["nsDoc/bitburner.hackingformulas.weakentime.md"] = nsDoc_bitburner_hackingformulas_weakentime_md;
|
AllPages["nsDoc/bitburner.hackingformulas.weakentime.md"] = nsDoc_bitburner_hackingformulas_weakentime_md;
|
||||||
AllPages["nsDoc/bitburner.hackingmultipliers.chance.md"] = nsDoc_bitburner_hackingmultipliers_chance_md;
|
AllPages["nsDoc/bitburner.hackingmultipliers.chance.md"] = nsDoc_bitburner_hackingmultipliers_chance_md;
|
||||||
AllPages["nsDoc/bitburner.hackingmultipliers.growth.md"] = nsDoc_bitburner_hackingmultipliers_growth_md;
|
AllPages["nsDoc/bitburner.hackingmultipliers.growth.md"] = nsDoc_bitburner_hackingmultipliers_growth_md;
|
||||||
|
|||||||
@@ -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 />}
|
||||||
|
|||||||
+24
-24
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ const gang = {
|
|||||||
getMemberNames: RamCostConstants.GangApiBase / 4,
|
getMemberNames: RamCostConstants.GangApiBase / 4,
|
||||||
renameMember: 0,
|
renameMember: 0,
|
||||||
getGangInformation: RamCostConstants.GangApiBase / 2,
|
getGangInformation: RamCostConstants.GangApiBase / 2,
|
||||||
getOtherGangInformation: RamCostConstants.GangApiBase / 2,
|
getAllGangInformation: RamCostConstants.GangApiBase / 2,
|
||||||
getMemberInformation: RamCostConstants.GangApiBase / 2,
|
getMemberInformation: RamCostConstants.GangApiBase / 2,
|
||||||
canRecruitMember: RamCostConstants.GangApiBase / 4,
|
canRecruitMember: RamCostConstants.GangApiBase / 4,
|
||||||
getRecruitsAvailable: RamCostConstants.GangApiBase / 4,
|
getRecruitsAvailable: RamCostConstants.GangApiBase / 4,
|
||||||
@@ -692,6 +692,7 @@ export const RamCosts: RamCostTree<NSFull> = {
|
|||||||
hackTime: 0,
|
hackTime: 0,
|
||||||
growTime: 0,
|
growTime: 0,
|
||||||
weakenTime: 0,
|
weakenTime: 0,
|
||||||
|
weakenEffect: 0,
|
||||||
},
|
},
|
||||||
hacknetNodes: {
|
hacknetNodes: {
|
||||||
moneyGainRate: 0,
|
moneyGainRate: 0,
|
||||||
|
|||||||
@@ -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,6 +1,6 @@
|
|||||||
import { Player } from "@player";
|
import { Player } from "@player";
|
||||||
import { calculateServerGrowth, calculateGrowMoney } from "../Server/formulas/grow";
|
import { calculateServerGrowth, calculateGrowMoney } from "../Server/formulas/grow";
|
||||||
import { numCycleForGrowthCorrected } from "../Server/ServerHelpers";
|
import { getWeakenEffect, numCycleForGrowthCorrected } from "../Server/ServerHelpers";
|
||||||
import {
|
import {
|
||||||
calculateMoneyGainRate,
|
calculateMoneyGainRate,
|
||||||
calculateLevelUpgradeCost,
|
calculateLevelUpgradeCost,
|
||||||
@@ -235,6 +235,14 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
|
|||||||
checkFormulasAccess(ctx);
|
checkFormulasAccess(ctx);
|
||||||
return calculateWeakenTime(server, person) * 1000;
|
return calculateWeakenTime(server, person) * 1000;
|
||||||
},
|
},
|
||||||
|
weakenEffect:
|
||||||
|
(ctx) =>
|
||||||
|
(_threads, _cores = 1) => {
|
||||||
|
const threads = helpers.number(ctx, "threads", _threads);
|
||||||
|
const cores = helpers.number(ctx, "cores", _cores);
|
||||||
|
checkFormulasAccess(ctx);
|
||||||
|
return getWeakenEffect(threads, cores);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
hacknetNodes: {
|
hacknetNodes: {
|
||||||
moneyGainRate:
|
moneyGainRate:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Gang as IGang, EquipmentStats, GangOtherInfoObject } from "@nsdefs
|
|||||||
import type { Gang } from "../Gang/Gang";
|
import type { Gang } from "../Gang/Gang";
|
||||||
import type { GangMember } from "../Gang/GangMember";
|
import type { GangMember } from "../Gang/GangMember";
|
||||||
import type { GangMemberTask } from "../Gang/GangMemberTask";
|
import type { GangMemberTask } from "../Gang/GangMemberTask";
|
||||||
import type { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
|
import { type InternalAPI, type NetscriptContext, setRemovedFunctions } from "../Netscript/APIWrapper";
|
||||||
|
|
||||||
import { GangPromise, RecruitmentResult } from "../Gang/Gang";
|
import { GangPromise, RecruitmentResult } from "../Gang/Gang";
|
||||||
import { Player } from "@player";
|
import { Player } from "@player";
|
||||||
@@ -37,7 +37,7 @@ export function NetscriptGang(): InternalAPI<IGang> {
|
|||||||
return task;
|
return task;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
const gangFunctions: InternalAPI<IGang> = {
|
||||||
createGang: (ctx) => (_faction) => {
|
createGang: (ctx) => (_faction) => {
|
||||||
const faction = getEnumHelper("FactionName").nsGetMember(ctx, _faction);
|
const faction = getEnumHelper("FactionName").nsGetMember(ctx, _faction);
|
||||||
if (Player.gang) {
|
if (Player.gang) {
|
||||||
@@ -117,7 +117,7 @@ export function NetscriptGang(): InternalAPI<IGang> {
|
|||||||
equipmentCostMult: 1 / gang.getDiscount(),
|
equipmentCostMult: 1 / gang.getDiscount(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getOtherGangInformation: (ctx) => () => {
|
getAllGangInformation: (ctx) => () => {
|
||||||
getGang(ctx);
|
getGang(ctx);
|
||||||
const cpy: Record<string, GangOtherInfoObject> = {};
|
const cpy: Record<string, GangOtherInfoObject> = {};
|
||||||
for (const gang of Object.keys(AllGangs)) {
|
for (const gang of Object.keys(AllGangs)) {
|
||||||
@@ -362,4 +362,10 @@ export function NetscriptGang(): InternalAPI<IGang> {
|
|||||||
return GangPromise.promise;
|
return GangPromise.promise;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Removed functions
|
||||||
|
setRemovedFunctions(gangFunctions, {
|
||||||
|
getOtherGangInformation: { version: "3.0.0", replacement: "gang.getAllGangInformation" },
|
||||||
|
});
|
||||||
|
return gangFunctions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -1176,7 +1176,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()) {
|
||||||
|
|||||||
@@ -64,7 +64,11 @@ export function NetscriptStanek(): InternalAPI<IStanek> {
|
|||||||
checkStanekAPIAccess(ctx);
|
checkStanekAPIAccess(ctx);
|
||||||
helpers.log(ctx, () => `Returned ${staneksGift.fragments.length} fragments`);
|
helpers.log(ctx, () => `Returned ${staneksGift.fragments.length} fragments`);
|
||||||
return staneksGift.fragments.map((activeFragment) => {
|
return staneksGift.fragments.map((activeFragment) => {
|
||||||
return { ...activeFragment.copy(), ...activeFragment.fragment().copy() };
|
return {
|
||||||
|
...activeFragment.copy(),
|
||||||
|
...activeFragment.fragment().copy(),
|
||||||
|
chargedEffect: staneksGift.effect(activeFragment),
|
||||||
|
};
|
||||||
}) satisfies ReturnType<IStanek["activeFragments"]>;
|
}) satisfies ReturnType<IStanek["activeFragments"]>;
|
||||||
},
|
},
|
||||||
clearGift: (ctx) => () => {
|
clearGift: (ctx) => () => {
|
||||||
@@ -99,9 +103,11 @@ export function NetscriptStanek(): InternalAPI<IStanek> {
|
|||||||
checkStanekAPIAccess(ctx);
|
checkStanekAPIAccess(ctx);
|
||||||
const activeFragment = staneksGift.findFragment(rootX, rootY);
|
const activeFragment = staneksGift.findFragment(rootX, rootY);
|
||||||
if (activeFragment !== undefined) {
|
if (activeFragment !== undefined) {
|
||||||
return { ...activeFragment.copy(), ...activeFragment.fragment().copy() } satisfies ReturnType<
|
return {
|
||||||
IStanek["getFragment"]
|
...activeFragment.copy(),
|
||||||
>;
|
...activeFragment.fragment().copy(),
|
||||||
|
chargedEffect: staneksGift.effect(activeFragment),
|
||||||
|
} satisfies ReturnType<IStanek["getFragment"]>;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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());
|
||||||
@@ -602,6 +604,10 @@ export function canAccessCotMG(this: PlayerObject): boolean {
|
|||||||
return canAccessBitNodeFeature(13);
|
return canAccessBitNodeFeature(13);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To ensure the "SF override" option work properly, this function should only be used in special cases. In most cases,
|
||||||
|
* activeSourceFileLvl should be used instead.
|
||||||
|
*/
|
||||||
export function sourceFileLvl(this: PlayerObject, n: number): number {
|
export function sourceFileLvl(this: PlayerObject, n: number): number {
|
||||||
return this.sourceFiles.get(n) ?? 0;
|
return this.sourceFiles.get(n) ?? 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function getFactionFieldWorkRepGain(p: IPerson, favor: number): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDarknetCharismaBonus(p: IPerson, scalar: number = 1): number {
|
function getDarknetCharismaBonus(p: IPerson, scalar: number = 1): number {
|
||||||
if (Player.sourceFileLvl(15) >= 3) {
|
if (Player.activeSourceFileLvl(15) >= 3) {
|
||||||
return p.skills.charisma * scalar;
|
return p.skills.charisma * scalar;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import { clampNumber } from "../../utils/helpers/clampNumber";
|
|||||||
* stat level. Stat-agnostic (same formula for every stat)
|
* stat level. Stat-agnostic (same formula for every stat)
|
||||||
*/
|
*/
|
||||||
export function calculateSkill(exp: number, mult = 1): number {
|
export function calculateSkill(exp: number, mult = 1): number {
|
||||||
|
// Mult can be 0 in BN12 when the player has a very high SF12 level. In this case, the skill level will never change
|
||||||
|
// from its initial value (1 for most stats, except intelligence).
|
||||||
|
if (mult === 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
const value = Math.floor(mult * (32 * Math.log(exp + 534.6) - 200));
|
const value = Math.floor(mult * (32 * Math.log(exp + 534.6) - 200));
|
||||||
return clampNumber(value, 1);
|
return clampNumber(value, 1);
|
||||||
}
|
}
|
||||||
@@ -12,7 +17,7 @@ export function calculateSkill(exp: number, mult = 1): number {
|
|||||||
export function calculateExp(skill: number, mult = 1): number {
|
export function calculateExp(skill: number, mult = 1): number {
|
||||||
const floorSkill = Math.floor(skill);
|
const floorSkill = Math.floor(skill);
|
||||||
let value = Math.exp((skill / mult + 200) / 32) - 534.6;
|
let value = Math.exp((skill / mult + 200) / 32) - 534.6;
|
||||||
if (skill === floorSkill && Number.isFinite(skill)) {
|
if (skill === floorSkill && Number.isFinite(skill) && Number.isFinite(value)) {
|
||||||
// Check for floating point rounding issues that would cause the inverse
|
// Check for floating point rounding issues that would cause the inverse
|
||||||
// operation to return the wrong result.
|
// operation to return the wrong result.
|
||||||
let calcSkill = calculateSkill(value, mult);
|
let calcSkill = calculateSkill(value, mult);
|
||||||
|
|||||||
+3
-1
@@ -190,6 +190,8 @@ export function prestigeAugmentation(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear recent scripts
|
||||||
|
recentScripts.splice(0);
|
||||||
resetPidCounter();
|
resetPidCounter();
|
||||||
ProgramsSeen.clear();
|
ProgramsSeen.clear();
|
||||||
InvitationsSeen.clear();
|
InvitationsSeen.clear();
|
||||||
@@ -310,7 +312,7 @@ export function prestigeSourceFile(isFlume: boolean): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BitNode 12: The Recursion
|
// BitNode 12: The Recursion
|
||||||
if (Player.bitNodeN === 12 && Player.activeSourceFileLvl(12) > 100) {
|
if (Player.bitNodeN === 12 && Player.sourceFileLvl(12) > 100) {
|
||||||
delayedDialog("Saynt_Garmo is watching you");
|
delayedDialog("Saynt_Garmo is watching you");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ function giveSourceFile(bitNodeNumber: number): void {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player.sourceFiles.set(bitNodeNumber, 1);
|
Player.sourceFiles.set(bitNodeNumber, 1);
|
||||||
if (bitNodeNumber === 5 && Player.skills.intelligence === 0) {
|
|
||||||
Player.skills.intelligence = 1;
|
|
||||||
}
|
|
||||||
dialogBoxCreate(
|
dialogBoxCreate(
|
||||||
<>
|
<>
|
||||||
You received a Source-File for destroying a BitNode!
|
You received a Source-File for destroying a BitNode!
|
||||||
@@ -63,13 +60,6 @@ export function enterBitNode(
|
|||||||
|
|
||||||
if (!isFlume) {
|
if (!isFlume) {
|
||||||
giveSourceFile(destroyedBitNode);
|
giveSourceFile(destroyedBitNode);
|
||||||
} else if (Player.sourceFileLvl(5) === 0 && newBitNode !== 5) {
|
|
||||||
Player.skills.intelligence = 0;
|
|
||||||
Player.exp.intelligence = 0;
|
|
||||||
Player.persistentIntelligenceData.exp = 0;
|
|
||||||
}
|
|
||||||
if (newBitNode === 5 && Player.skills.intelligence === 0) {
|
|
||||||
Player.skills.intelligence = 1;
|
|
||||||
}
|
}
|
||||||
// Set new Bit Node
|
// Set new Bit Node
|
||||||
Player.bitNodeN = newBitNode;
|
Player.bitNodeN = newBitNode;
|
||||||
|
|||||||
+9
-2
@@ -36,6 +36,7 @@ import { loadInfiltrations } from "./Infiltration/SaveLoadInfiltration";
|
|||||||
import { InfiltrationState } from "./Infiltration/formulas/game";
|
import { InfiltrationState } from "./Infiltration/formulas/game";
|
||||||
import { hasDarknetAccess } from "./DarkNet/utils/darknetAuthUtils";
|
import { hasDarknetAccess } from "./DarkNet/utils/darknetAuthUtils";
|
||||||
import { loadSettings } from "./Settings/SettingsUtils";
|
import { loadSettings } from "./Settings/SettingsUtils";
|
||||||
|
import { getBitNodeLevel } from "./BitNode/BitNodeUtils";
|
||||||
|
|
||||||
/* SaveObject.js
|
/* SaveObject.js
|
||||||
* Defines the object used to save/load games
|
* Defines the object used to save/load games
|
||||||
@@ -270,7 +271,7 @@ class BitburnerSaveObject implements BitburnerSaveObjectType {
|
|||||||
* - Base64 format: save file uses .json extension. Save data is the base64-encoded json save string.
|
* - Base64 format: save file uses .json extension. Save data is the base64-encoded json save string.
|
||||||
*/
|
*/
|
||||||
const extension = canUseBinaryFormat() ? "json.gz" : "json";
|
const extension = canUseBinaryFormat() ? "json.gz" : "json";
|
||||||
return `bitburnerSave_${epochTime}_BN${bn}x${Player.sourceFileLvl(bn) + 1}.${extension}`;
|
return `bitburnerSave_${epochTime}_BN${bn}x${getBitNodeLevel()}.${extension}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async exportGame(): Promise<void> {
|
async exportGame(): Promise<void> {
|
||||||
@@ -430,7 +431,10 @@ class BitburnerSaveObject implements BitburnerSaveObjectType {
|
|||||||
achievements: importedPlayer.achievements?.length ?? 0,
|
achievements: importedPlayer.achievements?.length ?? 0,
|
||||||
|
|
||||||
bitNode: importedPlayer.bitNodeN,
|
bitNode: importedPlayer.bitNodeN,
|
||||||
bitNodeLevel: importedPlayer.sourceFileLvl(importedPlayer.bitNodeN) + 1,
|
bitNodeLevel: getBitNodeLevel(
|
||||||
|
importedPlayer.bitNodeN,
|
||||||
|
importedPlayer.activeSourceFileLvl(importedPlayer.bitNodeN),
|
||||||
|
),
|
||||||
sourceFiles: [...importedPlayer.sourceFiles].reduce<number>((total, [__bn, lvl]) => (total += lvl), 0),
|
sourceFiles: [...importedPlayer.sourceFiles].reduce<number>((total, [__bn, lvl]) => (total += lvl), 0),
|
||||||
exploits: importedPlayer.exploits.length,
|
exploits: importedPlayer.exploits.length,
|
||||||
|
|
||||||
@@ -453,6 +457,9 @@ class BitburnerSaveObject implements BitburnerSaveObjectType {
|
|||||||
async function loadGame(saveData: SaveData): Promise<boolean> {
|
async function loadGame(saveData: SaveData): Promise<boolean> {
|
||||||
createScamUpdateText();
|
createScamUpdateText();
|
||||||
if (!saveData) {
|
if (!saveData) {
|
||||||
|
console.error(
|
||||||
|
`Invalid save data. typeof saveData: ${typeof saveData}. saveData is an empty string: ${saveData === ""}`,
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const jsonSaveString = await decodeSaveData(saveData);
|
const jsonSaveString = await decodeSaveData(saveData);
|
||||||
|
|||||||
+59
-45
@@ -1852,7 +1852,7 @@ export type Task = StudyTask | CompanyWorkTask | CreateProgramWorkTask | CrimeTa
|
|||||||
*
|
*
|
||||||
* - 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.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@@ -2925,7 +2925,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the number of hacknet nodes you own.
|
* Get the number of hacknet nodes you own.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns the number of Hacknet Nodes you own.
|
* Returns the number of Hacknet Nodes you own.
|
||||||
*
|
*
|
||||||
@@ -2936,7 +2936,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the maximum number of hacknet nodes.
|
* Get the maximum number of hacknet nodes.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* @returns Maximum number of hacknet nodes.
|
* @returns Maximum number of hacknet nodes.
|
||||||
*/
|
*/
|
||||||
@@ -2945,7 +2945,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Purchase a new hacknet node.
|
* Purchase a new hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Purchases a new Hacknet Node. Returns a number with the index of the
|
* Purchases a new Hacknet Node. Returns a number with the index of the
|
||||||
* Hacknet Node. This index is equivalent to the number at the end of
|
* Hacknet Node. This index is equivalent to the number at the end of
|
||||||
@@ -2961,7 +2961,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the price of the next hacknet node.
|
* Get the price of the next hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns the cost of purchasing a new Hacknet Node.
|
* Returns the cost of purchasing a new Hacknet Node.
|
||||||
*
|
*
|
||||||
@@ -2972,7 +2972,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the stats of a hacknet node.
|
* Get the stats of a hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns an object containing a variety of stats about the specified Hacknet Node.
|
* Returns an object containing a variety of stats about the specified Hacknet Node.
|
||||||
*
|
*
|
||||||
@@ -2988,7 +2988,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Upgrade the level of a hacknet node.
|
* Upgrade the level of a hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Tries to upgrade the level of the specified Hacknet Node by n.
|
* Tries to upgrade the level of the specified Hacknet Node by n.
|
||||||
*
|
*
|
||||||
@@ -3006,7 +3006,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Upgrade the RAM of a hacknet node.
|
* Upgrade the RAM of a hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Tries to upgrade the specified Hacknet Node’s RAM n times.
|
* Tries to upgrade the specified Hacknet Node’s RAM n times.
|
||||||
* Note that each upgrade doubles the Node’s RAM.
|
* Note that each upgrade doubles the Node’s RAM.
|
||||||
@@ -3026,7 +3026,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Upgrade the core of a hacknet node.
|
* Upgrade the core of a hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Tries to purchase n cores for the specified Hacknet Node.
|
* Tries to purchase n cores for the specified Hacknet Node.
|
||||||
*
|
*
|
||||||
@@ -3044,7 +3044,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Upgrade the cache of a hacknet node.
|
* Upgrade the cache of a hacknet node.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3064,7 +3064,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Calculate the cost of upgrading hacknet node levels.
|
* Calculate the cost of upgrading hacknet node levels.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns the cost of upgrading the specified Hacknet Node by n levels.
|
* Returns the cost of upgrading the specified Hacknet Node by n levels.
|
||||||
*
|
*
|
||||||
@@ -3080,7 +3080,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Calculate the cost of upgrading hacknet node RAM.
|
* Calculate the cost of upgrading hacknet node RAM.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns the cost of upgrading the RAM of the specified Hacknet Node n times.
|
* Returns the cost of upgrading the RAM of the specified Hacknet Node n times.
|
||||||
*
|
*
|
||||||
@@ -3096,7 +3096,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Calculate the cost of upgrading hacknet node cores.
|
* Calculate the cost of upgrading hacknet node cores.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* Returns the cost of upgrading the number of cores of the specified Hacknet Node by n.
|
* Returns the cost of upgrading the number of cores of the specified Hacknet Node by n.
|
||||||
*
|
*
|
||||||
@@ -3112,7 +3112,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Calculate the cost of upgrading hacknet node cache.
|
* Calculate the cost of upgrading hacknet node cache.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3130,7 +3130,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the total number of hashes stored.
|
* Get the total number of hashes stored.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3143,7 +3143,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the maximum number of hashes you can store.
|
* Get the maximum number of hashes you can store.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3156,7 +3156,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the cost of a hash upgrade.
|
* Get the cost of a hash upgrade.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3178,7 +3178,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Purchase a hash upgrade.
|
* Purchase a hash upgrade.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3207,7 +3207,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the list of hash upgrades
|
* Get the list of hash upgrades
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3223,7 +3223,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the level of a hash upgrade.
|
* Get the level of a hash upgrade.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3234,7 +3234,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the multiplier to study.
|
* Get the multiplier to study.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -3245,7 +3245,7 @@ export interface Hacknet {
|
|||||||
/**
|
/**
|
||||||
* Get the multiplier to training.
|
* Get the multiplier to training.
|
||||||
* @remarks
|
* @remarks
|
||||||
* RAM cost: 0 GB
|
* RAM cost: 0.5 GB
|
||||||
*
|
*
|
||||||
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
* This function is only applicable for Hacknet Servers (the upgraded version of a Hacknet Node).
|
||||||
*
|
*
|
||||||
@@ -4879,7 +4879,7 @@ export interface Gang {
|
|||||||
*
|
*
|
||||||
* @returns Object containing territory and power information about all gangs, including the player's gang, if any.
|
* @returns Object containing territory and power information about all gangs, including the player's gang, if any.
|
||||||
*/
|
*/
|
||||||
getOtherGangInformation(): Record<string, GangOtherInfoObject>;
|
getAllGangInformation(): Record<string, GangOtherInfoObject>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about a specific gang member.
|
* Get information about a specific gang member.
|
||||||
@@ -6299,6 +6299,16 @@ interface HackingFormulas {
|
|||||||
* @returns The calculated weaken time, in milliseconds.
|
* @returns The calculated weaken time, in milliseconds.
|
||||||
*/
|
*/
|
||||||
weakenTime(server: Server, player: Person): number;
|
weakenTime(server: Server, player: Person): number;
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* {@code 1 + (cores - 1) / 16}.
|
||||||
|
* @param threads - Number of threads running weaken.
|
||||||
|
* @param cores - Number of cores on the host server. Default 1.
|
||||||
|
* @returns The security decrease amount.
|
||||||
|
*/
|
||||||
|
weakenEffect(threads: number, cores?: number): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6586,6 +6596,21 @@ interface ActiveFragment extends Fragment {
|
|||||||
rotation: number;
|
rotation: number;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
/**
|
||||||
|
* This is the raw value of the modifier used to calculate the effect on your multipliers. It may not be a multiplier.
|
||||||
|
*
|
||||||
|
* With fragments that increase a multiplier, this value is a multiplier. For example, with "+x% hacknet production"
|
||||||
|
* fragment, a value of 1.25 will multiply the "hacknet_node_money" multiplier by 1.25. The UI will show "+25% hacknet
|
||||||
|
* production".
|
||||||
|
*
|
||||||
|
* With fragments that decrease a multiplier, you need to invert this value. For example, with "-x% cheaper hacknet
|
||||||
|
* costs" fragment, a value of 1.25 means the "hacknet_node_purchase_cost" (and other relevant cost multipliers) will
|
||||||
|
* be multiplied by 0.8 (1 / 1.25). The UI will show "20% cheaper hacknet costs".
|
||||||
|
*
|
||||||
|
* With booster fragments, this value is always 1. Booster fragments only boost non-booster fragments. They don't
|
||||||
|
* directly boost your multipliers.
|
||||||
|
*/
|
||||||
|
chargedEffect: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6999,113 +7024,93 @@ interface UserInterface {
|
|||||||
export interface NS {
|
export interface NS {
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Hacknet | hacknet} functions. Some of this API contains spoilers.
|
* Namespace for {@link Hacknet | hacknet} functions. Some of this API contains spoilers.
|
||||||
* @remarks RAM cost: 4 GB.
|
|
||||||
*/
|
*/
|
||||||
readonly hacknet: Hacknet;
|
readonly hacknet: Hacknet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Bladeburner | Bladeburner} functions. Contains spoilers.
|
* Namespace for {@link Bladeburner | Bladeburner} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly bladeburner: Bladeburner;
|
readonly bladeburner: Bladeburner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link CodingContract | coding contract} functions.
|
* Namespace for {@link CodingContract | coding contract} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly codingcontract: CodingContract;
|
readonly codingcontract: CodingContract;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Cloud | cloud} functions.
|
* Namespace for {@link Cloud | cloud} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly cloud: Cloud;
|
readonly cloud: Cloud;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for darknet functions. Contains spoilers.
|
* Namespace for darknet functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly dnet: Darknet;
|
readonly dnet: Darknet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Format | formatting} functions.
|
* Namespace for {@link Format | formatting} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly format: Format;
|
readonly format: Format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Gang | gang} functions. Contains spoilers.
|
* Namespace for {@link Gang | gang} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly gang: Gang;
|
readonly gang: Gang;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Go | Go} functions.
|
* Namespace for {@link Go | Go} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly go: Go;
|
readonly go: Go;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Sleeve | sleeve} functions. Contains spoilers.
|
* Namespace for {@link Sleeve | sleeve} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly sleeve: Sleeve;
|
readonly sleeve: Sleeve;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Stock | stock} functions.
|
* Namespace for {@link Stock | stock} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly stock: Stock;
|
readonly stock: Stock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Formulas | formulas} functions.
|
* Namespace for {@link Formulas | formulas} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly formulas: Formulas;
|
readonly formulas: Formulas;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Stanek | Stanek} functions. Contains spoilers.
|
* Namespace for {@link Stanek | Stanek} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly stanek: Stanek;
|
readonly stanek: Stanek;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Infiltration | infiltration} functions.
|
* Namespace for {@link Infiltration | infiltration} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly infiltration: Infiltration;
|
readonly infiltration: Infiltration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Corporation | corporation} functions. Contains spoilers.
|
* Namespace for {@link Corporation | corporation} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly corporation: Corporation;
|
readonly corporation: Corporation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link UserInterface | user interface} functions.
|
* Namespace for {@link UserInterface | user interface} functions.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly ui: UserInterface;
|
readonly ui: UserInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Singularity | singularity} functions. Contains spoilers.
|
* Namespace for {@link Singularity | singularity} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly singularity: Singularity;
|
readonly singularity: Singularity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Namespace for {@link Grafting | grafting} functions. Contains spoilers.
|
* Namespace for {@link Grafting | grafting} functions. Contains spoilers.
|
||||||
* @remarks RAM cost: 0 GB
|
|
||||||
*/
|
*/
|
||||||
readonly grafting: Grafting;
|
readonly grafting: Grafting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arguments passed into the script.
|
* Arguments passed into the script.
|
||||||
*
|
*
|
||||||
* @remarks
|
* These arguments can be accessed as a normal array by using the `[]` operator
|
||||||
* RAM cost: 0 GB
|
|
||||||
*
|
|
||||||
* Arguments passed into a script can be accessed as a normal array by using the `[]` operator
|
|
||||||
* (`args[0]`, `args[1]`, etc...).
|
* (`args[0]`, `args[1]`, etc...).
|
||||||
* Arguments can be string, number, or boolean.
|
* Arguments can be string, number, or boolean.
|
||||||
* Use `args.length` to get the number of arguments that were passed into a script.
|
* Use `args.length` to get the number of arguments that were passed into a script.
|
||||||
@@ -7905,6 +7910,11 @@ export interface NS {
|
|||||||
* // arguments to the script.
|
* // arguments to the script.
|
||||||
* ns.exec("foo.js", "foodnstuff", 5, 1, "test");
|
* ns.exec("foo.js", "foodnstuff", 5, 1, "test");
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
|
* For darknet servers: A session must be established with the target server, and the script must be
|
||||||
|
* running on a server that is directly connected to the target, or the target must have a backdoor or
|
||||||
|
* stasis link installed.
|
||||||
|
*
|
||||||
* @param script - Filename of script to execute. This file must already exist on the target server.
|
* @param script - Filename of script to execute. This file must already exist on the target server.
|
||||||
* @param host - Hostname/IP of the target server on which to execute the script.
|
* @param host - Hostname/IP of the target server on which to execute the script.
|
||||||
* @param threadOrOptions - Either an integer number of threads for new script, or a {@link RunOptions} object. Threads defaults to 1.
|
* @param threadOrOptions - Either an integer number of threads for new script, or a {@link RunOptions} object. Threads defaults to 1.
|
||||||
@@ -8042,7 +8052,11 @@ export interface NS {
|
|||||||
* ns.scp(files, server, "home");
|
* ns.scp(files, server, "home");
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. (The source server does not require a session.)
|
* For darknet servers: The destination requires a session, but unlike {@link NS.exec | exec}, does not
|
||||||
|
* require a direct connection — scp works at any distance. The source server has no darknet requirements
|
||||||
|
* (no session or connection needed). Use {@link Darknet.authenticate | dnet.authenticate} (requires direct
|
||||||
|
* connection) or {@link Darknet.connectToSession | dnet.connectToSession} (at any distance) to
|
||||||
|
* establish a session.
|
||||||
*
|
*
|
||||||
* @param files - Filename or an array of filenames of script/literature files to copy. Note that if a file is located in a subdirectory, the filename must include the leading `/`.
|
* @param files - Filename or an array of filenames of script/literature files to copy. Note that if a file is located in a subdirectory, the filename must include the leading `/`.
|
||||||
* @param destination - Hostname/IP of the destination server, which is the server to which the file will be copied.
|
* @param destination - Hostname/IP of the destination server, which is the server to which the file will be copied.
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { OpenScript } from "./OpenScript";
|
|||||||
import { Tab } from "./Tab";
|
import { Tab } from "./Tab";
|
||||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||||
|
|
||||||
const tabsMaxWidth = 1640;
|
|
||||||
const searchWidth = 180;
|
const searchWidth = 180;
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@@ -101,7 +100,6 @@ export function Tabs({ scripts, currentScript, onTabClick, onTabClose, onTabUpda
|
|||||||
<Droppable droppableId="tabs" direction="horizontal">
|
<Droppable droppableId="tabs" direction="horizontal">
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<Box
|
<Box
|
||||||
maxWidth={`${tabsMaxWidth}px`}
|
|
||||||
display="flex"
|
display="flex"
|
||||||
flexGrow="1"
|
flexGrow="1"
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { Settings } from "../Settings/Settings";
|
|||||||
import type { ScriptKey } from "../utils/helpers/scriptKey";
|
import type { ScriptKey } from "../utils/helpers/scriptKey";
|
||||||
import { assertObject } from "../utils/TypeAssertion";
|
import { assertObject } from "../utils/TypeAssertion";
|
||||||
import { clampNumber } from "../utils/helpers/clampNumber";
|
import { clampNumber } from "../utils/helpers/clampNumber";
|
||||||
|
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||||
|
|
||||||
export interface BaseServerConstructorParams {
|
export interface BaseServerConstructorParams {
|
||||||
adminRights?: boolean;
|
adminRights?: boolean;
|
||||||
@@ -233,7 +234,7 @@ export abstract class BaseServer implements IServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateRamUsed(ram: number): void {
|
updateRamUsed(ram: number): void {
|
||||||
this.ramUsed = clampNumber(ram, 0, this.maxRam);
|
this.ramUsed = roundToTwo(clampNumber(ram, 0, this.maxRam));
|
||||||
}
|
}
|
||||||
|
|
||||||
pushProgram(program: ProgramFilePath | CompletedProgramName): void {
|
pushProgram(program: ProgramFilePath | CompletedProgramName): void {
|
||||||
|
|||||||
@@ -359,6 +359,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
|||||||
canStaneksGift && { key_: Page.StaneksGift, icon: DeveloperBoardIcon },
|
canStaneksGift && { key_: Page.StaneksGift, icon: DeveloperBoardIcon },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Typography id="sidebar-extra-hook-0"></Typography>
|
||||||
<Divider />
|
<Divider />
|
||||||
<SidebarAccordion
|
<SidebarAccordion
|
||||||
key_="Character"
|
key_="Character"
|
||||||
@@ -386,6 +387,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
|||||||
canOpenGrafting && { key_: Page.Grafting, icon: BiotechIcon },
|
canOpenGrafting && { key_: Page.Grafting, icon: BiotechIcon },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Typography id="sidebar-extra-hook-1"></Typography>
|
||||||
<Divider />
|
<Divider />
|
||||||
<SidebarAccordion
|
<SidebarAccordion
|
||||||
key_="World"
|
key_="World"
|
||||||
@@ -411,6 +413,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
|||||||
canDarkNet && { key_: Page.DarkNet, icon: ShareIcon },
|
canDarkNet && { key_: Page.DarkNet, icon: ShareIcon },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Typography id="sidebar-extra-hook-2"></Typography>
|
||||||
<Divider />
|
<Divider />
|
||||||
<SidebarAccordion
|
<SidebarAccordion
|
||||||
key_="Help"
|
key_="Help"
|
||||||
@@ -428,6 +431,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
|||||||
process.env.NODE_ENV === "development" && { key_: Page.DevMenu, icon: DeveloperBoardIcon },
|
process.env.NODE_ENV === "development" && { key_: Page.DevMenu, icon: DeveloperBoardIcon },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Typography id="sidebar-extra-hook-3"></Typography>
|
||||||
</List>
|
</List>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const TerminalHelpText: string[] = [
|
|||||||
" analyze Get information about the current machine ",
|
" analyze Get information about the current machine ",
|
||||||
" backdoor Install a backdoor on the current machine ",
|
" backdoor Install a backdoor on the current machine ",
|
||||||
" buy [-l/-a/program] Purchase a program through the Dark Web",
|
" buy [-l/-a/program] Purchase a program through the Dark Web",
|
||||||
" cat [file] Display a .msg, .lit, or text file",
|
" cat [file] Display the contents of a file",
|
||||||
" cd [dir] Change to a new directory",
|
" cd [dir] Change to a new directory",
|
||||||
" changelog Display changelog",
|
" changelog Display changelog",
|
||||||
" check [script] [args...] Print a script's logs to Terminal",
|
" check [script] [args...] Print a script's logs to Terminal",
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ import { commitHash } from "../utils/helpers/commitHash";
|
|||||||
import { apr1 } from "./commands/apr1";
|
import { apr1 } from "./commands/apr1";
|
||||||
import { changelog } from "./commands/changelog";
|
import { changelog } from "./commands/changelog";
|
||||||
import { clear } from "./commands/clear";
|
import { clear } from "./commands/clear";
|
||||||
|
import { mkdir } from "./commands/mkdir";
|
||||||
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
|
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
|
||||||
import { Engine } from "../engine";
|
import { Engine } from "../engine";
|
||||||
import { Directory, resolveDirectory, root } from "../Paths/Directory";
|
import { Directory, resolveDirectory, root } from "../Paths/Directory";
|
||||||
@@ -134,8 +135,12 @@ export const TerminalCommands: Record<string, (args: (string | number | boolean)
|
|||||||
vim: vim,
|
vim: vim,
|
||||||
weaken: weaken,
|
weaken: weaken,
|
||||||
wget: wget,
|
wget: wget,
|
||||||
|
mkdir: mkdir,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// "mkdir" is a "hidden" command; i.e., it is not shown in help text or autocomplete.
|
||||||
|
export const supportedCommands = Object.keys(TerminalCommands).filter((command) => command !== "mkdir");
|
||||||
|
|
||||||
export class Terminal {
|
export class Terminal {
|
||||||
// Flags to determine whether the player is currently running a hack or an analyze
|
// Flags to determine whether the player is currently running a hack or an analyze
|
||||||
action: TTimer | null = null;
|
action: TTimer | null = null;
|
||||||
@@ -149,6 +154,8 @@ export class Terminal {
|
|||||||
|
|
||||||
// True if a Coding Contract prompt is opened
|
// True if a Coding Contract prompt is opened
|
||||||
contractOpen = false;
|
contractOpen = false;
|
||||||
|
// True if a prompt is opened via the ns.prompt() API
|
||||||
|
nsPromptApiOpen = false;
|
||||||
|
|
||||||
// Path of current directory
|
// Path of current directory
|
||||||
currDir = "" as Directory;
|
currDir = "" as Directory;
|
||||||
@@ -875,8 +882,7 @@ export class Terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function findSimilarCommands(command: string): string[] {
|
function findSimilarCommands(command: string): string[] {
|
||||||
const commands = Object.keys(TerminalCommands);
|
const offByOneLetter = supportedCommands.filter((c) => {
|
||||||
const offByOneLetter = commands.filter((c) => {
|
|
||||||
if (c.length !== command.length) return false;
|
if (c.length !== command.length) return false;
|
||||||
let diff = 0;
|
let diff = 0;
|
||||||
for (let i = 0; i < c.length; i++) {
|
for (let i = 0; i < c.length; i++) {
|
||||||
@@ -884,6 +890,6 @@ function findSimilarCommands(command: string): string[] {
|
|||||||
}
|
}
|
||||||
return diff === 1;
|
return diff === 1;
|
||||||
});
|
});
|
||||||
const subset = commands.filter((c) => c.includes(command)).sort((a, b) => a.length - b.length);
|
const subset = supportedCommands.filter((c) => c.includes(command)).sort((a, b) => a.length - b.length);
|
||||||
return Array.from(new Set([...offByOneLetter, ...subset])).slice(0, 3);
|
return Array.from(new Set([...offByOneLetter, ...subset])).slice(0, 3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { Terminal } from "../../Terminal";
|
||||||
|
|
||||||
|
export function mkdir(): void {
|
||||||
|
Terminal.error(
|
||||||
|
"Directories do not exist in the Bitburner filesystem. They are simply part of the file path.\n" +
|
||||||
|
`For example, with "/foo/bar.txt", there is no actual "/foo" directory.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user