Fix bug where ISocket get refreshed more than once, add BN19

This commit is contained in:
Olivier Gagnon 2024-06-10 21:47:59 -04:00
parent 548f08ce62
commit 3d87baeb15
No known key found for this signature in database
GPG Key ID: 0018772EA86FA03F
12 changed files with 262 additions and 16 deletions

@ -2,6 +2,7 @@ import React from "react";
import { Player } from "@player";
import { CityName, FactionName } from "@enums";
import { BitNodeMultipliers, replaceCurrentNodeMults } from "./BitNodeMultipliers";
import { CorruptableText } from "../ui/React/CorruptableText";
class BitNode {
// A short description, or tagline, about the BitNode
@ -480,6 +481,19 @@ export function initBitNodes() {
</>
),
);
BitNodes.BitNode19 = new BitNode(
19,
2,
"MyrianOS",
"l̷i̵g̵h̴t̵ ̴a̷t̸ ̶t̵h̵e̸ ̶e̷n̵d̶ ̶o̸f̶ ̸t̴h̸e̴ ̸t̷u̶n̸n̸e̷l̵.̷",
(
<CorruptableText
content={`yNjHLAgecI ASW1fQdKx5 n9DQ3rmHp3 mnv0XEdwH2 sBkAlBOPhx NohIDL9eRy TbIl8U3WKz 1wjnJ9iuwS VML36vYLNH K06StviNvI cRboTarefZ 7BSNntPpJj DfayVbfxU6 46xvOPQd2Y Ogyj2gnyLr FIND THE GLITCH IN ISHIMA S6E0Vpmxk6 GTF9dWvE6n EEGg7xvtYR Um8YIC0Qww PG4vauBKBk JWG8V1j5Z5 bfYYTTFnBY 7uoicoqIaV IeUu0F42aA EhTF7Fkxyt OBYgGSu0es bJQpenVoO6 L9cL39tRhh xfLroUMvY8 xmMckUHLSQ`}
spoiler={false}
/>
),
);
}
export const defaultMultipliers = new BitNodeMultipliers();
@ -987,6 +1001,64 @@ export function getBitNodeMultipliers(n: number, lvl: number): BitNodeMultiplier
WorldDaemonDifficulty: 5,
});
}
case 19: {
return new BitNodeMultipliers({
MyrianPower: 10,
AgilityLevelMultiplier: 0.01,
AugmentationMoneyCost: 100,
AugmentationRepCost: 100,
BladeburnerRank: 0.01,
BladeburnerSkillCost: 100,
CharismaLevelMultiplier: 0.01,
ClassGymExpGain: 0.01,
CodingContractMoney: 0.01,
CompanyWorkExpGain: 0.01,
CompanyWorkMoney: 0.01,
CompanyWorkRepGain: 0.01,
CorporationValuation: 0.01,
CrimeExpGain: 0.01,
CrimeMoney: 0.01,
CrimeSuccessRate: 0.01,
DaedalusAugsRequirement: 100,
DefenseLevelMultiplier: 0.01,
DexterityLevelMultiplier: 0.01,
FactionPassiveRepGain: 0.01,
FactionWorkExpGain: 0.01,
FactionWorkRepGain: 0.01,
FourSigmaMarketDataApiCost: 100,
FourSigmaMarketDataCost: 100,
GangSoftcap: 0.01,
GangUniqueAugs: 0.01,
GoPower: 0.01,
HackExpGain: 0.01,
HackingLevelMultiplier: 0.01,
HackingSpeedMultiplier: 0.01,
HacknetNodeMoney: 0.01,
HomeComputerRamCost: 100,
InfiltrationMoney: 0.01,
InfiltrationRep: 0.01,
ManualHackMoney: 0.01,
PurchasedServerCost: 100,
PurchasedServerSoftcap: 100,
PurchasedServerLimit: 0.01,
PurchasedServerMaxRam: 0.01,
RepToDonateToFaction: 10000,
ScriptHackMoney: 0.01,
ScriptHackMoneyGain: 0.01,
ServerGrowthRate: 0.01,
ServerMaxMoney: 0.01,
ServerStartingMoney: 0.01,
ServerStartingSecurity: 100,
ServerWeakenRate: 0.01,
StrengthLevelMultiplier: 0.01,
StaneksGiftPowerMultiplier: 0.01,
StaneksGiftExtraSize: -100,
WorldDaemonDifficulty: 100,
CorporationSoftcap: 0.01,
CorporationDivisions: 0.01,
});
}
default: {
throw new Error("Invalid BitNodeN");
}

