diff --git a/.gitignore b/.gitignore index 84671db69..7ffbc4168 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ Netburner.txt # editor files .vscode + +.idea/ diff --git a/doc/source/basicgameplay/factions.rst b/doc/source/basicgameplay/factions.rst index 430cab103..bab97651e 100644 --- a/doc/source/basicgameplay/factions.rst +++ b/doc/source/basicgameplay/factions.rst @@ -39,21 +39,23 @@ List of Factions and their Requirements .. _gameplay_factions:: -+---------------------+----------------+-----------------------------------------+-------------------------------+ -| Early Game | Faction Name | Requirements | Joining this Faction prevents | -| Factions | | | you from joining: | -+ +----------------+-----------------------------------------+-------------------------------+ -| | CyberSec | * Install a backdoor on the CSEC server | | -+ +----------------+-----------------------------------------+-------------------------------+ -| | Tian Di Hui | * $1m | | -| | | * Hacking Level 50 | | -| | | * Be in Chongqing, New Tokyo, or Ishima | | -+ +----------------+-----------------------------------------+-------------------------------+ -| | Netburners | * Hacking Level 80 | | -| | | * Total Hacknet Levels of 100 | | -| | | * Total Hacknet RAM of 8 | | -| | | * Total Hacknet Cores of 4 | | -+---------------------+----------------+-----------------------------------------+-------------------------------+ ++---------------------+--------------------+-----------------------------------------+-------------------------------+ +| Early Game | Faction Name | Requirements | Joining this Faction prevents | +| Factions | | | you from joining: | ++ +--------------------+-----------------------------------------+-------------------------------+ +| | CyberSec | * Install a backdoor on the CSEC server | | ++ +--------------------+-----------------------------------------+-------------------------------+ +| | Tian Di Hui | * $1m | | +| | | * Hacking Level 50 | | +| | | * Be in Chongqing, New Tokyo, or Ishima | | ++ +--------------------+-----------------------------------------+-------------------------------+ +| | Netburners | * Hacking Level 80 | | +| | | * Total Hacknet Levels of 100 | | +| | | * Total Hacknet RAM of 8 | | +| | | * Total Hacknet Cores of 4 | | ++ +--------------------+-----------------------------------------+-------------------------------+ +| | Shadows of Anarchy | * Successfully infiltrate a company | | ++---------------------+--------------------+-----------------------------------------+-------------------------------+ .. raw:: html diff --git a/jest.config.js b/jest.config.js index 22f371dcd..25c9858c2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -9,5 +9,6 @@ module.exports = { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/test/__mocks__/fileMock.js", "\\.(css|less)$": "/test/__mocks__/styleMock.js", + "\\!!raw-loader!.*$": "/test/__mocks__/rawLoader.js", }, }; diff --git a/src/Message/MessageHelpers.ts b/src/Message/MessageHelpers.ts index 82d0d6353..26764b72c 100644 --- a/src/Message/MessageHelpers.ts +++ b/src/Message/MessageHelpers.ts @@ -69,7 +69,7 @@ function checkForMessagesToSend(): void { const truthGazer = Messages[MessageFilenames.TruthGazer]; const redpill = Messages[MessageFilenames.RedPill]; - if (Player.hasAugmentation(AugmentationNames.TheRedPill)) { + if (Player.hasAugmentation(AugmentationNames.TheRedPill, true)) { //Get the world daemon required hacking level const worldDaemon = GetServer(SpecialServers.WorldDaemon); if (!(worldDaemon instanceof Server)) { diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 01578fd63..e5f51dd0f 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -55,6 +55,7 @@ import { FactionWorkType } from "../Work/data/FactionWorkType"; import { CompanyWork } from "../Work/CompanyWork"; import { canGetBonus, onExport } from "../ExportBonus"; import { saveObject } from "../SaveObject"; +import { calculateCrimeWorkStats } from "../Work/formulas/Crime"; export function NetscriptSingularity(): InternalAPI { const getAugmentation = function (ctx: NetscriptContext, name: string): Augmentation { @@ -1210,7 +1211,19 @@ export function NetscriptSingularity(): InternalAPI { throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: ${crimeRoughName}`); } - return Object.assign({}, crime); + const crimeStatsWithMultipliers = calculateCrimeWorkStats(crime); + + return Object.assign({}, crime, { + money: crimeStatsWithMultipliers.money, + reputation: crimeStatsWithMultipliers.reputation, + hacking_exp: crimeStatsWithMultipliers.hackExp, + strength_exp: crimeStatsWithMultipliers.strExp, + defense_exp: crimeStatsWithMultipliers.defExp, + dexterity_exp: crimeStatsWithMultipliers.dexExp, + agility_exp: crimeStatsWithMultipliers.agiExp, + charisma_exp: crimeStatsWithMultipliers.chaExp, + intelligence_exp: crimeStatsWithMultipliers.intExp, + }); }, getDarkwebPrograms: (ctx: NetscriptContext) => function (): string[] { diff --git a/src/NetscriptFunctions/Stanek.ts b/src/NetscriptFunctions/Stanek.ts index c2e936f1b..f0753b379 100644 --- a/src/NetscriptFunctions/Stanek.ts +++ b/src/NetscriptFunctions/Stanek.ts @@ -142,7 +142,7 @@ export function NetscriptStanek(): InternalAPI { //Return true iff the player is in CotMG and has the first Stanek aug installed return ( Factions[FactionNames.ChurchOfTheMachineGod].isMember && - player.hasAugmentation(AugmentationNames.StaneksGift1) + player.hasAugmentation(AugmentationNames.StaneksGift1, true) ); }, }; diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts index 9fc352893..fed24e61d 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts @@ -1462,7 +1462,7 @@ export function sourceFileLvl(this: IPlayer, n: number): number { export function focusPenalty(this: IPlayer): number { let focus = 1; - if (!this.hasAugmentation(AugmentationNames["NeuroreceptorManager"])) { + if (!this.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focus = this.focus ? 1 : CONSTANTS.BaseFocusBonus; } return focus; diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index ef9031473..3218576e6 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -159,6 +159,7 @@ export class Sleeve extends Person { this.exp.agility = 0; this.exp.charisma = 0; this.updateStatLevels(); + this.hp.current = this.hp.max; // Reset task-related stuff this.stopWork(p); @@ -440,6 +441,9 @@ export class Sleeve extends Person { case "Diplomacy": this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Diplomacy" })); return true; + case "Hyperbolic Regeneration Chamber": + this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Hyperbolic Regeneration Chamber" })); + return true; case "Infiltrate synthoids": this.startWork(p, new SleeveInfiltrateWork()); return true; diff --git a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx index d94f6888e..8df94de47 100644 --- a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx +++ b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx @@ -35,6 +35,7 @@ const bladeburnerSelectorOptions: string[] = [ "Field analysis", "Recruitment", "Diplomacy", + "Hyperbolic Regeneration Chamber", "Infiltrate synthoids", "Support main sleeve", "Take on contracts", @@ -285,6 +286,8 @@ function getABC(sleeve: Sleeve): [string, string, string] { return ["Perform Bladeburner Actions", "Diplomacy", "------"]; case "Recruitment": return ["Perform Bladeburner Actions", "Recruitment", "------"]; + case "Hyperbolic Regeneration Chamber": + return ["Perform Bladeburner Actions", "Hyperbolic Regeneration Chamber", "------"]; } } diff --git a/src/Prestige.ts b/src/Prestige.ts index aed8096e7..b526946fe 100755 --- a/src/Prestige.ts +++ b/src/Prestige.ts @@ -55,15 +55,15 @@ export function prestigeAugmentation(): void { AddToAllServers(homeComp); prestigeHomeComputer(Player, homeComp); - if (augmentationExists(AugmentationNames.Neurolink) && Player.hasAugmentation(AugmentationNames.Neurolink)) { + if (augmentationExists(AugmentationNames.Neurolink) && Player.hasAugmentation(AugmentationNames.Neurolink, true)) { homeComp.programs.push(Programs.FTPCrackProgram.name); homeComp.programs.push(Programs.RelaySMTPProgram.name); } - if (augmentationExists(AugmentationNames.CashRoot) && Player.hasAugmentation(AugmentationNames.CashRoot)) { + if (augmentationExists(AugmentationNames.CashRoot) && Player.hasAugmentation(AugmentationNames.CashRoot, true)) { Player.setMoney(1e6); homeComp.programs.push(Programs.BruteSSHProgram.name); } - if (augmentationExists(AugmentationNames.PCMatrix) && Player.hasAugmentation(AugmentationNames.PCMatrix)) { + if (augmentationExists(AugmentationNames.PCMatrix) && Player.hasAugmentation(AugmentationNames.PCMatrix, true)) { homeComp.programs.push(Programs.DeepscanV1.name); homeComp.programs.push(Programs.AutoLink.name); } @@ -151,7 +151,7 @@ export function prestigeAugmentation(): void { } // Red Pill - if (augmentationExists(AugmentationNames.TheRedPill) && Player.hasAugmentation(AugmentationNames.TheRedPill)) { + if (augmentationExists(AugmentationNames.TheRedPill) && Player.hasAugmentation(AugmentationNames.TheRedPill, true)) { const WorldDaemon = GetServer(SpecialServers.WorldDaemon); const DaedalusServer = GetServer(SpecialServers.DaedalusServer); if (WorldDaemon && DaedalusServer) { @@ -160,7 +160,10 @@ export function prestigeAugmentation(): void { } } - if (augmentationExists(AugmentationNames.StaneksGift1) && Player.hasAugmentation(AugmentationNames.StaneksGift1)) { + if ( + augmentationExists(AugmentationNames.StaneksGift1) && + Player.hasAugmentation(AugmentationNames.StaneksGift1, true) + ) { joinFaction(Factions[FactionNames.ChurchOfTheMachineGod]); } diff --git a/src/Work/CompanyWork.tsx b/src/Work/CompanyWork.tsx index dca07d85c..f601904eb 100644 --- a/src/Work/CompanyWork.tsx +++ b/src/Work/CompanyWork.tsx @@ -35,7 +35,7 @@ export class CompanyWork extends Work { getGainRates(player: IPlayer): WorkStats { let focusBonus = 1; - if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) { + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; } return scaleWorkStats(calculateCompanyWorkStats(player, player, this.getCompany()), focusBonus); diff --git a/src/Work/CreateProgramWork.ts b/src/Work/CreateProgramWork.ts index da463a752..be5cf30f3 100644 --- a/src/Work/CreateProgramWork.ts +++ b/src/Work/CreateProgramWork.ts @@ -58,7 +58,7 @@ export class CreateProgramWork extends Work { process(player: IPlayer, cycles: number): boolean { let focusBonus = 1; - if (!player.hasAugmentation(AugmentationNames["NeuroreceptorManager"])) { + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; } //Higher hacking skill will allow you to create programs faster diff --git a/src/Work/FactionWork.tsx b/src/Work/FactionWork.tsx index d25ab67a5..d1ad4e988 100644 --- a/src/Work/FactionWork.tsx +++ b/src/Work/FactionWork.tsx @@ -39,7 +39,7 @@ export class FactionWork extends Work { getReputationRate(player: IPlayer): number { let focusBonus = 1; - if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) { + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; } return calculateFactionRep(player, this.factionWorkType, this.getFaction().favor) * focusBonus; @@ -47,7 +47,7 @@ export class FactionWork extends Work { getExpRates(player: IPlayer): WorkStats { let focusBonus = 1; - if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) { + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; } const rate = calculateFactionExp(player, this.factionWorkType); diff --git a/src/Work/GraftingWork.tsx b/src/Work/GraftingWork.tsx index d9582d29e..c0279235d 100644 --- a/src/Work/GraftingWork.tsx +++ b/src/Work/GraftingWork.tsx @@ -37,7 +37,7 @@ export class GraftingWork extends Work { process(player: IPlayer, cycles: number): boolean { let focusBonus = 1; - if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager)) { + if (!player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = player.focus ? 1 : CONSTANTS.BaseFocusBonus; } @@ -52,7 +52,7 @@ export class GraftingWork extends Work { if (!cancelled) { applyAugmentation({ name: augName, level: 1 }); - if (!player.hasAugmentation(AugmentationNames.CongruityImplant)) { + if (!player.hasAugmentation(AugmentationNames.CongruityImplant, true)) { player.entropy += 1; player.applyEntropy(player.entropy); } @@ -62,7 +62,7 @@ export class GraftingWork extends Work { <> You've finished grafting {augName}.
The augmentation has been applied to your body{" "} - {player.hasAugmentation(AugmentationNames.CongruityImplant) ? "." : ", but you feel a bit off."} + {player.hasAugmentation(AugmentationNames.CongruityImplant, true) ? "." : ", but you feel a bit off."} , ); } diff --git a/src/ui/WorkInProgressRoot.tsx b/src/ui/WorkInProgressRoot.tsx index 8f5ba77ce..f99730478 100644 --- a/src/ui/WorkInProgressRoot.tsx +++ b/src/ui/WorkInProgressRoot.tsx @@ -119,6 +119,7 @@ function ExpRows(rate: WorkStats): React.ReactElement[] { ]; } +/* Because crime exp is given all at once at the end, we don't care about the cycles per second. */ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { return [ rate.hackExp > 0 ? ( @@ -126,7 +127,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Hacking Exp" color={Settings.theme.hack} data={{ - content: `${numeralWrapper.formatExp(rate.hackExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.hackExp)}`, }} /> ) : ( @@ -137,7 +138,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Strength Exp" color={Settings.theme.combat} data={{ - content: `${numeralWrapper.formatExp(rate.strExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.strExp)}`, }} /> ) : ( @@ -148,7 +149,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Defense Exp" color={Settings.theme.combat} data={{ - content: `${numeralWrapper.formatExp(rate.defExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.defExp)}`, }} /> ) : ( @@ -159,7 +160,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Dexterity Exp" color={Settings.theme.combat} data={{ - content: `${numeralWrapper.formatExp(rate.dexExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.dexExp)}`, }} /> ) : ( @@ -170,7 +171,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Agility Exp" color={Settings.theme.combat} data={{ - content: `${numeralWrapper.formatExp(rate.agiExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.agiExp)}`, }} /> ) : ( @@ -181,7 +182,7 @@ function CrimeExpRows(rate: WorkStats): React.ReactElement[] { name="Charisma Exp" color={Settings.theme.cha} data={{ - content: `${numeralWrapper.formatExp(rate.chaExp * CYCLES_PER_SEC)}`, + content: `${numeralWrapper.formatExp(rate.chaExp)}`, }} /> ) : ( diff --git a/test/__mocks__/rawLoader.js b/test/__mocks__/rawLoader.js new file mode 100644 index 000000000..e69de29bb