Merge pull request #1817 from danielyxie/dev

BN13: They're Lunatics
This commit is contained in:
hydroflame 2021-12-03 16:14:51 -05:00 committed by GitHub
commit 403ab167b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 4616 additions and 261 deletions

23
css/staneksgift.scss Normal file

@ -0,0 +1,23 @@
.staneksgift_row {
padding: 0;
margin: 0;
}
.staneksgift_cell {
width: 25px;
height: 25px;
background-color: #808080;
font-color: white;
padding: 0px;
margin: 0px;
border: 1px solid black;
float: left;
}
.staneksgift_cell:first-child {
clear: left;
}
.staneksgift_container {
position: fixed;
}

187
dist/bitburner.d.ts vendored

@ -1,3 +1,15 @@
/**
* @public
*/
export declare interface ActiveFragment {
id: number;
avgCharge: number;
numCharge: number;
rotation: number;
x: number;
y: number;
}
/** /**
* Data representing the internal values of an Augmentation. * Data representing the internal values of an Augmentation.
* @public * @public
@ -890,6 +902,17 @@ export declare interface Formulas {
hacknetServers: HacknetServersFormulas; hacknetServers: HacknetServersFormulas;
} }
/**
* @public
*/
export declare interface Fragment {
id: number;
shape: boolean[][];
type: number;
power: number;
limit: number;
}
/** /**
* Gang API * Gang API
* @remarks * @remarks
@ -1769,6 +1792,11 @@ export declare interface NS extends Singularity {
* RAM cost: 0 GB * RAM cost: 0 GB
*/ */
readonly formulas: Formulas; readonly formulas: Formulas;
/**
* Namespace for stanek functions.
* RAM cost: 0 GB
*/
readonly stanek: Stanek;
/** /**
* Arguments passed into the script. * Arguments passed into the script.
@ -3572,6 +3600,45 @@ export declare interface Server {
/** Flag indicating whether the SSH Port is open */ /** Flag indicating whether the SSH Port is open */
sshPortOpen: boolean; sshPortOpen: boolean;
/** Flag indicating whether this is a purchased server */
purchasedByPlayer: boolean;
/** Flag indicating whether this server has a backdoor installed by a player */
backdoorInstalled: boolean;
/**
* Initial server security level
* (i.e. security level when the server was created)
*/
baseDifficulty: number;
/** Server Security Level */
hackDifficulty: number;
/** Minimum server security level that this server can be weakened to */
minDifficulty: number;
/** How much money currently resides on the server and can be hacked */
moneyAvailable: number;
/** Maximum amount of money that this server can hold */
moneyMax: number;
/** Number of open ports required in order to gain admin/root access */
numOpenPortsRequired: number;
/** How many ports are currently opened on the server */
openPortCount: number;
/** Hacking level required to hack this server */
requiredHackingSkill: number;
/**
* Parameter that affects how effectively this server's money can
* be increased using the grow() Netscript function
*/
serverGrowth: number;
} }
/** /**
@ -4282,24 +4349,6 @@ export declare interface Singularity {
* @returns True if the installation was successful. * @returns True if the installation was successful.
*/ */
installBackdoor(): Promise<void>; installBackdoor(): Promise<void>;
/**
* SF4.2 - Check if the player is focused.
* @remarks
* RAM cost: 0.1 GB
*
*
* @returns True if the player is focused.
*/
isFocused(): void;
/**
* SF4.2 - Set the players focus.
* @remarks
* RAM cost: 0.1 GB
*
*/
setFocus(focus: boolean): void;
} }
/** /**
@ -4610,6 +4659,108 @@ export declare interface SourceFileLvl {
lvl: number; lvl: number;
} }
/**
* Stanek's Gift API.
* @public
*/
export declare interface Stanek {
/**
* Stanek's Gift width.
* @remarks
* RAM cost: 0.4 GB
* @returns The width of the gift.
*/
width(): number;
/**
* Stanek's Gift height.
* @remarks
* RAM cost: 0.4 GB
* @returns The height of the gift.
*/
height(): number;
/**
* Charge a fragment, increasing it's power.
* @remarks
* RAM cost: 0.4 GB
* @param rootX - rootX Root X against which to align the top left of the fragment.
* @param rootY - rootY Root Y against which to align the top left of the fragment.
* @returns Promise that lasts until the charge action is over.
*/
charge(rootX: number, rootY: number): Promise<void>;
/**
* List possible fragments.
* @remarks
* RAM cost: cost: 0 GB
*
* @returns List of possible fragments.
*/
fragmentDefinitions(): Fragment[];
/**
* List of fragments in Stanek's Gift.
* @remarks
* RAM cost: cost: 5 GB
*
* @returns List of active fragments placed on Stanek's Gift.
*/
activeFragments(): ActiveFragment[];
/**
* Clear the board of all fragments.
* @remarks
* RAM cost: cost: 0 GB
*/
clear(): void;
/**
* Check if fragment can be placed at specified location.
* @remarks
* RAM cost: cost: 0.5 GB
*
* @param rootX - rootX Root X against which to align the top left of the fragment.
* @param rootY - rootY Root Y against which to align the top left of the fragment.
* @param rotation - rotation A number from 0 to 3, the mount of 90 degree turn to take.
* @param fragmentId - fragmentId ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
canPlace(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Place fragment on Stanek's Gift.
* @remarks
* RAM cost: cost: 5 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @param rotation - A number from 0 to 3, the mount of 90 degree turn to take.
* @param fragmentId - ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
place(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Get placed fragment at location.
* @remarks
* RAM cost: cost: 5 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
get(rootX: number, rootY: number): ActiveFragment | undefined;
/**
* Remove fragment at location.
* @remarks
* RAM cost: cost: 0.15 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
remove(rootX: number, rootY: number): boolean;
}
/** /**
* Return value of {@link TIX.getOrders | getOrders} * Return value of {@link TIX.getOrders | getOrders}
* @public * @public

36
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,68 @@
Changelog Changelog
========= =========
v1.1.0 - 2021-12-03 BN13: They're Lunatics (hydroflame & community)
-------------------------------------------------------
** BN13: They're Lunatics **
* BN13 added.
** Steam **
* Tested on all 3 major OS.
* 94 achievements added
* Release is 2021-12-10.
** Netscript **
* tprintf crashes when not giving a format as first arg.
* tprintf no longer prints filename (@BartKoppelmans)
* TIX buy/sell/sellShort all return askprice/bidprice (@Insight)
* getRunningScript now works.
* Fix disableLog for gang and TIX API
* getOwnedSourceFiles is not singularity anymore (makes it easier to share scripts.) (@theit8514)
* true/false is a valid value to send to other scripts.
* workForFaction no longer returns null when trying to work for gang.
* Scripts logging no longer generates the string if logging is disabled.
This should give performance boost for some scripts.
** Gang **
* Gang with 0 territory can no longer fight
* Territory now caps at exactly 0 or 1.
** Misc. **
* Clicking "previous" on the browser will not pretend you had unsaved information
allowing you to cancel if needs be.
* Fixed some tail box coloring issue.
* Fixed BladeBurner getCityCommunities ram cost
* The download terminal command no longer duplicate extensions (@Insight)
* Fix #000 on #000 text in blackjack. (@Insight)
* Remove reference to .fconf
* Tail boxes all die on soft reset.
* Fix codign contract focus bug.
* Megacorp factions simply re-invite you instead of auto added on reset. (@theit8514)
* Tail window is bound to html body.
* Infiltration reward is tied to your potential stats, not your actual stats
So you won't lose reward for doing the same thing over and over.
* intelligence lowers program creation requirements.
* Terminal parses true as the boolean, not the string.
* Tail and kill autocomplete using the ns2 autocomplete feature.
* scan-analyze doesn't take up as many terminal entries.
* GangOtherInfo documentation now renders correctly.
* ActiveScripts search box also searches for script names.
* Infinite money no longer allows for infinite hacknet server.
* Blackjack doesn't make you lose money twice.
* Recent Scripts is now from most to least recent.
* Fix mathjax ascii art bug in NiteSec.
* Remove warning that the theme editor is slow, it's only slow in dev mode.
* In BN8 is it possible to reduce the money on a server without gaining any.
* In the options, the timestamp feature has a placeholder explaining the expected format.
* Bunch of doc typo fix. (hydroflame & @BartKoppelmans & @cvr-119)
* nerf noodle bar
v1.0.2 - 2021-11-17 It's the little things (hydroflame) v1.0.2 - 2021-11-17 It's the little things (hydroflame)
------------------------------------------------------- -------------------------------------------------------

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '1.0' version = '1.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '1.0.2' release = '1.1.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

@ -0,0 +1,20 @@
.. _netscriptstanek:
Netscript Stanek Functions
============================
.. warning:: This page contains spoilers for the game.
The Stanek API allow you to control Stanek's Gift.
All these function require Source-File 13-1 or to be in BitNode 13.
.. toctree::
charge() <stanekapi/charge>
fragmentDefinitions() <stanekapi/fragmentDefinitions>
placedFragments() <stanekapi/placedFragments>
clear() <stanekapi/clear>
canPlace() <stanekapi/canPlace>
place() <stanekapi/place>
fragmentAt() <stanekapi/fragmentAt>
deleteAt() <stanekapi/deleteAt>

@ -0,0 +1,16 @@
canPlace() Netscript Function
=======================================
.. js:function:: canPlace(worldX, worldY, rotation, fragmentId)
:RAM cost: 0.5 GB
:param int worldX: World X against which to align the top left of the fragment.
:param int worldY: World Y against which to align the top left of the fragment.
:param int rotation: A number from 0 to 3, the mount of 90 degree turn to take.
:param int fragmentId: ID of the fragment to place.
:returns: `true` if the fragment can be placed at that position. `false` otherwise.
Example:
.. code-block:: javascript
canPlace(0, 4, 17); // returns true

@ -0,0 +1,21 @@
charge() Netscript Function
=======================================
.. js:function:: charge(worldX, worldY)
:RAM cost: 0.4 GB
:param int worldX: World X of the fragment to charge.
:param int worldY: World Y of the fragment to charge.
Charge a fragment, increasing it's power but also it's heat. The
effectiveness of the charge depends on the amount of ram the running script
consumes as well as the fragments current heat. This operation takes time to
complete.
Example:
.. code-block:: javascript
charge(0, 4); // Finishes 5 seconds later.
.. warning::
Netscript JS users: This function is `async`

@ -0,0 +1,13 @@
clear() Netscript Function
=======================================
.. js:function:: clear()
:RAM cost: 0 GB
Completely clear Stanek's Gift.
Example:
.. code-block:: javascript
clear(); // No more fragments.

@ -0,0 +1,16 @@
deleteAt() Netscript Function
=======================================
.. js:function:: deleteAt(worldX, worldY)
:RAM cost: 0.15 GB
:param int worldX: World X coordinate of the fragment to delete.
:param int worldY: World Y coordinate of the fragment to delete.
:returns: `true` if the fragment was deleted. `false` otherwise.
Delete the fragment located at `[worldX, worldY]`.
Example:
.. code-block:: javascript
deleteAt(0, 4); // returns true

@ -0,0 +1,28 @@
fragmentAt() Netscript Function
=======================================
.. js:function:: fragmentAt(worldX, worldY)
:RAM cost: 2 GB
:param int worldX: World X coordinate of the fragment.
:param int worldY: World Y coordinate of the fragment.
:returns: The fragment located at `[worldX, worldY]` in Stanek's Gift, or null.
.. code-block:: typescript
{
// In world coordinates
x: number;
y: number;
heat: number;
charge: number;
id: number;
shape: boolean[][];
type: string;
magnitude: number;
limit: number;
}
Example:
.. code-block:: javascript
var fragment = fragmentAt(0, 4);
print(fragment); // {'heat': 50, 'charge': 98}

@ -0,0 +1,23 @@
fragmentDefinitions() Netscript Function
=======================================
.. js:function:: fragmentDefinitions()
:RAM cost: 0 GB
:returns: The list of all fragment that can be embedded in Stanek's Gift.
.. code-block:: typescript
[
{
id: number;
shape: boolean[][];
type: string;
magnitude: number;
limit: number;
}
]
Example:
.. code-block:: javascript
var fragments = fragmentDefinitions();
print(fragment); // prints all possible fragments

@ -0,0 +1,16 @@
place() Netscript Function
=======================================
.. js:function:: place(worldX, worldY, fragmentId)
:RAM cost: 5 GB
:param int worldX: World X against which to align the top left of the fragment.
:param int worldY: World Y against which to align the top left of the fragment.
:param int rotation: A number from 0 to 3, the mount of 90 degree turn to take.
:param int fragmentId: ID of the fragment to place.
:returns: `true` if the fragment has been placed at that position. `false` otherwise.
Example:
.. code-block:: javascript
place(0, 4, 17); // returns true

@ -0,0 +1,26 @@
placedFragments() Netscript Function
=======================================
.. js:function:: placedFragments()
:RAM cost: 5 GB
:returns: The list of all fragment that are embedded in Stanek's Gift.
.. code-block:: typescript
[
{
// In world coordinates
x: number;
y: number;
charge: number;
id: number;
shape: boolean[][];
type: string;
power: number;
limit: number;
}
]
Example:
.. code-block:: javascript
var myFragments = placedFragments();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [avgCharge](./bitburner.activefragment.avgcharge.md)
## ActiveFragment.avgCharge property
<b>Signature:</b>
```typescript
avgCharge: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [id](./bitburner.activefragment.id.md)
## ActiveFragment.id property
<b>Signature:</b>
```typescript
id: number;
```

@ -0,0 +1,24 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md)
## ActiveFragment interface
<b>Signature:</b>
```typescript
export interface ActiveFragment
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [avgCharge](./bitburner.activefragment.avgcharge.md) | number | |
| [id](./bitburner.activefragment.id.md) | number | |
| [numCharge](./bitburner.activefragment.numcharge.md) | number | |
| [rotation](./bitburner.activefragment.rotation.md) | number | |
| [x](./bitburner.activefragment.x.md) | number | |
| [y](./bitburner.activefragment.y.md) | number | |

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [numCharge](./bitburner.activefragment.numcharge.md)
## ActiveFragment.numCharge property
<b>Signature:</b>
```typescript
numCharge: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [rotation](./bitburner.activefragment.rotation.md)
## ActiveFragment.rotation property
<b>Signature:</b>
```typescript
rotation: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [x](./bitburner.activefragment.x.md)
## ActiveFragment.x property
<b>Signature:</b>
```typescript
x: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [ActiveFragment](./bitburner.activefragment.md) &gt; [y](./bitburner.activefragment.y.md)
## ActiveFragment.y property
<b>Signature:</b>
```typescript
y: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md) &gt; [id](./bitburner.fragment.id.md)
## Fragment.id property
<b>Signature:</b>
```typescript
id: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md) &gt; [limit](./bitburner.fragment.limit.md)
## Fragment.limit property
<b>Signature:</b>
```typescript
limit: number;
```

@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md)
## Fragment interface
<b>Signature:</b>
```typescript
export interface Fragment
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [id](./bitburner.fragment.id.md) | number | |
| [limit](./bitburner.fragment.limit.md) | number | |
| [power](./bitburner.fragment.power.md) | number | |
| [shape](./bitburner.fragment.shape.md) | boolean\[\]\[\] | |
| [type](./bitburner.fragment.type.md) | number | |

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md) &gt; [power](./bitburner.fragment.power.md)
## Fragment.power property
<b>Signature:</b>
```typescript
power: number;
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md) &gt; [shape](./bitburner.fragment.shape.md)
## Fragment.shape property
<b>Signature:</b>
```typescript
shape: boolean[][];
```

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Fragment](./bitburner.fragment.md) &gt; [type](./bitburner.fragment.type.md)
## Fragment.type property
<b>Signature:</b>
```typescript
type: number;
```

@ -8,6 +8,7 @@
| Interface | Description | | Interface | Description |
| --- | --- | | --- | --- |
| [ActiveFragment](./bitburner.activefragment.md) | |
| [AugmentationStats](./bitburner.augmentationstats.md) | Data representing the internal values of an Augmentation. | | [AugmentationStats](./bitburner.augmentationstats.md) | Data representing the internal values of an Augmentation. |
| [AugmentPair](./bitburner.augmentpair.md) | Return value of [getSleevePurchasableAugs](./bitburner.sleeve.getsleevepurchasableaugs.md) | | [AugmentPair](./bitburner.augmentpair.md) | Return value of [getSleevePurchasableAugs](./bitburner.sleeve.getsleevepurchasableaugs.md) |
| [BasicHGWOptions](./bitburner.basichgwoptions.md) | Options to affect the behavior of [hack](./bitburner.ns.hack.md)<!-- -->, [grow](./bitburner.ns.grow.md)<!-- -->, and [weaken](./bitburner.ns.weaken.md)<!-- -->. | | [BasicHGWOptions](./bitburner.basichgwoptions.md) | Options to affect the behavior of [hack](./bitburner.ns.hack.md)<!-- -->, [grow](./bitburner.ns.grow.md)<!-- -->, and [weaken](./bitburner.ns.weaken.md)<!-- -->. |
@ -21,6 +22,7 @@
| [CrimeStats](./bitburner.crimestats.md) | Data representing the internal values of a crime. | | [CrimeStats](./bitburner.crimestats.md) | Data representing the internal values of a crime. |
| [EquipmentStats](./bitburner.equipmentstats.md) | Object representing data representing a gang member equipment. | | [EquipmentStats](./bitburner.equipmentstats.md) | Object representing data representing a gang member equipment. |
| [Formulas](./bitburner.formulas.md) | | | [Formulas](./bitburner.formulas.md) | |
| [Fragment](./bitburner.fragment.md) | |
| [Gang](./bitburner.gang.md) | Gang API | | [Gang](./bitburner.gang.md) | Gang API |
| [GangGenInfo](./bitburner.ganggeninfo.md) | Gang general info. | | [GangGenInfo](./bitburner.ganggeninfo.md) | Gang general info. |
| [GangMemberAscension](./bitburner.gangmemberascension.md) | | | [GangMemberAscension](./bitburner.gangmemberascension.md) | |
@ -50,6 +52,7 @@
| [SleeveTask](./bitburner.sleevetask.md) | Object representing a sleeve current task. | | [SleeveTask](./bitburner.sleevetask.md) | Object representing a sleeve current task. |
| [SleeveWorkGains](./bitburner.sleeveworkgains.md) | | | [SleeveWorkGains](./bitburner.sleeveworkgains.md) | |
| [SourceFileLvl](./bitburner.sourcefilelvl.md) | | | [SourceFileLvl](./bitburner.sourcefilelvl.md) | |
| [Stanek](./bitburner.stanek.md) | Stanek's Gift API. |
| [StockOrder](./bitburner.stockorder.md) | Return value of [getOrders](./bitburner.tix.getorders.md) | | [StockOrder](./bitburner.stockorder.md) | Return value of [getOrders](./bitburner.tix.getorders.md) |
| [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) | | [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) |
| [TIX](./bitburner.tix.md) | Stock market API | | [TIX](./bitburner.tix.md) | Stock market API |

@ -24,6 +24,7 @@ export interface NS extends Singularity
| [gang](./bitburner.ns.gang.md) | [Gang](./bitburner.gang.md) | Namespace for gang functions. | | [gang](./bitburner.ns.gang.md) | [Gang](./bitburner.gang.md) | Namespace for gang functions. |
| [hacknet](./bitburner.ns.hacknet.md) | [Hacknet](./bitburner.hacknet.md) | Namespace for hacknet functions. | | [hacknet](./bitburner.ns.hacknet.md) | [Hacknet](./bitburner.hacknet.md) | Namespace for hacknet functions. |
| [sleeve](./bitburner.ns.sleeve.md) | [Sleeve](./bitburner.sleeve.md) | Namespace for sleeve functions. | | [sleeve](./bitburner.ns.sleeve.md) | [Sleeve](./bitburner.sleeve.md) | Namespace for sleeve functions. |
| [stanek](./bitburner.ns.stanek.md) | [Stanek](./bitburner.stanek.md) | Namespace for stanek functions. RAM cost: 0 GB |
| [stock](./bitburner.ns.stock.md) | [TIX](./bitburner.tix.md) | Namespace for stock functions. | | [stock](./bitburner.ns.stock.md) | [TIX](./bitburner.tix.md) | Namespace for stock functions. |
## Methods ## Methods

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [NS](./bitburner.ns.md) &gt; [stanek](./bitburner.ns.stanek.md)
## NS.stanek property
Namespace for stanek functions. RAM cost: 0 GB
<b>Signature:</b>
```typescript
readonly stanek: Stanek;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [backdoorInstalled](./bitburner.server.backdoorinstalled.md)
## Server.backdoorInstalled property
Flag indicating whether this server has a backdoor installed by a player
<b>Signature:</b>
```typescript
backdoorInstalled: boolean;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [baseDifficulty](./bitburner.server.basedifficulty.md)
## Server.baseDifficulty property
Initial server security level (i.e. security level when the server was created)
<b>Signature:</b>
```typescript
baseDifficulty: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [hackDifficulty](./bitburner.server.hackdifficulty.md)
## Server.hackDifficulty property
Server Security Level
<b>Signature:</b>
```typescript
hackDifficulty: number;
```

@ -16,16 +16,27 @@ export interface Server
| Property | Type | Description | | Property | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| [backdoorInstalled](./bitburner.server.backdoorinstalled.md) | boolean | Flag indicating whether this server has a backdoor installed by a player |
| [baseDifficulty](./bitburner.server.basedifficulty.md) | number | Initial server security level (i.e. security level when the server was created) |
| [cpuCores](./bitburner.server.cpucores.md) | number | How many CPU cores this server has. Maximum of 8. Affects magnitude of grow and weaken. | | [cpuCores](./bitburner.server.cpucores.md) | number | How many CPU cores this server has. Maximum of 8. Affects magnitude of grow and weaken. |
| [ftpPortOpen](./bitburner.server.ftpportopen.md) | boolean | Flag indicating whether the FTP port is open | | [ftpPortOpen](./bitburner.server.ftpportopen.md) | boolean | Flag indicating whether the FTP port is open |
| [hackDifficulty](./bitburner.server.hackdifficulty.md) | number | Server Security Level |
| [hasAdminRights](./bitburner.server.hasadminrights.md) | boolean | Flag indicating whether player has admin/root access to this server | | [hasAdminRights](./bitburner.server.hasadminrights.md) | boolean | Flag indicating whether player has admin/root access to this server |
| [hostname](./bitburner.server.hostname.md) | string | Hostname. Must be unique | | [hostname](./bitburner.server.hostname.md) | string | Hostname. Must be unique |
| [httpPortOpen](./bitburner.server.httpportopen.md) | boolean | Flag indicating whether HTTP Port is open | | [httpPortOpen](./bitburner.server.httpportopen.md) | boolean | Flag indicating whether HTTP Port is open |
| [ip](./bitburner.server.ip.md) | string | IP Address. Must be unique | | [ip](./bitburner.server.ip.md) | string | IP Address. Must be unique |
| [isConnectedTo](./bitburner.server.isconnectedto.md) | boolean | Flag indicating whether player is curently connected to this server | | [isConnectedTo](./bitburner.server.isconnectedto.md) | boolean | Flag indicating whether player is curently connected to this server |
| [maxRam](./bitburner.server.maxram.md) | number | RAM (GB) available on this server | | [maxRam](./bitburner.server.maxram.md) | number | RAM (GB) available on this server |
| [minDifficulty](./bitburner.server.mindifficulty.md) | number | Minimum server security level that this server can be weakened to |
| [moneyAvailable](./bitburner.server.moneyavailable.md) | number | How much money currently resides on the server and can be hacked |
| [moneyMax](./bitburner.server.moneymax.md) | number | Maximum amount of money that this server can hold |
| [numOpenPortsRequired](./bitburner.server.numopenportsrequired.md) | number | Number of open ports required in order to gain admin/root access |
| [openPortCount](./bitburner.server.openportcount.md) | number | How many ports are currently opened on the server |
| [organizationName](./bitburner.server.organizationname.md) | string | Name of company/faction/etc. that this server belongs to. Optional, not applicable to all Servers | | [organizationName](./bitburner.server.organizationname.md) | string | Name of company/faction/etc. that this server belongs to. Optional, not applicable to all Servers |
| [purchasedByPlayer](./bitburner.server.purchasedbyplayer.md) | boolean | Flag indicating whether this is a purchased server |
| [ramUsed](./bitburner.server.ramused.md) | number | RAM (GB) used. i.e. unavailable RAM | | [ramUsed](./bitburner.server.ramused.md) | number | RAM (GB) used. i.e. unavailable RAM |
| [requiredHackingSkill](./bitburner.server.requiredhackingskill.md) | number | Hacking level required to hack this server |
| [serverGrowth](./bitburner.server.servergrowth.md) | number | Parameter that affects how effectively this server's money can be increased using the grow() Netscript function |
| [smtpPortOpen](./bitburner.server.smtpportopen.md) | boolean | Flag indicating whether SMTP Port is open | | [smtpPortOpen](./bitburner.server.smtpportopen.md) | boolean | Flag indicating whether SMTP Port is open |
| [sqlPortOpen](./bitburner.server.sqlportopen.md) | boolean | Flag indicating whether SQL Port is open | | [sqlPortOpen](./bitburner.server.sqlportopen.md) | boolean | Flag indicating whether SQL Port is open |
| [sshPortOpen](./bitburner.server.sshportopen.md) | boolean | Flag indicating whether the SSH Port is open | | [sshPortOpen](./bitburner.server.sshportopen.md) | boolean | Flag indicating whether the SSH Port is open |

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [minDifficulty](./bitburner.server.mindifficulty.md)
## Server.minDifficulty property
Minimum server security level that this server can be weakened to
<b>Signature:</b>
```typescript
minDifficulty: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [moneyAvailable](./bitburner.server.moneyavailable.md)
## Server.moneyAvailable property
How much money currently resides on the server and can be hacked
<b>Signature:</b>
```typescript
moneyAvailable: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [moneyMax](./bitburner.server.moneymax.md)
## Server.moneyMax property
Maximum amount of money that this server can hold
<b>Signature:</b>
```typescript
moneyMax: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [numOpenPortsRequired](./bitburner.server.numopenportsrequired.md)
## Server.numOpenPortsRequired property
Number of open ports required in order to gain admin/root access
<b>Signature:</b>
```typescript
numOpenPortsRequired: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [openPortCount](./bitburner.server.openportcount.md)
## Server.openPortCount property
How many ports are currently opened on the server
<b>Signature:</b>
```typescript
openPortCount: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [purchasedByPlayer](./bitburner.server.purchasedbyplayer.md)
## Server.purchasedByPlayer property
Flag indicating whether this is a purchased server
<b>Signature:</b>
```typescript
purchasedByPlayer: boolean;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [requiredHackingSkill](./bitburner.server.requiredhackingskill.md)
## Server.requiredHackingSkill property
Hacking level required to hack this server
<b>Signature:</b>
```typescript
requiredHackingSkill: number;
```

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Server](./bitburner.server.md) &gt; [serverGrowth](./bitburner.server.servergrowth.md)
## Server.serverGrowth property
Parameter that affects how effectively this server's money can be increased using the grow() Netscript function
<b>Signature:</b>
```typescript
serverGrowth: number;
```

@ -1,23 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Singularity](./bitburner.singularity.md) &gt; [isFocused](./bitburner.singularity.isfocused.md)
## Singularity.isFocused() method
SF4.2 - Check if the player is focused.
<b>Signature:</b>
```typescript
isFocused(): void;
```
<b>Returns:</b>
void
True if the player is focused.
## Remarks
RAM cost: 0.1 GB

@ -52,13 +52,11 @@ This API requires Source-File 4 level 1 / 2 / 3 to use.
| [installAugmentations(cbScript)](./bitburner.singularity.installaugmentations.md) | SF4.3 - Install your purchased augmentations. | | [installAugmentations(cbScript)](./bitburner.singularity.installaugmentations.md) | SF4.3 - Install your purchased augmentations. |
| [installBackdoor()](./bitburner.singularity.installbackdoor.md) | SF4.1 - Run the backdoor command in the terminal. | | [installBackdoor()](./bitburner.singularity.installbackdoor.md) | SF4.1 - Run the backdoor command in the terminal. |
| [isBusy()](./bitburner.singularity.isbusy.md) | SF4.1 - Check if the player is busy. | | [isBusy()](./bitburner.singularity.isbusy.md) | SF4.1 - Check if the player is busy. |
| [isFocused()](./bitburner.singularity.isfocused.md) | SF4.2 - Check if the player is focused. |
| [joinFaction(faction)](./bitburner.singularity.joinfaction.md) | SF4.2 - Join a faction. | | [joinFaction(faction)](./bitburner.singularity.joinfaction.md) | SF4.2 - Join a faction. |
| [manualHack()](./bitburner.singularity.manualhack.md) | SF4.1 - Run the hack command in the terminal. | | [manualHack()](./bitburner.singularity.manualhack.md) | SF4.1 - Run the hack command in the terminal. |
| [purchaseAugmentation(faction, augmentation)](./bitburner.singularity.purchaseaugmentation.md) | SF4.3 - Purchase an augmentation | | [purchaseAugmentation(faction, augmentation)](./bitburner.singularity.purchaseaugmentation.md) | SF4.3 - Purchase an augmentation |
| [purchaseProgram(programName)](./bitburner.singularity.purchaseprogram.md) | SF4.1 - Purchase a program from the dark web. | | [purchaseProgram(programName)](./bitburner.singularity.purchaseprogram.md) | SF4.1 - Purchase a program from the dark web. |
| [purchaseTor()](./bitburner.singularity.purchasetor.md) | SF4.1 - Purchase the TOR router. | | [purchaseTor()](./bitburner.singularity.purchasetor.md) | SF4.1 - Purchase the TOR router. |
| [setFocus(focus)](./bitburner.singularity.setfocus.md) | SF4.2 - Set the players focus. |
| [softReset(cbScript)](./bitburner.singularity.softreset.md) | SF4.3 - Soft reset the game. | | [softReset(cbScript)](./bitburner.singularity.softreset.md) | SF4.3 - Soft reset the game. |
| [stopAction()](./bitburner.singularity.stopaction.md) | SF4.1 - Stop the current action. | | [stopAction()](./bitburner.singularity.stopaction.md) | SF4.1 - Stop the current action. |
| [travelToCity(city)](./bitburner.singularity.traveltocity.md) | SF4.1 - Travel to another city. | | [travelToCity(city)](./bitburner.singularity.traveltocity.md) | SF4.1 - Travel to another city. |

@ -1,28 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Singularity](./bitburner.singularity.md) &gt; [setFocus](./bitburner.singularity.setfocus.md)
## Singularity.setFocus() method
SF4.2 - Set the players focus.
<b>Signature:</b>
```typescript
setFocus(focus: boolean): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| focus | boolean | |
<b>Returns:</b>
void
## Remarks
RAM cost: 0.1 GB

@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [activeFragments](./bitburner.stanek.activefragments.md)
## Stanek.activeFragments() method
List of fragments in Stanek's Gift.
<b>Signature:</b>
```typescript
activeFragments(): ActiveFragment[];
```
<b>Returns:</b>
[ActiveFragment](./bitburner.activefragment.md)<!-- -->\[\]
List of active fragments placed on Stanek's Gift.
## Remarks
RAM cost: cost: 5 GB

@ -0,0 +1,33 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [canPlace](./bitburner.stanek.canplace.md)
## Stanek.canPlace() method
Check if fragment can be placed at specified location.
<b>Signature:</b>
```typescript
canPlace(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| rootX | number | rootX Root X against which to align the top left of the fragment. |
| rootY | number | rootY Root Y against which to align the top left of the fragment. |
| rotation | number | rotation A number from 0 to 3, the mount of 90 degree turn to take. |
| fragmentId | number | fragmentId ID of the fragment to place. |
<b>Returns:</b>
boolean
true if the fragment can be placed at that position. false otherwise.
## Remarks
RAM cost: cost: 0.5 GB

@ -0,0 +1,31 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [charge](./bitburner.stanek.charge.md)
## Stanek.charge() method
Charge a fragment, increasing it's power.
<b>Signature:</b>
```typescript
charge(rootX: number, rootY: number): Promise<void>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| rootX | number | rootX Root X against which to align the top left of the fragment. |
| rootY | number | rootY Root Y against which to align the top left of the fragment. |
<b>Returns:</b>
Promise&lt;void&gt;
Promise that lasts until the charge action is over.
## Remarks
RAM cost: 0.4 GB

@ -0,0 +1,21 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [clear](./bitburner.stanek.clear.md)
## Stanek.clear() method
Clear the board of all fragments.
<b>Signature:</b>
```typescript
clear(): void;
```
<b>Returns:</b>
void
## Remarks
RAM cost: cost: 0 GB

@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [fragmentDefinitions](./bitburner.stanek.fragmentdefinitions.md)
## Stanek.fragmentDefinitions() method
List possible fragments.
<b>Signature:</b>
```typescript
fragmentDefinitions(): Fragment[];
```
<b>Returns:</b>
[Fragment](./bitburner.fragment.md)<!-- -->\[\]
List of possible fragments.
## Remarks
RAM cost: cost: 0 GB

@ -0,0 +1,31 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [get](./bitburner.stanek.get.md)
## Stanek.get() method
Get placed fragment at location.
<b>Signature:</b>
```typescript
get(rootX: number, rootY: number): ActiveFragment | undefined;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| rootX | number | X against which to align the top left of the fragment. |
| rootY | number | Y against which to align the top left of the fragment. |
<b>Returns:</b>
[ActiveFragment](./bitburner.activefragment.md) \| undefined
The fragment at \[rootX, rootY\], if any.
## Remarks
RAM cost: cost: 5 GB

@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [height](./bitburner.stanek.height.md)
## Stanek.height() method
Stanek's Gift height.
<b>Signature:</b>
```typescript
height(): number;
```
<b>Returns:</b>
number
The height of the gift.
## Remarks
RAM cost: 0.4 GB

@ -0,0 +1,29 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md)
## Stanek interface
Stanek's Gift API.
<b>Signature:</b>
```typescript
interface Stanek
```
## Methods
| Method | Description |
| --- | --- |
| [activeFragments()](./bitburner.stanek.activefragments.md) | List of fragments in Stanek's Gift. |
| [canPlace(rootX, rootY, rotation, fragmentId)](./bitburner.stanek.canplace.md) | Check if fragment can be placed at specified location. |
| [charge(rootX, rootY)](./bitburner.stanek.charge.md) | Charge a fragment, increasing it's power. |
| [clear()](./bitburner.stanek.clear.md) | Clear the board of all fragments. |
| [fragmentDefinitions()](./bitburner.stanek.fragmentdefinitions.md) | List possible fragments. |
| [get(rootX, rootY)](./bitburner.stanek.get.md) | Get placed fragment at location. |
| [height()](./bitburner.stanek.height.md) | Stanek's Gift height. |
| [place(rootX, rootY, rotation, fragmentId)](./bitburner.stanek.place.md) | Place fragment on Stanek's Gift. |
| [remove(rootX, rootY)](./bitburner.stanek.remove.md) | Remove fragment at location. |
| [width()](./bitburner.stanek.width.md) | Stanek's Gift width. |

@ -0,0 +1,33 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [place](./bitburner.stanek.place.md)
## Stanek.place() method
Place fragment on Stanek's Gift.
<b>Signature:</b>
```typescript
place(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| rootX | number | X against which to align the top left of the fragment. |
| rootY | number | Y against which to align the top left of the fragment. |
| rotation | number | A number from 0 to 3, the mount of 90 degree turn to take. |
| fragmentId | number | ID of the fragment to place. |
<b>Returns:</b>
boolean
true if the fragment can be placed at that position. false otherwise.
## Remarks
RAM cost: cost: 5 GB

@ -0,0 +1,31 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [remove](./bitburner.stanek.remove.md)
## Stanek.remove() method
Remove fragment at location.
<b>Signature:</b>
```typescript
remove(rootX: number, rootY: number): boolean;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| rootX | number | X against which to align the top left of the fragment. |
| rootY | number | Y against which to align the top left of the fragment. |
<b>Returns:</b>
boolean
The fragment at \[rootX, rootY\], if any.
## Remarks
RAM cost: cost: 0.15 GB

@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [Stanek](./bitburner.stanek.md) &gt; [width](./bitburner.stanek.width.md)
## Stanek.width() method
Stanek's Gift width.
<b>Signature:</b>
```typescript
width(): number;
```
<b>Returns:</b>
number
The width of the gift.
## Remarks
RAM cost: 0.4 GB

@ -1,7 +1,7 @@
{ {
"name": "bitburner", "name": "bitburner",
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"version": "1.0.2", "version": "1.1.0",
"main": "electron-main.js", "main": "electron-main.js",
"author": { "author": {
"name": "Daniel Xie" "name": "Daniel Xie"

@ -2366,6 +2366,134 @@ function initAugmentations(): void {
resetAugmentation(BladesSimulacrum); resetAugmentation(BladesSimulacrum);
} }
// Special CotMG Augmentations
const ChurchOfTheMachineGodFactionName = "Church of the Machine God";
if (factionExists(ChurchOfTheMachineGodFactionName)) {
const StaneksGift1 = new Augmentation({
name: AugmentationNames.StaneksGift1,
repCost: 0,
moneyCost: 0,
info:
'Allison "Mother" Stanek imparts you with her gift. An ' +
"experimental Augmentation implanted at the base of the neck. " +
"It allows you to overclock your entire system by carefully " +
"changing the configuration.",
isSpecial: true,
hacking_chance_mult: 0.9,
hacking_speed_mult: 0.9,
hacking_money_mult: 0.9,
hacking_grow_mult: 0.9,
hacking_mult: 0.9,
strength_mult: 0.9,
defense_mult: 0.9,
dexterity_mult: 0.9,
agility_mult: 0.9,
charisma_mult: 0.9,
hacking_exp_mult: 0.9,
strength_exp_mult: 0.9,
defense_exp_mult: 0.9,
dexterity_exp_mult: 0.9,
agility_exp_mult: 0.9,
charisma_exp_mult: 0.9,
company_rep_mult: 0.9,
faction_rep_mult: 0.9,
crime_money_mult: 0.9,
crime_success_mult: 0.9,
hacknet_node_money_mult: 0.9,
hacknet_node_purchase_cost_mult: 1.1,
hacknet_node_ram_cost_mult: 1.1,
hacknet_node_core_cost_mult: 1.1,
hacknet_node_level_cost_mult: 1.1,
work_money_mult: 0.9,
stats: <>Its unstable nature decreases all your stats by 10%</>,
});
StaneksGift1.addToFactions([ChurchOfTheMachineGodFactionName]);
resetAugmentation(StaneksGift1);
const StaneksGift2 = new Augmentation({
name: AugmentationNames.StaneksGift2,
repCost: 1e6,
moneyCost: 0,
info:
"The next evolution is near, A coming together of man and machine. A synthesis greater than the birth of the human " +
"organism. Time spent with the gift has allowed for acclimitaztion of the invavise augment and the toll it takes upon " +
"your frame granting lesser penalty of 5% to all stats.",
prereqs: [AugmentationNames.StaneksGift1],
isSpecial: true,
hacking_chance_mult: 0.95 / 0.9,
hacking_speed_mult: 0.95 / 0.9,
hacking_money_mult: 0.95 / 0.9,
hacking_grow_mult: 0.95 / 0.9,
hacking_mult: 0.95 / 0.9,
strength_mult: 0.95 / 0.9,
defense_mult: 0.95 / 0.9,
dexterity_mult: 0.95 / 0.9,
agility_mult: 0.95 / 0.9,
charisma_mult: 0.95 / 0.9,
hacking_exp_mult: 0.95 / 0.9,
strength_exp_mult: 0.95 / 0.9,
defense_exp_mult: 0.95 / 0.9,
dexterity_exp_mult: 0.95 / 0.9,
agility_exp_mult: 0.95 / 0.9,
charisma_exp_mult: 0.95 / 0.9,
company_rep_mult: 0.95 / 0.9,
faction_rep_mult: 0.95 / 0.9,
crime_money_mult: 0.95 / 0.9,
crime_success_mult: 0.95 / 0.9,
hacknet_node_money_mult: 0.95 / 0.9,
hacknet_node_purchase_cost_mult: 1.05 / 1.1,
hacknet_node_ram_cost_mult: 1.05 / 1.1,
hacknet_node_core_cost_mult: 1.05 / 1.1,
hacknet_node_level_cost_mult: 1.05 / 1.1,
work_money_mult: 0.95 / 0.9,
stats: <>The penalty for the gift is reduced to 5%</>,
});
StaneksGift2.addToFactions([ChurchOfTheMachineGodFactionName]);
resetAugmentation(StaneksGift2);
const StaneksGift3 = new Augmentation({
name: AugmentationNames.StaneksGift3,
repCost: 1e8,
moneyCost: 0,
info:
"The synthesis of human and machine is nothing to fear. It is our destiny. " +
"You will become greater than the sum of our parts. As One. Enbrace your gift " +
"fully and wholly free of it's accursed toll. Serenity brings tranquility the form " +
"of no longer suffering a stat penalty. ",
prereqs: [AugmentationNames.StaneksGift2],
isSpecial: true,
hacking_chance_mult: 1 / 0.95,
hacking_speed_mult: 1 / 0.95,
hacking_money_mult: 1 / 0.95,
hacking_grow_mult: 1 / 0.95,
hacking_mult: 1 / 0.95,
strength_mult: 1 / 0.95,
defense_mult: 1 / 0.95,
dexterity_mult: 1 / 0.95,
agility_mult: 1 / 0.95,
charisma_mult: 1 / 0.95,
hacking_exp_mult: 1 / 0.95,
strength_exp_mult: 1 / 0.95,
defense_exp_mult: 1 / 0.95,
dexterity_exp_mult: 1 / 0.95,
agility_exp_mult: 1 / 0.95,
charisma_exp_mult: 1 / 0.95,
company_rep_mult: 1 / 0.95,
faction_rep_mult: 1 / 0.95,
crime_money_mult: 1 / 0.95,
crime_success_mult: 1 / 0.95,
hacknet_node_money_mult: 1 / 0.95,
hacknet_node_purchase_cost_mult: 1 / 1.05,
hacknet_node_ram_cost_mult: 1 / 1.05,
hacknet_node_core_cost_mult: 1 / 1.05,
hacknet_node_level_cost_mult: 1 / 1.05,
work_money_mult: 1 / 0.95,
stats: <>Staneks Gift has no penalty.</>,
});
StaneksGift3.addToFactions([ChurchOfTheMachineGodFactionName]);
resetAugmentation(StaneksGift3);
}
// Update costs based on how many have been purchased // Update costs based on how many have been purchased
mult = Math.pow( mult = Math.pow(
CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]], CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][SourceFileFlags[11]],

@ -108,6 +108,9 @@ export const AugmentationNames: {
BladeArmorOmnibeam: string; BladeArmorOmnibeam: string;
BladeArmorIPU: string; BladeArmorIPU: string;
BladesSimulacrum: string; BladesSimulacrum: string;
StaneksGift1: string;
StaneksGift2: string;
StaneksGift3: string;
} = { } = {
Targeting1: "Augmented Targeting I", Targeting1: "Augmented Targeting I",
Targeting2: "Augmented Targeting II", Targeting2: "Augmented Targeting II",
@ -219,6 +222,10 @@ export const AugmentationNames: {
BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade", BladeArmorIPU: "BLADE-51b Tesla Armor: IPU Upgrade",
BladesSimulacrum: "The Blade's Simulacrum", BladesSimulacrum: "The Blade's Simulacrum",
StaneksGift1: "Stanek's Gift - Genesis",
StaneksGift2: "Stanek's Gift - Awakening",
StaneksGift3: "Stanek's Gift - Serenity",
//Wasteland Augs //Wasteland Augs
//PepBoy: "P.E.P-Boy", Plasma Energy Projection System //PepBoy: "P.E.P-Boy", Plasma Energy Projection System
//PepBoyForceField Generates plasma force fields //PepBoyForceField Generates plasma force fields

@ -530,8 +530,38 @@ BitNodes["BitNode12"] = new BitNode(
</> </>
), ),
); );
BitNodes["BitNode13"] = new BitNode(
13,
2,
"They're lunatics",
"1 step back, 2 steps forward",
(
<>
With the invention of Augmentations in the 2040s a religious group known as the Church of the Machine God has
rallied far more support than anyone would have hoped.
<br />
<br />
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
other. Find her in Chongquing and gain her trust.
<br />
<br />
In this BitNode:
<br />
<br />
Every stat is significantly reduced
<br />
Stanek's Gift power is significantly increased.
<br />
<br />
Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File lets the Church of the Machine God appear in other BitNodes.
<br />
<br />
Each level of this Source-File increases the size of Stanek's Gift.
</>
),
);
// Books: Frontera, Shiner // Books: Frontera, Shiner
BitNodes["BitNode13"] = new BitNode(13, 2, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode14"] = new BitNode(14, 2, "", "COMING SOON"); BitNodes["BitNode14"] = new BitNode(14, 2, "", "COMING SOON");
BitNodes["BitNode15"] = new BitNode(15, 2, "", "COMING SOON"); BitNodes["BitNode15"] = new BitNode(15, 2, "", "COMING SOON");
BitNodes["BitNode16"] = new BitNode(16, 2, "", "COMING SOON"); BitNodes["BitNode16"] = new BitNode(16, 2, "", "COMING SOON");
@ -553,6 +583,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers[mult] = 1; BitNodeMultipliers[mult] = 1;
} }
} }
// Special case.
BitNodeMultipliers.StaneksGiftExtraSize = 0;
switch (p.bitNodeN) { switch (p.bitNodeN) {
case 1: // Source Genesis (every multiplier is 1) case 1: // Source Genesis (every multiplier is 1)
@ -566,6 +598,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.InfiltrationMoney = 3; BitNodeMultipliers.InfiltrationMoney = 3;
BitNodeMultipliers.FactionWorkRepGain = 0.5; BitNodeMultipliers.FactionWorkRepGain = 0.5;
BitNodeMultipliers.FactionPassiveRepGain = 0; BitNodeMultipliers.FactionPassiveRepGain = 0;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 2;
BitNodeMultipliers.StaneksGiftExtraSize = -6;
BitNodeMultipliers.PurchasedServerSoftcap = 1.3; BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
BitNodeMultipliers.CorporationSoftCap = 0.9; BitNodeMultipliers.CorporationSoftCap = 0.9;
break; break;
@ -583,6 +617,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HacknetNodeMoney = 0.25; BitNodeMultipliers.HacknetNodeMoney = 0.25;
BitNodeMultipliers.HomeComputerRamCost = 1.5; BitNodeMultipliers.HomeComputerRamCost = 1.5;
BitNodeMultipliers.PurchasedServerCost = 2; BitNodeMultipliers.PurchasedServerCost = 2;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.75;
BitNodeMultipliers.StaneksGiftExtraSize = -2;
BitNodeMultipliers.PurchasedServerSoftcap = 1.3; BitNodeMultipliers.PurchasedServerSoftcap = 1.3;
BitNodeMultipliers.GangSoftcap = 0.9; BitNodeMultipliers.GangSoftcap = 0.9;
break; break;
@ -599,6 +635,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HackExpGain = 0.4; BitNodeMultipliers.HackExpGain = 0.4;
BitNodeMultipliers.CrimeExpGain = 0.5; BitNodeMultipliers.CrimeExpGain = 0.5;
BitNodeMultipliers.FactionWorkRepGain = 0.75; BitNodeMultipliers.FactionWorkRepGain = 0.75;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 1.5;
BitNodeMultipliers.StaneksGiftExtraSize = 0;
BitNodeMultipliers.PurchasedServerSoftcap = 1.2; BitNodeMultipliers.PurchasedServerSoftcap = 1.2;
break; break;
case 5: // Artificial intelligence case 5: // Artificial intelligence
@ -613,6 +651,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.AugmentationMoneyCost = 2; BitNodeMultipliers.AugmentationMoneyCost = 2;
BitNodeMultipliers.HackExpGain = 0.5; BitNodeMultipliers.HackExpGain = 0.5;
BitNodeMultipliers.CorporationValuation = 0.5; BitNodeMultipliers.CorporationValuation = 0.5;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 1.3;
BitNodeMultipliers.StaneksGiftExtraSize = 0;
BitNodeMultipliers.PurchasedServerSoftcap = 1.2; BitNodeMultipliers.PurchasedServerSoftcap = 1.2;
break; break;
case 6: // Bladeburner case 6: // Bladeburner
@ -630,6 +670,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.HackExpGain = 0.25; BitNodeMultipliers.HackExpGain = 0.25;
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
BitNodeMultipliers.PurchasedServerSoftcap = 2; BitNodeMultipliers.PurchasedServerSoftcap = 2;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.5;
BitNodeMultipliers.StaneksGiftExtraSize = 2;
BitNodeMultipliers.GangSoftcap = 0.7; BitNodeMultipliers.GangSoftcap = 0.7;
BitNodeMultipliers.CorporationSoftCap = 0.9; BitNodeMultipliers.CorporationSoftCap = 0.9;
break; break;
@ -653,6 +695,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.FourSigmaMarketDataApiCost = 2; BitNodeMultipliers.FourSigmaMarketDataApiCost = 2;
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
BitNodeMultipliers.PurchasedServerSoftcap = 2; BitNodeMultipliers.PurchasedServerSoftcap = 2;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.9;
BitNodeMultipliers.StaneksGiftExtraSize = -1;
BitNodeMultipliers.GangSoftcap = 0.7; BitNodeMultipliers.GangSoftcap = 0.7;
BitNodeMultipliers.CorporationSoftCap = 0.9; BitNodeMultipliers.CorporationSoftCap = 0.9;
break; break;
@ -667,6 +711,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.RepToDonateToFaction = 0; BitNodeMultipliers.RepToDonateToFaction = 0;
BitNodeMultipliers.CorporationValuation = 0; BitNodeMultipliers.CorporationValuation = 0;
BitNodeMultipliers.CodingContractMoney = 0; BitNodeMultipliers.CodingContractMoney = 0;
BitNodeMultipliers.StaneksGiftExtraSize = -7;
BitNodeMultipliers.PurchasedServerSoftcap = 4; BitNodeMultipliers.PurchasedServerSoftcap = 4;
BitNodeMultipliers.GangSoftcap = 0; BitNodeMultipliers.GangSoftcap = 0;
BitNodeMultipliers.CorporationSoftCap = 0; BitNodeMultipliers.CorporationSoftCap = 0;
@ -691,6 +736,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4; BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
BitNodeMultipliers.BladeburnerRank = 0.9; BitNodeMultipliers.BladeburnerRank = 0.9;
BitNodeMultipliers.BladeburnerSkillCost = 1.2; BitNodeMultipliers.BladeburnerSkillCost = 1.2;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.5;
BitNodeMultipliers.StaneksGiftExtraSize = 2;
BitNodeMultipliers.GangSoftcap = 0.8; BitNodeMultipliers.GangSoftcap = 0.8;
BitNodeMultipliers.CorporationSoftCap = 0.9; BitNodeMultipliers.CorporationSoftCap = 0.9;
break; break;
@ -716,6 +763,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.PurchasedServerLimit = 0.6; BitNodeMultipliers.PurchasedServerLimit = 0.6;
BitNodeMultipliers.PurchasedServerMaxRam = 0.5; BitNodeMultipliers.PurchasedServerMaxRam = 0.5;
BitNodeMultipliers.BladeburnerRank = 0.8; BitNodeMultipliers.BladeburnerRank = 0.8;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.75;
BitNodeMultipliers.StaneksGiftExtraSize = -3;
BitNodeMultipliers.PurchasedServerSoftcap = 1.1; BitNodeMultipliers.PurchasedServerSoftcap = 1.1;
BitNodeMultipliers.GangSoftcap = 0.9; BitNodeMultipliers.GangSoftcap = 0.9;
BitNodeMultipliers.CorporationSoftCap = 0.9; BitNodeMultipliers.CorporationSoftCap = 0.9;
@ -807,10 +856,56 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.BladeburnerRank = dec; BitNodeMultipliers.BladeburnerRank = dec;
BitNodeMultipliers.BladeburnerSkillCost = inc; BitNodeMultipliers.BladeburnerSkillCost = inc;
BitNodeMultipliers.StaneksGiftPowerMultiplier = inc;
BitNodeMultipliers.StaneksGiftExtraSize = inc;
BitNodeMultipliers.GangSoftcap = 0.8; BitNodeMultipliers.GangSoftcap = 0.8;
BitNodeMultipliers.CorporationSoftCap = 0.8; BitNodeMultipliers.CorporationSoftCap = 0.8;
break; break;
} }
case 13: {
BitNodeMultipliers.PurchasedServerSoftcap = 1.5;
BitNodeMultipliers.HackingLevelMultiplier = 0.3;
BitNodeMultipliers.StrengthLevelMultiplier = 0.3;
BitNodeMultipliers.DefenseLevelMultiplier = 0.3;
BitNodeMultipliers.DexterityLevelMultiplier = 0.3;
BitNodeMultipliers.AgilityLevelMultiplier = 0.3;
BitNodeMultipliers.CharismaLevelMultiplier = 0.3;
BitNodeMultipliers.ServerMaxMoney = 0.45;
BitNodeMultipliers.ServerStartingMoney = 0.75;
BitNodeMultipliers.ServerStartingSecurity = 2;
BitNodeMultipliers.ScriptHackMoney = 0.4;
BitNodeMultipliers.CompanyWorkMoney = 0.4;
BitNodeMultipliers.CrimeMoney = 0.4;
BitNodeMultipliers.HacknetNodeMoney = 0.4;
BitNodeMultipliers.CodingContractMoney = 0.4;
BitNodeMultipliers.CompanyWorkExpGain = 0.5;
BitNodeMultipliers.ClassGymExpGain = 0.5;
BitNodeMultipliers.FactionWorkExpGain = 0.5;
BitNodeMultipliers.HackExpGain = 0.5;
BitNodeMultipliers.CrimeExpGain = 0.5;
BitNodeMultipliers.FactionWorkRepGain = 0.6;
BitNodeMultipliers.FourSigmaMarketDataCost = 10;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 10;
BitNodeMultipliers.CorporationValuation = 0.001;
BitNodeMultipliers.BladeburnerRank = 0.45;
BitNodeMultipliers.BladeburnerSkillCost = 2;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 2;
BitNodeMultipliers.StaneksGiftExtraSize = 1;
BitNodeMultipliers.GangSoftcap = 0.3;
BitNodeMultipliers.CorporationSoftCap = 0.3;
BitNodeMultipliers.WorldDaemonDifficulty = 2.5;
break;
}
default: default:
console.warn("Player.bitNodeN invalid"); console.warn("Player.bitNodeN invalid");
break; break;

@ -217,6 +217,21 @@ interface IBitNodeMultipliers {
*/ */
StrengthLevelMultiplier: number; StrengthLevelMultiplier: number;
/**
* Influences the power of the gift.
*/
StaneksGiftPowerMultiplier: number;
/**
* Influences the size of the gift.
*/
StaneksGiftExtraSize: number;
/**
* Influences the hacking skill required to backdoor the world daemon.
*/
WorldDaemonDifficulty: number;
// Index signature // Index signature
[key: string]: number; [key: string]: number;
} }
@ -282,4 +297,9 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
GangSoftcap: 1, GangSoftcap: 1,
DaedalusAugsRequirement: 1, DaedalusAugsRequirement: 1,
StaneksGiftPowerMultiplier: 1,
StaneksGiftExtraSize: 0,
WorldDaemonDifficulty: 1,
}; };

