From 3d87baeb15040d2196af6a3658c8134c14f9da80 Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Mon, 10 Jun 2024 21:47:59 -0400 Subject: [PATCH] Fix bug where ISocket get refreshed more than once, add BN19 --- src/BitNode/BitNode.tsx | 72 ++++++++++++ src/BitNode/BitNodeMultipliers.ts | 3 + src/BitNode/ui/BitverseRoot.tsx | 2 +- src/Locations/ui/SpecialLocation.tsx | 27 ++++- src/Myrian/ui/MyrianRoot.tsx | 17 ++- src/Myrian/ui/tutorial.ts | 109 ++++++++++++++++++ src/NetscriptFunctions/Myrian.ts | 21 ++-- src/PersonObjects/Player/PlayerObject.ts | 2 + .../Player/PlayerObjectGeneralMethods.ts | 4 + src/Prestige.ts | 2 +- src/Sidebar/ui/SidebarRoot.tsx | 3 +- src/SourceFile/SourceFiles.tsx | 16 +++ 12 files changed, 262 insertions(+), 16 deletions(-) create mode 100644 src/Myrian/ui/tutorial.ts diff --git a/src/BitNode/BitNode.tsx b/src/BitNode/BitNode.tsx index 01741816b..5588cabd8 100644 --- a/src/BitNode/BitNode.tsx +++ b/src/BitNode/BitNode.tsx @@ -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̵.̷", + ( + + ), + ); } 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"); } diff --git a/src/BitNode/BitNodeMultipliers.ts b/src/BitNode/BitNodeMultipliers.ts index eb2a98219..c253e3851 100644 --- a/src/BitNode/BitNodeMultipliers.ts +++ b/src/BitNode/BitNodeMultipliers.ts @@ -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; diff --git a/src/BitNode/ui/BitverseRoot.tsx b/src/BitNode/ui/BitverseRoot.tsx index 798d50ae2..17696054c 100644 --- a/src/BitNode/ui/BitverseRoot.tsx +++ b/src/BitNode/ui/BitverseRoot.tsx @@ -239,7 +239,7 @@ export function BitverseRoot(props: IProps): React.ReactElement { O | O O | O O | O | | / __| \ | | O - O | O | | O / | O | | O | O + O | O | | / | O | | O | O | | | | |_/ |/ | \_ \_| | | | | O | | | | | O__/ | / \__ | | O | | | O | | | | | | | / /| O / \| | | | | | | diff --git a/src/Locations/ui/SpecialLocation.tsx b/src/Locations/ui/SpecialLocation.tsx index 6f776eafb..f914f7abd 100644 --- a/src/Locations/ui/SpecialLocation.tsx +++ b/src/Locations/ui/SpecialLocation.tsx @@ -300,11 +300,36 @@ 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 ( + <> + + + + + ); + return ( <> - + 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. +
+ In the middle of the alley is a personal link port. You can connect your personal link to the anomaly.
+ ); } diff --git a/src/Myrian/ui/MyrianRoot.tsx b/src/Myrian/ui/MyrianRoot.tsx index 37b5e60fb..ba2aeed85 100644 --- a/src/Myrian/ui/MyrianRoot.tsx +++ b/src/Myrian/ui/MyrianRoot.tsx @@ -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(); + }; return ( - Myrian OS + + Myrian OS + + + + {myrian.vulns} vulns : {myrian.totalVulns} total vulns diff --git a/src/Myrian/ui/tutorial.ts b/src/Myrian/ui/tutorial.ts new file mode 100644 index 000000000..ad400f5bd --- /dev/null +++ b/src/Myrian/ui/tutorial.ts @@ -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. +`; diff --git a/src/NetscriptFunctions/Myrian.ts b/src/NetscriptFunctions/Myrian.ts index 511882738..505b583c1 100644 --- a/src/NetscriptFunctions/Myrian.ts +++ b/src/NetscriptFunctions/Myrian.ts @@ -193,6 +193,7 @@ export function NetscriptMyrian(): InternalAPI { 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 { switch (container.type) { case DeviceType.ISocket: { + if (previousSize <= container.content.length) break; const cooldown = isocketSpeed(container.emissionLvl); container.cooldownUntil = Date.now() + cooldown; setTimeout(() => { @@ -210,16 +212,15 @@ export function NetscriptMyrian(): InternalAPI { } case DeviceType.OSocket: { - if (inventoryMatches(container.currentRequest, container.content)) { - const gain = - container.content.map((i) => vulnsMap[i]).reduce((a, b) => a + b, 0) * getTotalGlitchMult(); - myrian.vulns += gain; - myrian.totalVulns += gain; - container.content = []; - const request = getNextISocketRequest(myrian.glitches[Glitch.Encryption]); - container.currentRequest = request; - container.maxContent = request.length; - } + 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; + myrian.totalVulns += gain; + container.content = []; + const request = getNextISocketRequest(myrian.glitches[Glitch.Encryption]); + container.currentRequest = request; + container.maxContent = request.length; break; } } diff --git a/src/PersonObjects/Player/PlayerObject.ts b/src/PersonObjects/Player/PlayerObject.ts index 7a8bb5a3f..8dab48c30 100644 --- a/src/PersonObjects/Player/PlayerObject.ts +++ b/src/PersonObjects/Player/PlayerObject.ts @@ -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; diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts index 91e41177b..a74fc3184 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts @@ -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; } diff --git a/src/Prestige.ts b/src/Prestige.ts index fa88ac974..0ae792874 100644 --- a/src/Prestige.ts +++ b/src/Prestige.ts @@ -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(); diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index d490d713e..8d5e86a01 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -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 }, ]} /> diff --git a/src/SourceFile/SourceFiles.tsx b/src/SourceFile/SourceFiles.tsx index 0b2a9a86c..c8284c0e7 100644 --- a/src/SourceFile/SourceFiles.tsx +++ b/src/SourceFile/SourceFiles.tsx @@ -256,4 +256,20 @@ export function initSourceFiles() { ), ); + + SourceFiles.SourceFile19 = new SourceFile( + 19, + ( + <> + This Source-File grants the following benefits: +
+
+ Level 1: Reduce the effect of the Rust Glitch +
+ Level 2: Reduce the effect of the Magnetism Glitch +
+ Level 3: Reduce the effect of the Friction, Isolation, Virtualization, and Jamming Glitch + + ), + ); }