@ -114,6 +114,9 @@ export class BitNodeMultipliers {
*/
ManualHackMoney = 1;
/** Influence how strongly Myrian improves bitnode multipliers */
MyrianPower = 1;
/** Influence how much it costs to purchase a server */
PurchasedServerCost = 1;

@ -239,7 +239,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | O O | O O | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | / __| \ | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | O / | O | | O | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | <BitNodePortal n={19} level={n(19)} flume={props.flume} destroyedBitNode={destroyed} /> / | O | | O | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | |_/ |/ | \_ \_| | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | | <BitNodePortal n={14} level={n(14)} flume={props.flume} destroyedBitNode={destroyed} /> | | O__/ | / \__ | | O | | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | / /| O / \| | | | | | | </Typography>

@ -300,13 +300,38 @@ export function SpecialLocation(props: SpecialLocationProps): React.ReactElement
}
function renderGlitch(): React.ReactElement {
const onClick = () => {
dialogBoxCreate(
"Hexabytes of information are streamed to your mind. Completely drained one thing remained clear as crystal. You now understand how to connect directly to the machine running the bitnodes. Myrian.",
);
Router.toPage(Page.MyrianOS);
Player.myrianConnection = true;
};
if (!Player.canAccessMyrian())
return (
<>
<Typography>
<CorruptableText content={"An eerie aura surrounds this area. You feel you should leave."} spoiler={false} />
<CorruptableText
content={"An eerie aura surrounds this area. You feel you should leave."}
spoiler={false}
/>
</Typography>
</>
);
return (
<>
<Typography>
You find yourself standing in a small, unremarkable alley. Despite the lack of air you do not feel the need to
breathe. There is no light, yet you can see every details of every objects in the alley. A rat walking in the
alley completely stop in it's track as if frozen in time. You know what this means. This location has fallen
through the crack of the Enders.
<br />
In the middle of the alley is a personal link port. You can connect your personal link to the anomaly.
</Typography>
<Button onClick={onClick}>Connect your personal link to the anomaly</Button>
</>
);
}
switch (props.loc.name) {

@ -1,10 +1,14 @@
import React from "react";
import { Container, Typography } from "@mui/material";
import { Container, IconButton, Typography } from "@mui/material";
import { styled } from "@mui/system";
import { myrian, myrianSize } from "../Helper";
import { useRerender } from "../../ui/React/hooks";
import { DeviceIcon, cellSize } from "./DeviceIcon";
import { Info } from "@mui/icons-material";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { MD } from "../../ui/MD/MD";
import { tutorial } from "./tutorial";
const CellD = styled("div")({
width: cellSize + "px",
@ -80,9 +84,18 @@ interface IProps {}
export const MyrianRoot = (__props: IProps): React.ReactElement => {
useRerender(50);
const onHelp = () => {
dialogBoxCreate(<MD md={tutorial} />);
};
return (
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
<Typography variant="h4">Myrian OS</Typography>
<Typography variant="h4">
Myrian OS
<IconButton onClick={onHelp}>
<Info />
</IconButton>
</Typography>
<Typography>
{myrian.vulns} vulns : {myrian.totalVulns} total vulns
</Typography>

109
src/Myrian/ui/tutorial.ts Normal file

@ -0,0 +1,109 @@
export const tutorial = `# Myrian
Myrian is the name of the OS that the BitNodes run on.
By gaining access to the OS directly you can start to break it apart by generating vulnerabilities (vulns).
You do so by interracting with the various devices in the OS, represented by a grid.
## Devices
A device is a component that takes space on the Myrian, no 2 devices can be on the same tile.
Devices can only interract when directly adjacent to each other. When one or more device is
performing an action it will become busy and no other actions can be taken until the current one finishes.
Contrary to every other mechanic in the game. Async functions using myrian functions CAN run simultenaously.
### Bus
The most important device is the Bus. Here's a few of the things it can do:
- move, only 1 tile at a time and that tile must be empty. No diagonal.
- transfer content, most entity can store items called components, bus are the only device that can transfer components to and from other devices
- use other devices, e.g. Use a Reducer device to create new components.
### ISocket
These devices produce basic components that can be used for other devices, [r0, g0, b0].
They must be picked up by busses and will eventually produce another one after a certain cooldown has passed.
### OSocket
These devices request components and produce vulns in return, a bus simply needs to transfer a component into a OSocket content in order to fulfill the request
### Reducer
These devices can be used by a bus, when being used they will first check their content, if the content matches one of the recipe they will take some time to consume their content in order to produce a new, upgraded, more valuable component, e.g. r0 + r0 => r1
### Cache
These devices act as storage for components.
### Lock
These devices cannot be installed. They appear after various conditions are fulfilled in order to block certain tiles.
### Battery
These devices are only relevant when the Magnetism glitch is active. It recharges the energy of a bus.
## Installing
Bus can install new devices, when they do so a lock will appear over the tile that will eventually become the device. The cost of any device depends on the number of that type of device currently in the OS.
### Uninstalling
A bus can remove a device, there is no refund.
## Tiers
Upgrading a reducers tier allows it to reduce components of a higher tier and ONLY that higher tier.
A tier 2 reducer can only tier 2 components like r1 + r1 => r2 and loses access to r0 + r0 => r1
Upgrading a batterys tier increases the amount of energy it produces.
## Glitches
glitches are optional difficulty modifiers that make the myrian more difficult BUT increase the amount of vulns gained.
All glitches start at level 0 and must be activated when you chose. They also have a max level that differs from glitch to glitch.
### Magnetism
By default bus lose 0 energy when moving. But when this glitch is active they start losing energy, at 0 energy bus move much more slowly. Batteries must be installed and used to charge busses.
### Friction
When Friction is active busses move more slowly.
### Rust
When rust is active, hidden tiles are set on the Myrian. When a bus steps on one of these hidden tiles one of their upgrade lowers. Higher Rust level means lowers by a larger amount and more rust tiles are set.
### Isolation
When Isolation is active busses transfer and charge more slowly.
### Segmentation
When Segmentation is active random Locks will spawn on the Myrian. You have to remove these locks or the bord will be overrun with Locks and you won't be able to move.
### Virtualization
When Virtualization is active busses install and uninstall devices more slowly.
### Jamming
When Jamming is active busses use reducers more slowly.
### Roaming
When Roaming is active, isockets and osockets start to move around the map
### Encryption
Encryption is the only glitch that's always active. The level of Encryption determines the complexity of the requests made by osockets.
## Destabilization
As the number of total vulns increase the bitnode becomes unstable and it's multiplier become more favorable.
`;

@ -193,6 +193,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
return helpers
.netscriptDelay(ctx, transferSpeed(bus.transferLvl) * isolationMult(myrian.glitches[Glitch.Isolation]), true)
.then(() => {
const previousSize = container.content.length;
toDevice.content = toDevice.content.filter((item) => !output.includes(item));
toDevice.content.push(...input);
@ -201,6 +202,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
switch (container.type) {
case DeviceType.ISocket: {
if (previousSize <= container.content.length) break;
const cooldown = isocketSpeed(container.emissionLvl);
container.cooldownUntil = Date.now() + cooldown;
setTimeout(() => {
@ -210,7 +212,7 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
}
case DeviceType.OSocket: {
if (inventoryMatches(container.currentRequest, container.content)) {
if (!inventoryMatches(container.currentRequest, container.content)) break;
const gain =
container.content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0) * getTotalGlitchMult();
myrian.vulns += gain;
@ -219,7 +221,6 @@ export function NetscriptMyrian(): InternalAPI<IMyrian> {
const request = getNextISocketRequest(myrian.glitches[Glitch.Encryption]);
container.currentRequest = request;
container.maxContent = request.length;
}
break;
}
}

@ -68,6 +68,7 @@ export class PlayerObject extends Person implements IPlayer {
lastUpdate = 0;
lastSave = 0;
totalPlaytime = 0;
myrianConnection = false;
currentWork: Work | null = null;
focus = false;
@ -129,6 +130,7 @@ export class PlayerObject extends Person implements IPlayer {
checkForFactionInvitations = generalMethods.checkForFactionInvitations;
setBitNodeNumber = generalMethods.setBitNodeNumber;
canAccessCotMG = generalMethods.canAccessCotMG;
canAccessMyrian = generalMethods.canAccessMyrian;
sourceFileLvl = generalMethods.sourceFileLvl;
applyEntropy = augmentationMethods.applyEntropy;
focusPenalty = generalMethods.focusPenalty;

@ -577,6 +577,10 @@ export function canAccessCotMG(this: PlayerObject): boolean {
return this.bitNodeN === 13 || this.sourceFileLvl(13) > 0;
}
export function canAccessMyrian(this: PlayerObject): boolean {
return this.bitNodeN === 19 || this.sourceFileLvl(19) > 0;
}
export function sourceFileLvl(this: PlayerObject, n: number): number {
return this.sourceFiles.get(n) ?? 0;
}

@ -313,7 +313,7 @@ export function prestigeSourceFile(isFlume: boolean): void {
updateHashManagerCapacity();
}
if (Player.bitNodeN === 13) {
if (Player.bitNodeN === 13 || Player.bitNodeN === 19) {
Player.money = CONSTANTS.TravelCost;
}
staneksGift.prestigeSourceFile();

@ -35,6 +35,7 @@ import CheckIcon from "@mui/icons-material/Check"; // Milestones
import HelpIcon from "@mui/icons-material/Help"; // Tutorial
import SettingsIcon from "@mui/icons-material/Settings"; // options
import DeveloperBoardIcon from "@mui/icons-material/DeveloperBoard"; // Dev
import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent"; // Myrian
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents"; // Achievements
import AccountBoxIcon from "@mui/icons-material/AccountBox";
import PublicIcon from "@mui/icons-material/Public";
@ -354,7 +355,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement {
canCorporation && { key_: Page.Corporation, icon: BusinessIcon },
canGang && { key_: Page.Gang, icon: SportsMmaIcon },
canIPvGO && { key_: Page.Go, icon: BorderInnerSharp },
{ key_: Page.MyrianOS, icon: DeveloperBoardIcon },
(true || Player.myrianConnection) && { key_: Page.MyrianOS, icon: SettingsInputComponentIcon },
]}
/>
<Divider />

@ -256,4 +256,20 @@ export function initSourceFiles() {
</>
),
);
SourceFiles.SourceFile19 = new SourceFile(
19,
(
<>
This Source-File grants the following benefits:
<br />
<br />
Level 1: Reduce the effect of the Rust Glitch
<br />
Level 2: Reduce the effect of the Magnetism Glitch
<br />
Level 3: Reduce the effect of the Friction, Isolation, Virtualization, and Jamming Glitch
</>
),
);
}