@ -160,7 +160,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ O \__| \_| | O |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>

@ -31,10 +31,6 @@ export const CONSTANTS: {
PurchasedServerMaxRam: number; PurchasedServerMaxRam: number;
MultipleAugMultiplier: number; MultipleAugMultiplier: number;
TorRouterCost: number; TorRouterCost: number;
InfiltrationBribeBaseAmount: number;
InfiltrationMoneyValue: number;
InfiltrationRepValue: number;
InfiltrationExpPow: number;
WSEAccountCost: number; WSEAccountCost: number;
TIXAPICost: number; TIXAPICost: number;
MarketData4SCost: number; MarketData4SCost: number;
@ -115,8 +111,8 @@ export const CONSTANTS: {
TotalNumBitNodes: number; TotalNumBitNodes: number;
LatestUpdate: string; LatestUpdate: string;
} = { } = {
VersionString: "1.0.2", VersionString: "1.1.0",
VersionNumber: 5, VersionNumber: 6,
// Speed (in ms) at which the main loop is updated // Speed (in ms) at which the main loop is updated
_idleSpeed: 200, _idleSpeed: 200,
@ -169,12 +165,6 @@ export const CONSTANTS: {
// TOR Router // TOR Router
TorRouterCost: 200e3, TorRouterCost: 200e3,
// Infiltration
InfiltrationBribeBaseAmount: 100e3, //Amount per clearance level
InfiltrationMoneyValue: 5e3, //Convert "secret" value to money
InfiltrationRepValue: 1.4, //Convert "secret" value to faction reputation
InfiltrationExpPow: 0.8,
// Stock market // Stock market
WSEAccountCost: 200e6, WSEAccountCost: 200e6,
TIXAPICost: 5e9, TIXAPICost: 5e9,
@ -283,19 +273,66 @@ export const CONSTANTS: {
TotalNumBitNodes: 24, TotalNumBitNodes: 24,
LatestUpdate: ` LatestUpdate: `
v1.0.2 - 2021-11-17 It's the little things (hydroflame) v1.1.0 - 2021-12-03 BN13: They're Lunatics (hydroflame & community)
------------------------------------------------------- -------------------------------------------------------
** Breaking (very small I promise!) ** ** BN13: They're Lunatics **
* buy / sell now return getAskPrice / getBidPrice instead of just price. * BN13 added.
This should help solve some inconsistencies.
** Steam **
* Tested on all 3 major OS.
* 94 achievements added
* Release is 2021-12-10.
** Netscript **
* tprintf crashes when not giving a format as first arg.
* tprintf no longer prints filename (@BartKoppelmans)
* TIX buy/sell/sellShort all return askprice/bidprice (@Insight)
* getRunningScript now works.
* Fix disableLog for gang and TIX API
* getOwnedSourceFiles is not singularity anymore (makes it easier to share scripts.) (@theit8514)
* true/false is a valid value to send to other scripts.
* workForFaction no longer returns null when trying to work for gang.
* Scripts logging no longer generates the string if logging is disabled.
This should give performance boost for some scripts.
** Gang **
* Gang with 0 territory can no longer fight
* Territory now caps at exactly 0 or 1.
** Misc. ** ** Misc. **
* scripts logs are colorized. Start your log with SUCCESS, ERROR, FAIL, WARN, INFO. * Clicking "previous" on the browser will not pretend you had unsaved information
* documentation for scp not say string | string[] allowing you to cancel if needs be.
* Donation link updated. * Fixed some tail box coloring issue.
* Fixed BladeBurner getCityCommunities ram cost
* The download terminal command no longer duplicate extensions (@Insight)
* Fix #000 on #000 text in blackjack. (@Insight)
* Remove reference to .fconf
* Tail boxes all die on soft reset.
* Fix codign contract focus bug.
* Megacorp factions simply re-invite you instead of auto added on reset. (@theit8514)
* Tail window is bound to html body.
* Infiltration reward is tied to your potential stats, not your actual stats
So you won't lose reward for doing the same thing over and over.
* intelligence lowers program creation requirements.
* Terminal parses true as the boolean, not the string.
* Tail and kill autocomplete using the ns2 autocomplete feature.
* scan-analyze doesn't take up as many terminal entries.
* GangOtherInfo documentation now renders correctly.
* ActiveScripts search box also searches for script names.
* Infinite money no longer allows for infinite hacknet server.
* Blackjack doesn't make you lose money twice.
* Recent Scripts is now from most to least recent.
* Fix mathjax ascii art bug in NiteSec.
* Remove warning that the theme editor is slow, it's only slow in dev mode.
* In BN8 is it possible to reduce the money on a server without gaining any.
* In the options, the timestamp feature has a placeholder explaining the expected format.
* Bunch of doc typo fix. (hydroflame & @BartKoppelmans & @cvr-119)
* nerf noodle bar * nerf noodle bar
`, `,
}; };

@ -0,0 +1,95 @@
import { Fragment, FragmentById } from "./Fragment";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
export interface IActiveFragmentParams {
x: number;
y: number;
rotation: number;
fragment: Fragment;
}
export class ActiveFragment {
id: number;
avgCharge: number;
numCharge: number;
rotation: number;
x: number;
y: number;
constructor(params?: IActiveFragmentParams) {
if (params) {
this.id = params.fragment.id;
this.x = params.x;
this.y = params.y;
this.avgCharge = 0;
this.numCharge = 0;
this.rotation = params.rotation;
} else {
this.id = -1;
this.x = -1;
this.y = -1;
this.avgCharge = -1;
this.numCharge = -1;
this.rotation = -1;
}
}
collide(other: ActiveFragment): boolean {
const thisFragment = this.fragment();
const otherFragment = other.fragment();
// These 2 variables converts 'this' local coordinates to world to other local.
const dx: number = other.x - this.x;
const dy: number = other.y - this.y;
for (let j = 0; j < thisFragment.shape.length; j++) {
for (let i = 0; i < thisFragment.shape[j].length; i++) {
if (thisFragment.fullAt(i, j, this.rotation) && otherFragment.fullAt(i - dx, j - dy, other.rotation))
return true;
}
}
return false;
}
fragment(): Fragment {
const fragment = FragmentById(this.id);
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
return fragment;
}
fullAt(worldX: number, worldY: number): boolean {
return this.fragment().fullAt(worldX - this.x, worldY - this.y, this.rotation);
}
neighboors(): number[][] {
return this.fragment()
.neighboors(this.rotation)
.map((cell) => [this.x + cell[0], this.y + cell[1]]);
}
copy(): ActiveFragment {
// We have to do a round trip because the constructor.
const fragment = FragmentById(this.id);
if (fragment === null) throw new Error("ActiveFragment id refers to unknown Fragment.");
const c = new ActiveFragment({ x: this.x, y: this.y, rotation: this.rotation, fragment: fragment });
c.avgCharge = this.avgCharge;
c.numCharge = this.numCharge;
return c;
}
/**
* Serialize an active fragment to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("ActiveFragment", this);
}
/**
* Initializes an acive fragment from a JSON save state
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): ActiveFragment {
return Generic_fromJSON(ActiveFragment, value.data);
}
}
Reviver.constructors.ActiveFragment = ActiveFragment;

356
src/CotMG/Fragment.ts Normal file

@ -0,0 +1,356 @@
import { FragmentType } from "./FragmentType";
import { Shapes } from "./data/Shapes";
export const Fragments: Fragment[] = [];
export class Fragment {
id: number;
shape: boolean[][];
type: FragmentType;
power: number;
limit: number;
constructor(id: number, shape: boolean[][], type: FragmentType, power: number, limit: number) {
this.id = id;
this.shape = shape;
this.type = type;
this.power = power;
this.limit = limit;
}
fullAt(x: number, y: number, rotation: number): boolean {
if (y < 0) return false;
if (y >= this.height(rotation)) return false;
if (x < 0) return false;
if (x >= this.width(rotation)) return false;
// start xy, modifier xy
let [sx, sy, mx, my] = [0, 0, 1, 1];
if (rotation === 1) {
[sx, sy, mx, my] = [this.width(rotation) - 1, 0, -1, 1];
} else if (rotation === 2) {
[sx, sy, mx, my] = [this.width(rotation) - 1, this.height(rotation) - 1, -1, -1];
} else if (rotation === 3) {
[sx, sy, mx, my] = [0, this.height(rotation) - 1, 1, -1];
}
let [qx, qy] = [sx + mx * x, sy + my * y];
if (rotation % 2 === 1) [qx, qy] = [qy, qx];
return this.shape[qy][qx];
}
width(rotation: number): number {
if (rotation % 2 === 0) return this.shape[0].length;
return this.shape.length;
}
height(rotation: number): number {
if (rotation % 2 === 0) return this.shape.length;
return this.shape[0].length;
}
// List of direct neighboors of this fragment.
neighboors(rotation: number): number[][] {
const candidates: number[][] = [];
const add = (x: number, y: number): void => {
if (this.fullAt(x, y, rotation)) return;
if (candidates.some((coord) => coord[0] === x && coord[1] === y)) return;
candidates.push([x, y]);
};
for (let y = 0; y < this.height(rotation); y++) {
for (let x = 0; x < this.width(rotation); x++) {
// This cell is full, add all it's neighboors.
if (!this.fullAt(x, y, rotation)) continue;
add(x - 1, y);
add(x + 1, y);
add(x, y - 1);
add(x, y + 1);
}
}
const cells: number[][] = [];
for (const candidate of candidates) {
if (cells.some((cell) => cell[0] === candidate[0] && cell[1] === candidate[1])) continue;
cells.push(candidate);
}
return cells;
}
copy(): Fragment {
return new Fragment(
this.id,
this.shape.map((a) => a.slice()),
this.type,
this.power,
this.limit,
);
}
}
export function FragmentById(id: number): Fragment | null {
for (const fragment of Fragments) {
if (fragment.id === id) return fragment;
}
return null;
}
(function () {
const _ = false;
const X = true;
Fragments.push(
new Fragment(
0, // id
Shapes.S,
FragmentType.Hacking, // type
1,
1, // limit
),
);
Fragments.push(
new Fragment(
1, // id
Shapes.Z,
FragmentType.Hacking, // type
1,
1, // limit
),
);
Fragments.push(
new Fragment(
5, // id
Shapes.T,
FragmentType.HackingSpeed, // type
1.3,
1, // limit
),
);
Fragments.push(
new Fragment(
6, // id
Shapes.I,
FragmentType.HackingMoney, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
7, // id
Shapes.J,
FragmentType.HackingGrow, // type
0.5, // power
1, // limit
),
);
Fragments.push(
new Fragment(
10, // id
Shapes.T,
FragmentType.Strength, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
12, // id
Shapes.L,
FragmentType.Defense, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
14, // id
Shapes.L,
FragmentType.Dexterity, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
16, // id
Shapes.S,
FragmentType.Agility, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
18, // id
Shapes.S,
FragmentType.Charisma, // type
3, // power
1, // limit
),
);
Fragments.push(
new Fragment(
20, // id
Shapes.I,
FragmentType.HacknetMoney, // type
1, // power
1, // limit
),
);
Fragments.push(
new Fragment(
21, // id
Shapes.O,
FragmentType.HacknetCost, // type
-1, // power
1, // limit
),
);
Fragments.push(
new Fragment(
25, // id
Shapes.J,
FragmentType.Rep, // type
0.5, // power
1, // limit
),
);
Fragments.push(
new Fragment(
27, // id
Shapes.J,
FragmentType.WorkMoney, // type
10, // power
1, // limit
),
);
Fragments.push(
new Fragment(
28, // id
Shapes.L,
FragmentType.Crime, // type
2, // power
1, // limit
),
);
Fragments.push(
new Fragment(
30, // id
Shapes.S,
FragmentType.Bladeburner, // type
0.4, // power
1, // limit
),
);
Fragments.push(
new Fragment(
100, // id
[
// shape
[_, X, X],
[X, X, _],
[_, X, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
101, // id
[
// shape
[X, X, X, X],
[X, _, _, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
102, // id
[
// shape
[_, X, X, X],
[X, X, _, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
103, // id
[
// shape
[X, X, X, _],
[_, _, X, X],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
104, // id
[
// shape
[_, X, X],
[_, X, _],
[X, X, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
105, // id
[
// shape
[_, _, X],
[_, X, X],
[X, X, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
106, // id
[
// shape
[X, _, _],
[X, X, X],
[X, _, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
Fragments.push(
new Fragment(
107, // id
[
// shape
[_, X, _],
[X, X, X],
[_, X, _],
],
FragmentType.Booster, // type
1.1, // power
99, // limit
),
);
})();
export const NoneFragment = new Fragment(-2, [], FragmentType.None, 0, Infinity);
export const DeleteFragment = new Fragment(-2, [], FragmentType.Delete, 0, Infinity);

96
src/CotMG/FragmentType.ts Normal file

@ -0,0 +1,96 @@
export enum FragmentType {
// Special fragments for the UI
None,
Delete,
// Stats boosting fragments
HackingChance,
HackingSpeed,
HackingMoney,
HackingGrow,
Hacking,
Strength,
Defense,
Dexterity,
Agility,
Charisma,
HacknetMoney,
HacknetCost,
Rep,
WorkMoney,
Crime,
Bladeburner,
// utility fragments.
Booster,
}
export function Effect(tpe: FragmentType): string {
switch (tpe) {
case FragmentType.HackingChance: {
return "+x% hack() success chance";
break;
}
case FragmentType.HackingSpeed: {
return "+x% faster hack(), grow(), and weaken()";
break;
}
case FragmentType.HackingMoney: {
return "+x% hack() power";
break;
}
case FragmentType.HackingGrow: {
return "+x% grow() power";
break;
}
case FragmentType.Hacking: {
return "+x% hacking skill";
break;
}
case FragmentType.Strength: {
return "+x% strength skill";
break;
}
case FragmentType.Defense: {
return "+x% defense skill";
break;
}
case FragmentType.Dexterity: {
return "+x% dexterity skill";
break;
}
case FragmentType.Agility: {
return "+x% agility skill";
break;
}
case FragmentType.Charisma: {
return "+x% charisma skill";
break;
}
case FragmentType.HacknetMoney: {
return "+x% hacknet production";
break;
}
case FragmentType.HacknetCost: {
return "-x% all hacknet cost";
break;
}
case FragmentType.Rep: {
return "+x% reputation from factions and companies";
break;
}
case FragmentType.WorkMoney: {
return "+x% work money";
break;
}
case FragmentType.Crime: {
return "+x% crime money";
break;
}
case FragmentType.Bladeburner: {
return "+x% all bladeburner stats";
break;
}
}
throw new Error("Calling effect for fragment type that doesn't have an effect " + tpe);
}

14
src/CotMG/Helper.tsx Normal file

@ -0,0 +1,14 @@
import { Reviver } from "../utils/JSONReviver";
import { IStaneksGift } from "./IStaneksGift";
import { StaneksGift } from "./StaneksGift";
export let staneksGift: IStaneksGift = new StaneksGift();
export function loadStaneksGift(saveString: string): void {
if (saveString) {
staneksGift = JSON.parse(saveString, Reviver);
} else {
staneksGift = new StaneksGift();
}
}

23
src/CotMG/IStaneksGift.ts Normal file

@ -0,0 +1,23 @@
import { ActiveFragment } from "./ActiveFragment";
import { Fragment } from "./Fragment";
import { IPlayer } from "../PersonObjects/IPlayer";
export interface IStaneksGift {
storedCycles: number;
fragments: ActiveFragment[];
width(): number;
height(): number;
charge(player: IPlayer, fragment: ActiveFragment, threads: number): void;
process(p: IPlayer, n: number): void;
effect(fragment: ActiveFragment): number;
canPlace(x: number, y: number, rotation: number, fragment: Fragment): boolean;
place(x: number, y: number, rotation: number, fragment: Fragment): boolean;
findFragment(rootX: number, rootY: number): ActiveFragment | undefined;
fragmentAt(rootX: number, rootY: number): ActiveFragment | undefined;
delete(rootX: number, rootY: number): boolean;
clear(): void;
count(fragment: Fragment): number;
inBonus(): boolean;
prestigeAugmentation(): void;
prestigeSourceFile(): void;
}

234
src/CotMG/StaneksGift.ts Normal file

@ -0,0 +1,234 @@
import { Fragment } from "./Fragment";
import { ActiveFragment } from "./ActiveFragment";
import { FragmentType } from "./FragmentType";
import { IStaneksGift } from "./IStaneksGift";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Factions } from "../Faction/Factions";
import { CalculateEffect } from "./formulas/effect";
import { StaneksGiftEvents } from "./StaneksGiftEvents";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { CONSTANTS } from "../Constants";
import { StanekConstants } from "./data/Constants";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Player } from "../Player";
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
export class StaneksGift implements IStaneksGift {
storedCycles = 0;
fragments: ActiveFragment[] = [];
baseSize(): number {
return StanekConstants.BaseSize + BitNodeMultipliers.StaneksGiftExtraSize + Player.sourceFileLvl(13);
}
width(): number {
return Math.floor(this.baseSize() / 2 + 1);
}
height(): number {
return Math.floor(this.baseSize() / 2 + 0.6);
}
charge(player: IPlayer, af: ActiveFragment, threads: number): void {
af.avgCharge = (af.numCharge * af.avgCharge + threads) / (af.numCharge + 1);
af.numCharge++;
const cotmg = Factions["Church of the Machine God"];
cotmg.playerReputation += (player.faction_rep_mult * (Math.pow(threads, 0.95) * (cotmg.favor + 100))) / 1000;
}
inBonus(): boolean {
return (this.storedCycles * CONSTANTS._idleSpeed) / 1000 > 1;
}
process(p: IPlayer, numCycles = 1): void {
if (!p.hasAugmentation(AugmentationNames.StaneksGift1)) return;
this.storedCycles += numCycles;
this.storedCycles -= 10;
this.storedCycles = Math.max(0, this.storedCycles);
this.updateMults(p);
StaneksGiftEvents.emit();
}
effect(fragment: ActiveFragment): number {
// Find all the neighbooring cells
const cells = fragment.neighboors();
// find the neighbooring active fragments.
const maybeFragments = cells.map((n) => this.fragmentAt(n[0], n[1]));
// Filter out undefined with typescript "Type guard". Whatever
let neighboors = maybeFragments.filter((v: ActiveFragment | undefined): v is ActiveFragment => !!v);
neighboors = neighboors.filter((fragment) => fragment.fragment().type === FragmentType.Booster);
let boost = 1;
neighboors = neighboors.filter((v, i, s) => s.indexOf(v) === i);
for (const neighboor of neighboors) {
boost *= neighboor.fragment().power;
}
return CalculateEffect(fragment.avgCharge, fragment.numCharge, fragment.fragment().power, boost);
}
canPlace(rootX: number, rootY: number, rotation: number, fragment: Fragment): boolean {
if (rootX < 0 || rootY < 0) return false;
if (rootX + fragment.width(rotation) > this.width()) return false;
if (rootY + fragment.height(rotation) > this.height()) return false;
if (this.count(fragment) >= fragment.limit) return false;
const newFrag = new ActiveFragment({ x: rootX, y: rootY, rotation: rotation, fragment: fragment });
for (const aFrag of this.fragments) {
if (aFrag.collide(newFrag)) return false;
}
return true;
}
place(rootX: number, rootY: number, rotation: number, fragment: Fragment): boolean {
if (!this.canPlace(rootX, rootY, rotation, fragment)) return false;
this.fragments.push(new ActiveFragment({ x: rootX, y: rootY, rotation: rotation, fragment: fragment }));
return true;
}
findFragment(rootX: number, rootY: number): ActiveFragment | undefined {
return this.fragments.find((f) => f.x === rootX && f.y === rootY);
}
fragmentAt(worldX: number, worldY: number): ActiveFragment | undefined {
for (const aFrag of this.fragments) {
if (aFrag.fullAt(worldX, worldY)) {
return aFrag;
}
}
return undefined;
}
count(fragment: Fragment): number {
let amt = 0;
for (const aFrag of this.fragments) {
if (aFrag.fragment().id === fragment.id) amt++;
}
return amt;
}
delete(rootX: number, rootY: number): boolean {
for (let i = 0; i < this.fragments.length; i++) {
if (this.fragments[i].x === rootX && this.fragments[i].y === rootY) {
this.fragments.splice(i, 1);
return true;
}
}
return false;
}
clear(): void {
this.fragments = [];
}
clearCharge(): void {
this.fragments.forEach((f) => {
f.avgCharge = 0;
f.numCharge = 0;
});
}
updateMults(p: IPlayer): void {
p.reapplyAllAugmentations(true);
p.reapplyAllSourceFiles();
for (const aFrag of this.fragments) {
const fragment = aFrag.fragment();
const power = this.effect(aFrag);
switch (fragment.type) {
case FragmentType.HackingChance:
p.hacking_chance_mult *= power;
break;
case FragmentType.HackingSpeed:
p.hacking_speed_mult *= power;
break;
case FragmentType.HackingMoney:
p.hacking_money_mult *= power;
break;
case FragmentType.HackingGrow:
p.hacking_grow_mult *= power;
break;
case FragmentType.Hacking:
p.hacking_mult *= power;
p.hacking_exp_mult *= power;
break;
case FragmentType.Strength:
p.strength_mult *= power;
p.strength_exp_mult *= power;
break;
case FragmentType.Defense:
p.defense_mult *= power;
p.defense_exp_mult *= power;
break;
case FragmentType.Dexterity:
p.dexterity_mult *= power;
p.dexterity_exp_mult *= power;
break;
case FragmentType.Agility:
p.agility_mult *= power;
p.agility_exp_mult *= power;
break;
case FragmentType.Charisma:
p.charisma_mult *= power;
p.charisma_exp_mult *= power;
break;
case FragmentType.HacknetMoney:
p.hacknet_node_money_mult *= power;
break;
case FragmentType.HacknetCost:
p.hacknet_node_purchase_cost_mult *= power;
p.hacknet_node_ram_cost_mult *= power;
p.hacknet_node_core_cost_mult *= power;
p.hacknet_node_level_cost_mult *= power;
break;
case FragmentType.Rep:
p.company_rep_mult *= power;
p.faction_rep_mult *= power;
break;
case FragmentType.WorkMoney:
p.work_money_mult *= power;
break;
case FragmentType.Crime:
p.crime_success_mult *= power;
p.crime_money_mult *= power;
break;
case FragmentType.Bladeburner:
p.bladeburner_max_stamina_mult *= power;
p.bladeburner_stamina_gain_mult *= power;
p.bladeburner_analysis_mult *= power;
p.bladeburner_success_chance_mult *= power;
break;
}
}
p.updateSkillLevels();
}
prestigeAugmentation(): void {
this.clearCharge();
}
prestigeSourceFile(): void {
this.clear();
this.storedCycles = 0;
}
/**
* Serialize Staneks Gift to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("StaneksGift", this);
}
/**
* Initializes Staneks Gift from a JSON save state
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): StaneksGift {
return Generic_fromJSON(StaneksGift, value.data);
}
}
Reviver.constructors.StaneksGift = StaneksGift;

@ -0,0 +1,2 @@
import { EventEmitter } from "../utils/EventEmitter";
export const StaneksGiftEvents = new EventEmitter<[]>();

@ -0,0 +1,7 @@
export const StanekConstants: {
RAMBonus: number;
BaseSize: number;
} = {
RAMBonus: 0.1,
BaseSize: 9,
};

37
src/CotMG/data/Shapes.ts Normal file

@ -0,0 +1,37 @@
const _ = false;
const X = true;
export const Shapes: {
O: boolean[][];
I: boolean[][];
L: boolean[][];
J: boolean[][];
S: boolean[][];
Z: boolean[][];
T: boolean[][];
} = {
O: [
[X, X],
[X, X],
],
I: [[X, X, X, X]],
L: [
[_, _, X],
[X, X, X],
],
J: [
[X, _, _],
[X, X, X],
],
S: [
[_, X, X],
[X, X, _],
],
Z: [
[X, X, _],
[_, X, X],
],
T: [
[X, X, X],
[_, X, _],
],
};

@ -0,0 +1,5 @@
import { StanekConstants } from "../data/Constants";
export function CalculateCharge(ram: number): number {
return ram * Math.pow(1 + Math.log2(ram) * StanekConstants.RAMBonus, 0.7);
}

@ -0,0 +1,12 @@
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
export function CalculateEffect(avgCharge: number, numCharge: number, power: number, boost: number): number {
return (
1 +
(Math.log(avgCharge + 1) / (Math.log(1.8) * 100)) *
Math.pow((numCharge + 1) / 5, 0.07) *
power *
boost *
BitNodeMultipliers.StaneksGiftPowerMultiplier
);
}

4
src/CotMG/notes Normal file

@ -0,0 +1,4 @@
incentive for more threads
boosters just multiply output, eg 20% * 1.5 = 30%
git remote add danielyxie git@github.com:danielyxie/bitburner.git

40
src/CotMG/ui/Cell.tsx Normal file

@ -0,0 +1,40 @@
import * as React from "react";
import makeStyles from "@mui/styles/makeStyles";
import { TableCell as MuiTableCell, TableCellProps } from "@mui/material";
const useStyles = makeStyles({
root: {
border: "1px solid white",
width: "5px",
height: "5px",
},
});
export const TableCell: React.FC<TableCellProps> = (props: TableCellProps) => {
return (
<MuiTableCell
{...props}
classes={{
root: useStyles().root,
...props.classes,
}}
/>
);
};
type IProps = {
onMouseEnter?: () => void;
onClick?: () => void;
color: string;
};
export function Cell(cellProps: IProps): React.ReactElement {
return (
<TableCell
style={{ backgroundColor: cellProps.color }}
onMouseEnter={cellProps.onMouseEnter}
onClick={cellProps.onClick}
></TableCell>
);
}

@ -0,0 +1,81 @@
import React, { useState, useEffect } from "react";
import { ActiveFragment } from "../ActiveFragment";
import { IStaneksGift } from "../IStaneksGift";
import { FragmentType, Effect } from "../FragmentType";
import { numeralWrapper } from "../../ui/numeralFormat";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
type IProps = {
gift: IStaneksGift;
fragment: ActiveFragment | undefined;
x: number;
y: number;
};
export function FragmentInspector(props: IProps): React.ReactElement {
const [, setC] = useState(new Date());
useEffect(() => {
const id = setInterval(() => setC(new Date()), 250);
return () => clearInterval(id);
}, []);
if (props.fragment === undefined) {
return (
<Paper>
<Typography>
ID: N/A
<br />
Effect: N/A
<br />
Magnitude: N/A
<br />
Charge: N/A
<br />
Heat: N/A
<br />
Effect: N/A
<br />
[X, Y] N/A
<br />
[X, Y] {props.x}, {props.y}
</Typography>
</Paper>
);
}
const f = props.fragment.fragment();
let charge = `${numeralWrapper.formatStaneksGiftCharge(props.fragment.avgCharge)} avg. * ${
props.fragment.numCharge
} times`;
let effect = "N/A";
// Boosters and cooling don't deal with heat.
if ([FragmentType.Booster, FragmentType.None, FragmentType.Delete].includes(f.type)) {
charge = "N/A";
effect = `${f.power}x adjacent fragment power`;
} else {
effect = Effect(f.type).replace(/-*x%/, numeralWrapper.formatPercentage(props.gift.effect(props.fragment) - 1));
}
return (
<Paper>
<Typography>
ID: {props.fragment.id}
<br />
Effect: {effect}
<br />
Base Power: {numeralWrapper.formatStaneksGiftPower(f.power)}
<br />
Charge: {charge}
<br />
<br />
root [X, Y] {props.fragment.x}, {props.fragment.y}
<br />
[X, Y] {props.x}, {props.y}
</Typography>
</Paper>
);
}

@ -0,0 +1,31 @@
import * as React from "react";
import { Cell } from "./Cell";
import TableRow from "@mui/material/TableRow";
import TableBody from "@mui/material/TableBody";
import { Table } from "../../ui/React/Table";
type IProps = {
width: number;
height: number;
colorAt: (x: number, y: number) => string;
};
export function FragmentPreview(props: IProps): React.ReactElement {
// switch the width/length to make axis consistent.
const elems = [];
for (let j = 0; j < props.height; j++) {
const cells = [];
for (let i = 0; i < props.width; i++) {
cells.push(<Cell key={i} color={props.colorAt(i, j)} />);
}
elems.push(<TableRow key={j}>{cells}</TableRow>);
}
return (
<Table>
<TableBody>{elems}</TableBody>
</Table>
);
}

@ -0,0 +1,89 @@
import React, { useState } from "react";
import { Fragments, Fragment, NoneFragment, DeleteFragment } from "../Fragment";
import { FragmentType, Effect } from "../FragmentType";
import { IStaneksGift } from "../IStaneksGift";
import { FragmentPreview } from "./FragmentPreview";
import { numeralWrapper } from "../../ui/numeralFormat";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
type IOptionProps = {
gift: IStaneksGift;
fragment: Fragment;
selectFragment: (fragment: Fragment) => void;
};
function FragmentOption(props: IOptionProps): React.ReactElement {
const left = props.fragment.limit - props.gift.count(props.fragment);
const remaining = props.fragment.limit !== Infinity ? <>{left} remaining</> : <></>;
return (
<Box display="flex">
<Box sx={{ mx: 2 }}>
<FragmentPreview
width={props.fragment.width(0)}
height={props.fragment.height(0)}
colorAt={(x, y) => {
if (!props.fragment.fullAt(x, y, 0)) return "";
if (left === 0) return "grey";
return props.fragment.type === FragmentType.Booster ? "blue" : "green";
}}
/>
</Box>
<Typography>
{props.fragment.type === FragmentType.Booster
? `${props.fragment.power}x adjacent fragment power`
: Effect(props.fragment.type)}
<br />
power: {numeralWrapper.formatStaneksGiftPower(props.fragment.power)}
<br />
{remaining}
</Typography>
</Box>
);
}
type IProps = {
gift: IStaneksGift;
selectFragment: (fragment: Fragment) => void;
};
export function FragmentSelector(props: IProps): React.ReactElement {
const [value, setValue] = useState<string | number>("None");
function onChange(event: SelectChangeEvent<string | number>): void {
const v = event.target.value;
setValue(v);
if (v === "None") {
props.selectFragment(NoneFragment);
return;
} else if (v === "Delete") {
props.selectFragment(DeleteFragment);
return;
}
const fragment = Fragments.find((f) => f.id === v);
if (fragment === undefined) throw new Error("Fragment selector selected an undefined fragment with id " + v);
if (typeof v === "number") props.selectFragment(fragment);
}
return (
<Select sx={{ width: "100%" }} onChange={onChange} value={value}>
<MenuItem value="None">
<Typography>None</Typography>
</MenuItem>
<MenuItem value="Delete">
<Typography>Delete</Typography>
</MenuItem>
{Fragments.map((fragment) => (
<MenuItem key={fragment.id} value={fragment.id}>
<FragmentOption
key={fragment.id}
gift={props.gift}
selectFragment={props.selectFragment}
fragment={fragment}
/>
</MenuItem>
))}
</Select>
);
}

172
src/CotMG/ui/MainBoard.tsx Normal file

@ -0,0 +1,172 @@
import * as React from "react";
import { Fragment, NoneFragment } from "../Fragment";
import { ActiveFragment } from "../ActiveFragment";
import { FragmentType } from "../FragmentType";
import { IStaneksGift } from "../IStaneksGift";
import { Cell } from "./Cell";
import { FragmentInspector } from "./FragmentInspector";
import { FragmentSelector } from "./FragmentSelector";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import TableRow from "@mui/material/TableRow";
import TableBody from "@mui/material/TableBody";
import { Table } from "../../ui/React/Table";
function zeros(dimensions: number[]): any {
const array = [];
for (let i = 0; i < dimensions[0]; ++i) {
array.push(dimensions.length == 1 ? 0 : zeros(dimensions.slice(1)));
}
return array;
}
function randomColor(fragment: ActiveFragment): string {
// Can't set Math.random seed so copy casino. TODO refactor both RNG later.
let s1 = Math.pow((fragment.x + 1) * (fragment.y + 1), 10);
let s2 = s1;
let s3 = s1;
const colors = [];
for (let i = 0; i < 3; i++) {
s1 = (171 * s1) % 30269;
s2 = (172 * s2) % 30307;
s3 = (170 * s3) % 30323;
colors.push((s1 / 30269.0 + s2 / 30307.0 + s3 / 30323.0) % 1.0);
}
return `rgb(${colors[0] * 256}, ${colors[1] * 256}, ${colors[2] * 256})`;
}
interface IProps {
gift: IStaneksGift;
}
export function MainBoard(props: IProps): React.ReactElement {
function calculateGrid(gift: IStaneksGift): any {
const newgrid = zeros([gift.width(), gift.height()]);
for (let i = 0; i < gift.width(); i++) {
for (let j = 0; j < gift.height(); j++) {
const fragment = gift.fragmentAt(i, j);
if (!fragment) continue;
newgrid[i][j] = 1;
}
}
return newgrid;
}
const [grid, setGrid] = React.useState(calculateGrid(props.gift));
const [ghostGrid, setGhostGrid] = React.useState(zeros([props.gift.width(), props.gift.height()]));
const [pos, setPos] = React.useState([0, 0]);
const [rotation, setRotation] = React.useState(0);
const [selectedFragment, setSelectedFragment] = React.useState(NoneFragment);
function moveGhost(worldX: number, worldY: number, rotation: number): void {
setPos([worldX, worldY]);
if (selectedFragment.type === FragmentType.None || selectedFragment.type === FragmentType.Delete) return;
const newgrid = zeros([props.gift.width(), props.gift.height()]);
for (let y = 0; y < selectedFragment.height(rotation); y++) {
for (let x = 0; x < selectedFragment.width(rotation); x++) {
if (!selectedFragment.fullAt(x, y, rotation)) continue;
if (worldX + x > newgrid.length - 1) continue;
if (worldY + y > newgrid[worldX + x].length - 1) continue;
newgrid[worldX + x][worldY + y] = 1;
}
}
setGhostGrid(newgrid);
}
function deleteAt(worldX: number, worldY: number): boolean {
const f = props.gift.fragmentAt(worldX, worldY);
if (f === undefined) return false;
return props.gift.delete(f.x, f.y);
}
function clickAt(worldX: number, worldY: number): void {
if (selectedFragment.type == FragmentType.None) return;
if (selectedFragment.type == FragmentType.Delete) {
deleteAt(worldX, worldY);
} else {
if (!props.gift.canPlace(worldX, worldY, rotation, selectedFragment)) return;
props.gift.place(worldX, worldY, rotation, selectedFragment);
}
setGrid(calculateGrid(props.gift));
}
function color(worldX: number, worldY: number): string {
if (ghostGrid[worldX][worldY] && grid[worldX][worldY]) return "red";
if (ghostGrid[worldX][worldY]) return "white";
if (grid[worldX][worldY]) {
const fragment = props.gift.fragmentAt(worldX, worldY);
if (!fragment) throw new Error("ActiveFragment should not be null");
return randomColor(fragment);
}
return "";
}
function clear(): void {
props.gift.clear();
setGrid(zeros([props.gift.width(), props.gift.height()]));
}
// switch the width/length to make axis consistent.
const elems = [];
for (let j = 0; j < props.gift.height(); j++) {
const cells = [];
for (let i = 0; i < props.gift.width(); i++) {
cells.push(
<Cell
key={i}
onMouseEnter={() => moveGhost(i, j, rotation)}
onClick={() => clickAt(i, j)}
color={color(i, j)}
/>,
);
}
elems.push(
<TableRow key={j} className="staneksgift_row">
{cells}
</TableRow>,
);
}
function updateSelectedFragment(fragment: Fragment): void {
setSelectedFragment(fragment);
const newgrid = zeros([props.gift.width(), props.gift.height()]);
setGhostGrid(newgrid);
}
React.useEffect(() => {
function doRotate(this: Document, event: KeyboardEvent): void {
if (event.key === "q") {
const r = (rotation - 1 + 4) % 4;
setRotation(r);
moveGhost(pos[0], pos[1], r);
}
if (event.key === "e") {
const r = (rotation + 1) % 4;
setRotation(r);
moveGhost(pos[0], pos[1], r);
}
}
document.addEventListener("keydown", doRotate);
return () => document.removeEventListener("keydown", doRotate);
});
return (
<>
<Button onClick={clear}>Clear</Button>
<Box display="flex">
<Table>
<TableBody>{elems}</TableBody>
</Table>
<FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
</Box>
<FragmentSelector gift={props.gift} selectFragment={updateSelectedFragment} />
</>
);
}

@ -0,0 +1,36 @@
import React, { useState, useEffect } from "react";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { CONSTANTS } from "../../Constants";
import { StaneksGiftEvents } from "../StaneksGiftEvents";
import { MainBoard } from "./MainBoard";
import { IStaneksGift } from "../IStaneksGift";
import Typography from "@mui/material/Typography";
type IProps = {
staneksGift: IStaneksGift;
};
export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
const setRerender = useState(true)[1];
function rerender(): void {
setRerender((o) => !o);
}
useEffect(() => StaneksGiftEvents.subscribe(rerender), []);
return (
<>
<Typography variant="h4">Stanek's Gift</Typography>
<Typography>
The gift is a grid on which you can place upgrades called fragments. The main type of fragment increases a stat,
like your hacking skill or agility exp. Once a stat fragment is placed it then needs to be charged via scripts
in order to become useful. The other kind of fragment is called booster fragments. They increase the efficiency
of the charged happening on fragments neighboring them (no diagonal). Q/E to rotate fragments.
</Typography>
{staneksGift.storedCycles > 5 && (
<Typography>
Bonus time: {convertTimeMsToTimeElapsedString(CONSTANTS._idleSpeed * staneksGift.storedCycles)}
</Typography>
)}
<MainBoard gift={staneksGift} />
</>
);
}

@ -2,6 +2,7 @@ import { IPlayer } from "./PersonObjects/IPlayer";
import { Bladeburner } from "./Bladeburner/Bladeburner"; import { Bladeburner } from "./Bladeburner/Bladeburner";
import { IEngine } from "./IEngine"; import { IEngine } from "./IEngine";
import { IRouter } from "./ui/Router"; import { IRouter } from "./ui/Router";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import React from "react"; import React from "react";
@ -19,6 +20,7 @@ import { Corporation } from "./DevMenu/ui/Corporation";
import { CodingContracts } from "./DevMenu/ui/CodingContracts"; import { CodingContracts } from "./DevMenu/ui/CodingContracts";
import { StockMarket } from "./DevMenu/ui/StockMarket"; import { StockMarket } from "./DevMenu/ui/StockMarket";
import { Sleeves } from "./DevMenu/ui/Sleeves"; import { Sleeves } from "./DevMenu/ui/Sleeves";
import { Stanek } from "./DevMenu/ui/Stanek";
import { TimeSkip } from "./DevMenu/ui/TimeSkip"; import { TimeSkip } from "./DevMenu/ui/TimeSkip";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -52,6 +54,7 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
{props.player.hasWseAccount && <StockMarket />} {props.player.hasWseAccount && <StockMarket />}
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />} {props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
{props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1) && <Stanek />}
<TimeSkip player={props.player} engine={props.engine} /> <TimeSkip player={props.player} engine={props.engine} />
</> </>

85
src/DevMenu/ui/Stanek.tsx Normal file

@ -0,0 +1,85 @@
import React from "react";
import { staneksGift } from "../../CotMG/Helper";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import { Adjuster } from "./Adjuster";
export function Stanek(): React.ReactElement {
function addCycles(): void {
staneksGift.storedCycles = 1e6;
}
function modCycles(modify: number): (x: number) => void {
return function (cycles: number): void {
staneksGift.storedCycles += cycles * modify;
};
}
function resetCycles(): void {
staneksGift.storedCycles = 0;
}
function addCharge(): void {
staneksGift.fragments.forEach((f) => {
f.avgCharge = 1e21;
f.numCharge = 1e21;
});
}
function modCharge(modify: number): (x: number) => void {
return function (cycles: number): void {
staneksGift.fragments.forEach((f) => (f.avgCharge += cycles * modify));
};
}
function resetCharge(): void {
staneksGift.fragments.forEach((f) => {
f.avgCharge = 0;
f.numCharge = 0;
});
}
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>Stanek's Gift</Typography>
</AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td>
<Adjuster
label="cycles"
placeholder="amt"
tons={addCycles}
add={modCycles(1)}
subtract={modCycles(-1)}
reset={resetCycles}
/>
</td>
</tr>
<tr>
<td>
<Adjuster
label="all charge"
placeholder="amt"
tons={addCharge}
add={modCharge(1)}
subtract={modCharge(-1)}
reset={resetCharge}
/>
</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</Accordion>
);
}

@ -526,4 +526,47 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
false, false,
), ),
// prettier-ignore
"Church of the Machine God": new FactionInfo(<>
{" `` "}<br />
{" -odmmNmds: "}<br />
{" `hNmo:..-omNh. "}<br />
{" yMd` `hNh "}<br />
{" mMd oNm "}<br />
{" oMNo .mM/ "}<br />
{" `dMN+ -mM+ "}<br />
{" -mMNo -mN+ "}<br />
{" .+- :mMNo/mN/ "}<br />
{":yNMd. :NMNNN/ "}<br />
{"-mMMMh. /NMMh` "}<br />
{" .dMMMd. /NMMMy` "}<br />
{" `yMMMd. /NNyNMMh` "}<br />
{" `sMMMd. +Nm: +NMMh. "}<br />
{" oMMMm- oNm: /NMMd. "}<br />
{" +NMMmsMm- :mMMd. "}<br />
{" /NMMMm- -mMMd. "}<br />
{" /MMMm- -mMMd. "}<br />
{" `sMNMMm- .mMmo "}<br />
{" `sMd:hMMm. ./. "}<br />
{" `yMy` `yNMd` "}<br />
{" `hMs` oMMy "}<br />
{" `hMh sMN- "}<br />
{" /MM- .NMo "}<br />
{" +MM: :MM+ "}<br />
{" sNNo-.`.-omNy` "}<br />
{" -smNNNNmdo- "}<br />
{" `..` "}<br /><br />
Many cultures predict an end to humanity in the near future, a final
Armageddon that will end the world; but we disagree.
<br /><br />Note that for this faction, reputation can
only be gained by charging Stanek's gift.</>,
[],
false,
false,
false,
false,
true,
true,
),
}; };

@ -17,6 +17,9 @@ import Button from "@mui/material/Button";
import { Location } from "../Location"; import { Location } from "../Location";
import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal"; import { CreateCorporationModal } from "../../Corporation/ui/CreateCorporationModal";
import { LocationName } from "../data/LocationNames"; import { LocationName } from "../data/LocationNames";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Factions } from "../../Faction/Factions";
import { joinFaction } from "../../Faction/FactionHelpers";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
@ -24,6 +27,7 @@ import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { N00dles } from "../../utils/helpers/N00dles"; import { N00dles } from "../../utils/helpers/N00dles";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
type IProps = { type IProps = {
loc: Location; loc: Location;
@ -119,9 +123,24 @@ export function SpecialLocation(props: IProps): React.ReactElement {
return <Button onClick={handleResleeving}>Re-Sleeve</Button>; return <Button onClick={handleResleeving}>Re-Sleeve</Button>;
} }
function handleCotMG(): void {
const faction = Factions["Church of the Machine God"];
if (!player.factions.includes("Church of the Machine God")) {
joinFaction(faction);
}
if (
!player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1) &&
!player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1)
) {
applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 });
}
router.toFaction(faction);
}
function renderCotMG(): React.ReactElement { function renderCotMG(): React.ReactElement {
// prettier-ignore // prettier-ignore
const symbol = <Typography sx={{ lineHeight: '1em', whiteSpace: 'pre' }}> const symbol = <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>
{" `` "}<br /> {" `` "}<br />
{" -odmmNmds: "}<br /> {" -odmmNmds: "}<br />
{" `hNmo:..-omNh. "}<br /> {" `hNmo:..-omNh. "}<br />
@ -150,7 +169,46 @@ export function SpecialLocation(props: IProps): React.ReactElement {
{" sNNo-.`.-omNy` "}<br /> {" sNNo-.`.-omNy` "}<br />
{" -smNNNNmdo- "}<br /> {" -smNNNNmdo- "}<br />
{" `..` "}</Typography> {" `..` "}</Typography>
if (player.hasAugmentation(AugmentationNames.StaneksGift3, true)) {
return (
<>
<Typography>
<i>
Allison "Mother" Stanek: ..can ...you hear them too ...? Come now, don't be shy and let me get a closer
look at you. Yes wonderful, I see my creation has taken root without consquence or much ill effect it
seems. Curious, Just how much of a machine's soul do you house in that body?
</i>
</Typography>
{symbol}
</>
);
}
if (player.hasAugmentation(AugmentationNames.StaneksGift2, true)) {
return (
<>
<Typography>
<i>
Allison "Mother" Stanek: I see you've taken to my creation. So much so it could hardly be recoginized as
one of my own after your tinkering with it. I see you follow the ways of the MachineGod as I do, and your
mastery of the gift thus for clearly demonstrates that. My hopes are climbing by the day for you.
</i>
</Typography>
{symbol}
</>
);
}
if (player.factions.includes("Church of the Machine God")) {
return (
<>
<Typography>
<i>Allison "Mother" Stanek: Welcome back my child!</i>
</Typography>
{symbol}
</>
);
}
if (!player.canAccessCotMG()) {
return ( return (
<> <>
<Typography> <Typography>
@ -164,6 +222,36 @@ export function SpecialLocation(props: IProps): React.ReactElement {
); );
} }
if (
player.augmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0 ||
player.queuedAugmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0
) {
return (
<>
<Typography>
<i>
Allison "Mother" Stanek: Begone you filth! My gift must be the first modification that your body should
have!
</i>
</Typography>
</>
);
}
return (
<>
<Typography>
<i>
Allison "Mother" Stanek: Welcome child, I see your body is pure. Are you ready to ascend beyond our human
form? If you are, accept my gift.
</i>
</Typography>
<Button onClick={handleCotMG}>Accept Stanek's Gift</Button>
{symbol}
</>
);
}
switch (props.loc.name) { switch (props.loc.name) {
case LocationName.NewTokyoVitaLife: { case LocationName.NewTokyoVitaLife: {
return renderResleeving(); return renderResleeving();

@ -55,6 +55,15 @@ export const RamCostConstants: IMap<number> = {
ScriptGangApiBaseRamCost: 4, ScriptGangApiBaseRamCost: 4,
ScriptBladeburnerApiBaseRamCost: 4, ScriptBladeburnerApiBaseRamCost: 4,
ScriptStanekCharge: 0.4,
ScriptStanekFragmentDefinitions: 0,
ScriptStanekPlacedFragments: 5,
ScriptStanekClear: 0,
ScriptStanekCanPlace: 0.5,
ScriptStanekPlace: 5,
ScriptStanekFragmentAt: 2,
ScriptStanekDeleteAt: 0.15,
}; };
export const RamCosts: IMap<any> = { export const RamCosts: IMap<any> = {
@ -326,6 +335,17 @@ export const RamCosts: IMap<any> = {
purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost, purchaseSleeveAug: RamCostConstants.ScriptSleeveBaseRamCost,
}, },
stanek: {
charge: RamCostConstants.ScriptStanekCharge,
fragmentDefinitions: RamCostConstants.ScriptStanekFragmentDefinitions,
activeFragments: RamCostConstants.ScriptStanekPlacedFragments,
clear: RamCostConstants.ScriptStanekClear,
canPlace: RamCostConstants.ScriptStanekCanPlace,
place: RamCostConstants.ScriptStanekPlace,
get: RamCostConstants.ScriptStanekFragmentAt,
remove: RamCostConstants.ScriptStanekDeleteAt,
},
heart: { heart: {
// Easter egg function // Easter egg function
break: 0, break: 0,

@ -63,14 +63,24 @@ import { NetscriptGang } from "./NetscriptFunctions/Gang";
import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve"; import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve";
import { NetscriptExtra } from "./NetscriptFunctions/Extra"; import { NetscriptExtra } from "./NetscriptFunctions/Extra";
import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet"; import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
import { NS as INS, Player as INetscriptPlayer, SourceFileLvl } from "./ScriptEditor/NetscriptDefinitions"; import { NetscriptStanek } from "./NetscriptFunctions/Stanek";
import { NetscriptBladeburner } from "./NetscriptFunctions/Bladeburner"; import { NetscriptBladeburner } from "./NetscriptFunctions/Bladeburner";
import { NetscriptCodingContract } from "./NetscriptFunctions/CodingContract"; import { NetscriptCodingContract } from "./NetscriptFunctions/CodingContract";
import { NetscriptCorporation } from "./NetscriptFunctions/Corporation"; import { NetscriptCorporation } from "./NetscriptFunctions/Corporation";
import { NetscriptFormulas } from "./NetscriptFunctions/Formulas"; import { NetscriptFormulas } from "./NetscriptFunctions/Formulas";
import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
import { NetscriptStockMarket } from "./NetscriptFunctions/StockMarket"; import { NetscriptStockMarket } from "./NetscriptFunctions/StockMarket";
import {
NS as INS,
Player as INetscriptPlayer,
Gang as IGang,
Bladeburner as IBladeburner,
Stanek as IStanek,
SourceFileLvl,
} from "./ScriptEditor/NetscriptDefinitions";
import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
import { toNative } from "./NetscriptFunctions/toNative"; import { toNative } from "./NetscriptFunctions/toNative";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
@ -80,6 +90,9 @@ import { Flags } from "./NetscriptFunctions/Flags";
interface NS extends INS { interface NS extends INS {
[key: string]: any; [key: string]: any;
gang: IGang;
bladeburner: IBladeburner;
stanek: IStanek;
} }
export function NetscriptFunctions(workerScript: WorkerScript): NS { export function NetscriptFunctions(workerScript: WorkerScript): NS {
@ -431,6 +444,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const sleeve = NetscriptSleeve(Player, workerScript, helper); const sleeve = NetscriptSleeve(Player, workerScript, helper);
const extra = NetscriptExtra(Player, workerScript); const extra = NetscriptExtra(Player, workerScript);
const hacknet = NetscriptHacknet(Player, workerScript, helper); const hacknet = NetscriptHacknet(Player, workerScript, helper);
const stanek = NetscriptStanek(Player, workerScript, helper);
const bladeburner = NetscriptBladeburner(Player, workerScript, helper); const bladeburner = NetscriptBladeburner(Player, workerScript, helper);
const codingcontract = NetscriptCodingContract(Player, workerScript, helper); const codingcontract = NetscriptCodingContract(Player, workerScript, helper);
const corporation = NetscriptCorporation(Player); const corporation = NetscriptCorporation(Player);
@ -445,6 +459,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
bladeburner: bladeburner, bladeburner: bladeburner,
codingcontract: codingcontract, codingcontract: codingcontract,
sleeve: sleeve, sleeve: sleeve,
stanek: stanek,
formulas: formulas, formulas: formulas,
stock: stockmarket, stock: stockmarket,
@ -2255,7 +2270,6 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
Object.assign(data.jobs, Player.jobs); Object.assign(data.jobs, Player.jobs);
return data; return data;
}, },
atExit: function (f: any): void { atExit: function (f: any): void {
if (typeof f !== "function") { if (typeof f !== "function") {
throw makeRuntimeErrorMsg("atExit", "argument should be function"); throw makeRuntimeErrorMsg("atExit", "argument should be function");

@ -1226,19 +1226,5 @@ export function NetscriptSingularity(
return Object.assign({}, crime); return Object.assign({}, crime);
}, },
isFocused: function (): boolean {
helper.updateDynamicRam("isFocused", getRamCost("isFocused"));
helper.checkSingularityAccess("isFocused", 2);
return player.focus;
},
setFocus: function (focus: any): void {
helper.updateDynamicRam("setFocus", getRamCost("setFocus"));
helper.checkSingularityAccess("setFocus", 2);
if (focus === true) {
player.startFocusing();
} else if (focus === false) {
player.stopFocusing();
}
},
}; };
} }

@ -0,0 +1,109 @@
import { INetscriptHelper } from "./INetscriptHelper";
import { IPlayer } from "../PersonObjects/IPlayer";
import { WorkerScript } from "../Netscript/WorkerScript";
import { netscriptDelay } from "../NetscriptEvaluator";
import { getRamCost } from "../Netscript/RamCostGenerator";
import { staneksGift } from "../CotMG/Helper";
import { Fragments, FragmentById } from "../CotMG/Fragment";
import {
Stanek as IStanek,
Fragment as IFragment,
ActiveFragment as IActiveFragment,
} from "../ScriptEditor/NetscriptDefinitions";
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IStanek {
function checkStanekAPIAccess(func: string): void {
if (!player.hasAugmentation(AugmentationNames.StaneksGift1, true)) {
helper.makeRuntimeErrorMsg(func, "Requires Stanek's Gift installed.");
}
}
return {
width: function (): number {
return staneksGift.width();
},
height: function (): number {
return staneksGift.height();
},
charge: function (arootX: any, arootY: any): Promise<void> {
const rootX = helper.number("stanek.charge", "rootX", arootX);
const rootY = helper.number("stanek.charge", "rootY", arootY);
helper.updateDynamicRam("charge", getRamCost("stanek", "charge"));
checkStanekAPIAccess("charge");
const fragment = staneksGift.findFragment(rootX, rootY);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.charge", `No fragment with root (${rootX}, ${rootY}).`);
const time = staneksGift.inBonus() ? 200 : 1000;
return netscriptDelay(time, workerScript).then(function () {
if (workerScript.env.stopFlag) {
return Promise.reject(workerScript);
}
const charge = staneksGift.charge(player, fragment, workerScript.scriptRef.threads);
workerScript.log("stanek.charge", () => `Charged fragment for ${charge} charge.`);
return Promise.resolve();
});
},
fragmentDefinitions: function (): IFragment[] {
helper.updateDynamicRam("fragmentDefinitions", getRamCost("stanek", "fragmentDefinitions"));
checkStanekAPIAccess("fragmentDefinitions");
workerScript.log("stanek.fragmentDefinitions", () => `Returned ${Fragments.length} fragments`);
return Fragments.map((f) => f.copy());
},
activeFragments: function (): IActiveFragment[] {
helper.updateDynamicRam("activeFragments", getRamCost("stanek", "activeFragments"));
checkStanekAPIAccess("activeFragments");
workerScript.log("stanek.activeFragments", () => `Returned ${staneksGift.fragments.length} fragments`);
return staneksGift.fragments.map((af) => {
return { ...af.copy(), ...af.fragment().copy() };
});
},
clear: function (): void {
helper.updateDynamicRam("clear", getRamCost("stanek", "clear"));
checkStanekAPIAccess("clear");
workerScript.log("stanek.clear", () => `Cleared Stanek's Gift.`);
staneksGift.clear();
},
canPlace: function (arootX: any, arootY: any, arotation: any, afragmentId: any): boolean {
const rootX = helper.number("stanek.canPlace", "rootX", arootX);
const rootY = helper.number("stanek.canPlace", "rootY", arootY);
const rotation = helper.number("stanek.canPlace", "rotation", arotation);
const fragmentId = helper.number("stanek.canPlace", "fragmentId", afragmentId);
helper.updateDynamicRam("canPlace", getRamCost("stanek", "canPlace"));
checkStanekAPIAccess("canPlace");
const fragment = FragmentById(fragmentId);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.canPlace", `Invalid fragment id: ${fragmentId}`);
const can = staneksGift.canPlace(rootX, rootY, rotation, fragment);
return can;
},
place: function (arootX: any, arootY: any, arotation: any, afragmentId: any): boolean {
const rootX = helper.number("stanek.place", "rootX", arootX);
const rootY = helper.number("stanek.place", "rootY", arootY);
const rotation = helper.number("stanek.place", "rotation", arotation);
const fragmentId = helper.number("stanek.place", "fragmentId", afragmentId);
helper.updateDynamicRam("place", getRamCost("stanek", "place"));
checkStanekAPIAccess("place");
const fragment = FragmentById(fragmentId);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.place", `Invalid fragment id: ${fragmentId}`);
return staneksGift.place(rootX, rootY, rotation, fragment);
},
get: function (arootX: any, arootY: any): IActiveFragment | undefined {
const rootX = helper.number("stanek.get", "rootX", arootX);
const rootY = helper.number("stanek.get", "rootY", arootY);
helper.updateDynamicRam("get", getRamCost("stanek", "get"));
checkStanekAPIAccess("get");
const fragment = staneksGift.findFragment(rootX, rootY);
if (fragment !== undefined) return fragment.copy();
return undefined;
},
remove: function (arootX: any, arootY: any): boolean {
const rootX = helper.number("stanek.remove", "rootX", arootX);
const rootY = helper.number("stanek.remove", "rootY", arootY);
helper.updateDynamicRam("remove", getRamCost("stanek", "remove"));
checkStanekAPIAccess("remove");
return staneksGift.delete(rootX, rootY);
},
};
}

@ -115,6 +115,7 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
if (typeof workerScript.env.vars[prop] !== "function") continue; if (typeof workerScript.env.vars[prop] !== "function") continue;
workerScript.env.vars[prop] = wrap(prop, workerScript.env.vars[prop]); workerScript.env.vars[prop] = wrap(prop, workerScript.env.vars[prop]);
} }
workerScript.env.vars.stanek.charge = wrap("stanek.prop", workerScript.env.vars.stanek.charge);
// Note: the environment that we pass to the JS script only needs to contain the functions visible // Note: the environment that we pass to the JS script only needs to contain the functions visible
// to that script, which env.vars does at this point. // to that script, which env.vars does at this point.

@ -277,5 +277,6 @@ export interface IPlayer {
setBitNodeNumber(n: number): void; setBitNodeNumber(n: number): void;
getMult(name: string): number; getMult(name: string): number;
setMult(name: string, mult: number): void; setMult(name: string, mult: number): void;
canAccessCotMG(): boolean;
sourceFileLvl(n: number): number; sourceFileLvl(n: number): number;
} }

@ -283,6 +283,7 @@ export class PlayerObject implements IPlayer {
setBitNodeNumber: (n: number) => void; setBitNodeNumber: (n: number) => void;
getMult: (name: string) => number; getMult: (name: string) => number;
setMult: (name: string, mult: number) => void; setMult: (name: string, mult: number) => void;
canAccessCotMG: () => boolean;
sourceFileLvl: (n: number) => number; sourceFileLvl: (n: number) => number;
constructor() { constructor() {
@ -579,6 +580,8 @@ export class PlayerObject implements IPlayer {
this.getMult = generalMethods.getMult; this.getMult = generalMethods.getMult;
this.setMult = generalMethods.setMult; this.setMult = generalMethods.setMult;
this.canAccessCotMG = generalMethods.canAccessCotMG;
this.sourceFileLvl = generalMethods.sourceFileLvl; this.sourceFileLvl = generalMethods.sourceFileLvl;
} }

@ -105,7 +105,14 @@ export function generateResleeves(): Resleeve[] {
const randKey: string = augKeys[randIndex]; const randKey: string = augKeys[randIndex];
// Forbidden augmentations // Forbidden augmentations
if (randKey === AugmentationNames.TheRedPill || randKey === AugmentationNames.NeuroFluxGovernor) { const forbidden = [
AugmentationNames.TheRedPill,
AugmentationNames.NeuroFluxGovernor,
AugmentationNames.StaneksGift1,
AugmentationNames.StaneksGift2,
AugmentationNames.StaneksGift3,
];
if (forbidden.includes(randKey)) {
continue; continue;
} }

@ -26,8 +26,10 @@ import { Terminal } from "./Terminal";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
import { staneksGift } from "./CotMG/Helper";
import { ProgramsSeen } from "./Programs/ui/ProgramsRoot"; import { ProgramsSeen } from "./Programs/ui/ProgramsRoot";
import { InvitationsSeen } from "./Faction/ui/FactionsRoot"; import { InvitationsSeen } from "./Faction/ui/FactionsRoot";
import { CONSTANTS } from "./Constants";
import { LogBoxClearEvents } from "./ui/React/LogBoxManager"; import { LogBoxClearEvents } from "./ui/React/LogBoxManager";
const BitNode8StartingMoney = 250e6; const BitNode8StartingMoney = 250e6;
@ -143,6 +145,14 @@ export function prestigeAugmentation(): void {
} }
} }
if (augmentationExists(AugmentationNames.StaneksGift1) && Augmentations[AugmentationNames.StaneksGift1].owned) {
// TODO(hydroflame): refactor faction names so we don't have to hard
// code strings.
joinFaction(Factions["Church of the Machine God"]);
}
staneksGift.prestigeAugmentation();
resetPidCounter(); resetPidCounter();
ProgramsSeen.splice(0, ProgramsSeen.length); ProgramsSeen.splice(0, ProgramsSeen.length);
InvitationsSeen.splice(0, InvitationsSeen.length); InvitationsSeen.splice(0, InvitationsSeen.length);
@ -247,6 +257,10 @@ export function prestigeSourceFile(flume: boolean): void {
dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!"); dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!");
} }
if (Player.bitNodeN === 13) {
dialogBoxCreate("Trouble is brewing in Chongqing");
}
// Reset Stock market, gang, and corporation // Reset Stock market, gang, and corporation
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
initStockMarket(); initStockMarket();
@ -272,6 +286,11 @@ export function prestigeSourceFile(flume: boolean): void {
updateHashManagerCapacity(Player); updateHashManagerCapacity(Player);
} }
if (Player.bitNodeN === 13) {
Player.money = CONSTANTS.TravelCost;
}
staneksGift.prestigeSourceFile();
// Gain int exp // Gain int exp
if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300); if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300);

@ -9,6 +9,7 @@ import { saveAllServers, loadAllServers, GetAllServers } from "./Server/AllServe
import { Settings } from "./Settings/Settings"; import { Settings } from "./Settings/Settings";
import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket"; import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
import { staneksGift, loadStaneksGift } from "./CotMG/Helper";
import { SnackbarEvents } from "./ui/React/Snackbar"; import { SnackbarEvents } from "./ui/React/Snackbar";
@ -38,6 +39,7 @@ class BitburnerSaveObject {
VersionSave = ""; VersionSave = "";
AllGangsSave = ""; AllGangsSave = "";
LastExportBonus = ""; LastExportBonus = "";
StaneksGiftSave = "";
getSaveString(): string { getSaveString(): string {
this.PlayerSave = JSON.stringify(Player); this.PlayerSave = JSON.stringify(Player);
@ -52,6 +54,7 @@ class BitburnerSaveObject {
this.SettingsSave = JSON.stringify(Settings); this.SettingsSave = JSON.stringify(Settings);
this.VersionSave = JSON.stringify(CONSTANTS.VersionNumber); this.VersionSave = JSON.stringify(CONSTANTS.VersionNumber);
this.LastExportBonus = JSON.stringify(ExportBonus.LastExportBonus); this.LastExportBonus = JSON.stringify(ExportBonus.LastExportBonus);
this.StaneksGiftSave = JSON.stringify(staneksGift);
if (Player.inGang()) { if (Player.inGang()) {
this.AllGangsSave = JSON.stringify(AllGangs); this.AllGangsSave = JSON.stringify(AllGangs);
} }
@ -240,6 +243,12 @@ function loadGame(saveString: string): boolean {
loadCompanies(saveObj.CompaniesSave); loadCompanies(saveObj.CompaniesSave);
loadFactions(saveObj.FactionsSave); loadFactions(saveObj.FactionsSave);
if (saveObj.hasOwnProperty("StaneksGiftSave")) {
loadStaneksGift(saveObj.StaneksGiftSave);
} else {
console.warn(`Could not load Staneks Gift from save`);
loadStaneksGift("");
}
if (saveObj.hasOwnProperty("AliasesSave")) { if (saveObj.hasOwnProperty("AliasesSave")) {
try { try {
loadAliases(saveObj.AliasesSave); loadAliases(saveObj.AliasesSave);

@ -183,6 +183,8 @@ async function parseOnlyRamCalculate(
func = workerScript.env.vars.bladeburner[ref]; func = workerScript.env.vars.bladeburner[ref];
} else if (ref in workerScript.env.vars.codingcontract) { } else if (ref in workerScript.env.vars.codingcontract) {
func = workerScript.env.vars.codingcontract[ref]; func = workerScript.env.vars.codingcontract[ref];
} else if (ref in workerScript.env.vars.stanek) {
func = workerScript.env.vars.stanek[ref];
} else if (ref in workerScript.env.vars.gang) { } else if (ref in workerScript.env.vars.gang) {
func = workerScript.env.vars.gang[ref]; func = workerScript.env.vars.gang[ref];
} else if (ref in workerScript.env.vars.sleeve) { } else if (ref in workerScript.env.vars.sleeve) {

@ -372,6 +372,45 @@ export interface Server {
/** Flag indicating whether the SSH Port is open */ /** Flag indicating whether the SSH Port is open */
sshPortOpen: boolean; sshPortOpen: boolean;
/** Flag indicating whether this is a purchased server */
purchasedByPlayer: boolean;
/** Flag indicating whether this server has a backdoor installed by a player */
backdoorInstalled: boolean;
/**
* Initial server security level
* (i.e. security level when the server was created)
*/
baseDifficulty: number;
/** Server Security Level */
hackDifficulty: number;
/** Minimum server security level that this server can be weakened to */
minDifficulty: number;
/** How much money currently resides on the server and can be hacked */
moneyAvailable: number;
/** Maximum amount of money that this server can hold */
moneyMax: number;
/** Number of open ports required in order to gain admin/root access */
numOpenPortsRequired: number;
/** How many ports are currently opened on the server */
openPortCount: number;
/** Hacking level required to hack this server */
requiredHackingSkill: number;
/**
* Parameter that affects how effectively this server's money can
* be increased using the grow() Netscript function
*/
serverGrowth: number;
} }
/** /**
@ -1940,24 +1979,6 @@ export interface Singularity {
* @returns True if the installation was successful. * @returns True if the installation was successful.
*/ */
installBackdoor(): Promise<void>; installBackdoor(): Promise<void>;
/**
* SF4.2 - Check if the player is focused.
* @remarks
* RAM cost: 0.1 GB
*
*
* @returns True if the player is focused.
*/
isFocused(): void;
/**
* SF4.2 - Set the players focus.
* @remarks
* RAM cost: 0.1 GB
*
*/
setFocus(focus: boolean): void;
} }
/** /**
@ -3325,6 +3346,131 @@ export interface Formulas {
hacknetServers: HacknetServersFormulas; hacknetServers: HacknetServersFormulas;
} }
/**
* @public
*/
export interface Fragment {
id: number;
shape: boolean[][];
type: number;
power: number;
limit: number;
}
/**
* @public
*/
export interface ActiveFragment {
id: number;
avgCharge: number;
numCharge: number;
rotation: number;
x: number;
y: number;
}
/**
* Stanek's Gift API.
* @public
*/
interface Stanek {
/**
* Stanek's Gift width.
* @remarks
* RAM cost: 0.4 GB
* @returns The width of the gift.
*/
width(): number;
/**
* Stanek's Gift height.
* @remarks
* RAM cost: 0.4 GB
* @returns The height of the gift.
*/
height(): number;
/**
* Charge a fragment, increasing it's power.
* @remarks
* RAM cost: 0.4 GB
* @param rootX - rootX Root X against which to align the top left of the fragment.
* @param rootY - rootY Root Y against which to align the top left of the fragment.
* @returns Promise that lasts until the charge action is over.
*/
charge(rootX: number, rootY: number): Promise<void>;
/**
* List possible fragments.
* @remarks
* RAM cost: cost: 0 GB
*
* @returns List of possible fragments.
*/
fragmentDefinitions(): Fragment[];
/**
* List of fragments in Stanek's Gift.
* @remarks
* RAM cost: cost: 5 GB
*
* @returns List of active fragments placed on Stanek's Gift.
*/
activeFragments(): ActiveFragment[];
/**
* Clear the board of all fragments.
* @remarks
* RAM cost: cost: 0 GB
*/
clear(): void;
/**
* Check if fragment can be placed at specified location.
* @remarks
* RAM cost: cost: 0.5 GB
*
* @param rootX - rootX Root X against which to align the top left of the fragment.
* @param rootY - rootY Root Y against which to align the top left of the fragment.
* @param rotation - rotation A number from 0 to 3, the mount of 90 degree turn to take.
* @param fragmentId - fragmentId ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
canPlace(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Place fragment on Stanek's Gift.
* @remarks
* RAM cost: cost: 5 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @param rotation - A number from 0 to 3, the mount of 90 degree turn to take.
* @param fragmentId - ID of the fragment to place.
* @returns true if the fragment can be placed at that position. false otherwise.
*/
place(rootX: number, rootY: number, rotation: number, fragmentId: number): boolean;
/**
* Get placed fragment at location.
* @remarks
* RAM cost: cost: 5 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
get(rootX: number, rootY: number): ActiveFragment | undefined;
/**
* Remove fragment at location.
* @remarks
* RAM cost: cost: 0.15 GB
*
* @param rootX - X against which to align the top left of the fragment.
* @param rootY - Y against which to align the top left of the fragment.
* @returns The fragment at [rootX, rootY], if any.
*/
remove(rootX: number, rootY: number): boolean;
}
/** /**
* Collection of all functions passed to scripts * Collection of all functions passed to scripts
* @public * @public
@ -3374,6 +3520,11 @@ export interface NS extends Singularity {
* RAM cost: 0 GB * RAM cost: 0 GB
*/ */
readonly formulas: Formulas; readonly formulas: Formulas;
/**
* Namespace for stanek functions.
* RAM cost: 0 GB
*/
readonly stanek: Stanek;
/** /**
* Arguments passed into the script. * Arguments passed into the script.

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