Merge branch 'dev' of github.com:danielyxie/bitburner into feature/grafting

This commit is contained in:
nickofolas 2022-03-19 10:27:49 -05:00
commit c5d86fba4d
55 changed files with 1518 additions and 1262 deletions

@ -22,6 +22,8 @@ import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router"; import { Page } from "../ui/Router";
import { IMap } from "../types"; import { IMap } from "../types";
import * as data from "./AchievementData.json"; import * as data from "./AchievementData.json";
import { FactionNames } from "../Faction/data/FactionNames";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise... // Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements; const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
@ -56,7 +58,7 @@ function bitNodeFinishedState(): boolean {
const wd = GetServer(SpecialServers.WorldDaemon); const wd = GetServer(SpecialServers.WorldDaemon);
if (!(wd instanceof Server)) return false; if (!(wd instanceof Server)) return false;
if (wd.backdoorInstalled) return true; if (wd.backdoorInstalled) return true;
return Player.bladeburner !== null && Player.bladeburner.blackops.hasOwnProperty("Operation Daedalus"); return Player.bladeburner !== null && Player.bladeburner.blackops.hasOwnProperty(BlackOperationNames.OperationDaedalus);
} }
function hasAccessToSF(player: PlayerObject, bn: number): boolean { function hasAccessToSF(player: PlayerObject, bn: number): boolean {
@ -82,40 +84,40 @@ function sfAchievement(): Achievement[] {
} }
export const achievements: IMap<Achievement> = { export const achievements: IMap<Achievement> = {
CYBERSEC: { [FactionNames.CyberSec.toUpperCase()]: {
...achievementData["CYBERSEC"], ...achievementData[FactionNames.CyberSec.toUpperCase()],
Icon: "CSEC", Icon: "CSEC",
Condition: () => Player.factions.includes("CyberSec"), Condition: () => Player.factions.includes(FactionNames.CyberSec),
}, },
NITESEC: { [FactionNames.NiteSec.toUpperCase()]: {
...achievementData["NITESEC"], ...achievementData[FactionNames.NiteSec.toUpperCase()],
Icon: "NiteSec", Icon: FactionNames.NiteSec,
Condition: () => Player.factions.includes("NiteSec"), Condition: () => Player.factions.includes(FactionNames.NiteSec),
}, },
THE_BLACK_HAND: { THE_BLACK_HAND: {
...achievementData["THE_BLACK_HAND"], ...achievementData["THE_BLACK_HAND"],
Icon: "TBH", Icon: "TBH",
Condition: () => Player.factions.includes("The Black Hand"), Condition: () => Player.factions.includes(FactionNames.TheBlackHand),
}, },
BITRUNNERS: { [FactionNames.BitRunners.toUpperCase()]: {
...achievementData["BITRUNNERS"], ...achievementData[FactionNames.BitRunners.toUpperCase()],
Icon: "bitrunners", Icon: FactionNames.BitRunners.toLowerCase(),
Condition: () => Player.factions.includes("BitRunners"), Condition: () => Player.factions.includes(FactionNames.BitRunners),
}, },
DAEDALUS: { [FactionNames.Daedalus.toUpperCase()]: {
...achievementData["DAEDALUS"], ...achievementData[FactionNames.Daedalus.toUpperCase()],
Icon: "daedalus", Icon: FactionNames.Daedalus.toLowerCase(),
Condition: () => Player.factions.includes("Daedalus"), Condition: () => Player.factions.includes(FactionNames.Daedalus),
}, },
THE_COVENANT: { THE_COVENANT: {
...achievementData["THE_COVENANT"], ...achievementData["THE_COVENANT"],
Icon: "thecovenant", Icon: FactionNames.TheCovenant.toLowerCase(),
Condition: () => Player.factions.includes("The Covenant"), Condition: () => Player.factions.includes(FactionNames.TheCovenant),
}, },
ILLUMINATI: { [FactionNames.Illuminati.toUpperCase()]: {
...achievementData["ILLUMINATI"], ...achievementData[FactionNames.Illuminati.toUpperCase()],
Icon: "illuminati", Icon: FactionNames.Illuminati.toLowerCase(),
Condition: () => Player.factions.includes("Illuminati"), Condition: () => Player.factions.includes(FactionNames.Illuminati),
}, },
"BRUTESSH.EXE": { "BRUTESSH.EXE": {
...achievementData["BRUTESSH.EXE"], ...achievementData["BRUTESSH.EXE"],
@ -745,31 +747,31 @@ export const achievements: IMap<Achievement> = {
}; };
// Steam has a limit of 100 achievement. So these were planned but commented for now. // Steam has a limit of 100 achievement. So these were planned but commented for now.
// { ID: "ECORP", Condition: () => Player.factions.includes("ECorp") }, // { ID: FactionNames.ECorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.ECorp) },
// { ID: "MEGACORP", Condition: () => Player.factions.includes("MegaCorp") }, // { ID: FactionNames.MegaCorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.MegaCorp) },
// { ID: "BACHMAN_&_ASSOCIATES", Condition: () => Player.factions.includes("Bachman & Associates") }, // { ID: "BACHMAN_&_ASSOCIATES", Condition: () => Player.factions.includes(FactionNames.BachmanAssociates) },
// { ID: "BLADE_INDUSTRIES", Condition: () => Player.factions.includes("Blade Industries") }, // { ID: "BLADE_INDUSTRIES", Condition: () => Player.factions.includes(FactionNames.BladeIndustries) },
// { ID: "NWO", Condition: () => Player.factions.includes("NWO") }, // { ID: FactionNames.NWO.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.NWO) },
// { ID: "CLARKE_INCORPORATED", Condition: () => Player.factions.includes("Clarke Incorporated") }, // { ID: "CLARKE_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.ClarkeIncorporated) },
// { ID: "OMNITEK_INCORPORATED", Condition: () => Player.factions.includes("OmniTek Incorporated") }, // { ID: "OMNITEK_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.OmniTekIncorporated) },
// { ID: "FOUR_SIGMA", Condition: () => Player.factions.includes("Four Sigma") }, // { ID: "FOUR_SIGMA", Condition: () => Player.factions.includes(FactionNames.FourSigma) },
// { ID: "KUAIGONG_INTERNATIONAL", Condition: () => Player.factions.includes("KuaiGong International") }, // { ID: "KUAIGONG_INTERNATIONAL", Condition: () => Player.factions.includes(FactionNames.KuaiGongInternational) },
// { ID: "FULCRUM_SECRET_TECHNOLOGIES", Condition: () => Player.factions.includes("Fulcrum Secret Technologies") }, // { ID: "FULCRUM_SECRET_TECHNOLOGIES", Condition: () => Player.factions.includes(FactionNames.FulcrumSecretTechnologies) },
// { ID: "AEVUM", Condition: () => Player.factions.includes("Aevum") }, // { ID: FactionNames.Aevum.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Aevum) },
// { ID: "CHONGQING", Condition: () => Player.factions.includes("Chongqing") }, // { ID: FactionNames.Chongqing.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Chongqing) },
// { ID: "ISHIMA", Condition: () => Player.factions.includes("Ishima") }, // { ID: FactionNames.Ishima.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Ishima) },
// { ID: "NEW_TOKYO", Condition: () => Player.factions.includes("New Tokyo") }, // { ID: "NEW_TOKYO", Condition: () => Player.factions.includes(FactionNames.NewTokyo) },
// { ID: "SECTOR-12", Condition: () => Player.factions.includes("Sector-12") }, // { ID: "SECTOR-12", Condition: () => Player.factions.includes(FactionNames.Sector12) },
// { ID: "VOLHAVEN", Condition: () => Player.factions.includes("Volhaven") }, // { ID: FactionNames.Volhaven.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Volhaven) },
// { ID: "SPEAKERS_FOR_THE_DEAD", Condition: () => Player.factions.includes("Speakers for the Dead") }, // { ID: "SPEAKERS_FOR_THE_DEAD", Condition: () => Player.factions.includes(FactionNames.SpeakersForTheDead) },
// { ID: "THE_DARK_ARMY", Condition: () => Player.factions.includes("The Dark Army") }, // { ID: "THE_DARK_ARMY", Condition: () => Player.factions.includes(FactionNames.TheDarkArmy) },
// { ID: "THE_SYNDICATE", Condition: () => Player.factions.includes("The Syndicate") }, // { ID: "THE_SYNDICATE", Condition: () => Player.factions.includes(FactionNames.TheSyndicate) },
// { ID: "SILHOUETTE", Condition: () => Player.factions.includes("Silhouette") }, // { ID: FactionNames.Silhouette.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Silhouette) },
// { ID: "TETRADS", Condition: () => Player.factions.includes("Tetrads") }, // { ID: FactionNames.Tetrads.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Tetrads) },
// { ID: "SLUM_SNAKES", Condition: () => Player.factions.includes("Slum Snakes") }, // { ID: "SLUM_SNAKES", Condition: () => Player.factions.includes(FactionNames.SlumSnakes) },
// { ID: "NETBURNERS", Condition: () => Player.factions.includes("Netburners") }, // { ID: FactionNames.Netburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Netburners) },
// { ID: "TIAN_DI_HUI", Condition: () => Player.factions.includes("Tian Di Hui") }, // { ID: "TIAN_DI_HUI", Condition: () => Player.factions.includes(FactionNames.TianDiHui) },
// { ID: "BLADEBURNERS", Condition: () => Player.factions.includes("Bladeburners") }, // { ID: FactionNames.Bladeburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Bladeburners) },
// { ID: "DEEPSCANV1.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV1.name) }, // { ID: "DEEPSCANV1.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV1.name) },
// { ID: "DEEPSCANV2.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV2.name) }, // { ID: "DEEPSCANV2.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV2.name) },
// { // {

File diff suppressed because it is too large Load Diff

@ -2,6 +2,8 @@ import React from "react";
import { BitNodeMultipliers } from "./BitNodeMultipliers"; import { BitNodeMultipliers } from "./BitNodeMultipliers";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { IMap } from "../types"; import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames";
import { CityName } from "../Locations/data/CityNames";
class BitNode { class BitNode {
// A short description, or tagline, about the BitNode // A short description, or tagline, about the BitNode
@ -80,8 +82,7 @@ BitNodes["BitNode2"] = new BitNode(
<br /> <br />
The amount of money gained from crimes and Infiltration is tripled The amount of money gained from crimes and Infiltration is tripled
<br /> <br />
Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, NiteSec, The Black Certain Factions ({FactionNames.SlumSnakes}, {FactionNames.Tetrads}, {FactionNames.TheSyndicate}, {FactionNames.TheDarkArmy}, {FactionNames.SpeakersForTheDead}, {FactionNames.NiteSec}, {FactionNames.TheBlackHand}) give the player the ability to form and manage their own gangs. These gangs will earn the player money and
Hand) give the player the ability to form and manage their own gangs. These gangs will earn the player money and
reputation with the corresponding Faction reputation with the corresponding Faction
<br /> <br />
Every Augmentation in the game will be available through the Factions listed above Every Augmentation in the game will be available through the Factions listed above
@ -220,18 +221,18 @@ BitNodes["BitNode5"] = new BitNode(
BitNodes["BitNode6"] = new BitNode( BitNodes["BitNode6"] = new BitNode(
6, 6,
1, 1,
"Bladeburners", FactionNames.Bladeburners,
"Like Tears in Rain", "Like Tears in Rain",
( (
<> <>
In the middle of the 21st century, OmniTek Incorporated began designing and manufacturing advanced synthetic In the middle of the 21st century, {FactionNames.OmniTekIncorporated} began designing and manufacturing advanced synthetic
androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth generation of androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth generation of
their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was the first their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was the first
sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more intelligent than sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more intelligent than
the humans that had created them. the humans that had created them.
<br /> <br />
<br /> <br />
In this BitNode you will be able to access the Bladeburner Division at the NSA, which provides a new mechanic for In this BitNode you will be able to access the {FactionNames.Bladeburners} Division at the NSA, which provides a new mechanic for
progression. Furthermore: progression. Furthermore:
<br /> <br />
<br /> <br />
@ -249,7 +250,7 @@ BitNodes["BitNode6"] = new BitNode(
<br /> <br />
<br /> <br />
Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade its Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File allows you to access the NSA's Bladeburner Division in other level up to a maximum of 3. This Source-File allows you to access the NSA's {FactionNames.Bladeburners} Division in other
BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your combat BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your combat
stats by: stats by:
<br /> <br />
@ -265,23 +266,23 @@ BitNodes["BitNode6"] = new BitNode(
BitNodes["BitNode7"] = new BitNode( BitNodes["BitNode7"] = new BitNode(
7, 7,
2, 2,
"Bladeburners 2079", `${FactionNames.Bladeburners} 2079`,
"More human than humans", "More human than humans",
( (
<> <>
In the middle of the 21st century, you were doing cutting-edge work at OmniTek Incorporated as part of the AI In the middle of the 21st century, you were doing cutting-edge work at {FactionNames.OmniTekIncorporated} as part of the AI
design team for advanced synthetic androids, or Synthoids for short. You helped achieve a major technological design team for advanced synthetic androids, or Synthoids for short. You helped achieve a major technological
breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing a breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing a
hyperintelligent AI. Many argue that this was the first sentient AI ever created. This resulted in Synthoid models hyperintelligent AI. Many argue that this was the first sentient AI ever created. This resulted in Synthoid models
that were stronger, faster, and more intelligent than the humans that had created them. that were stronger, faster, and more intelligent than the humans that had created them.
<br /> <br />
<br /> <br />
In this BitNode you will be able to access the Bladeburner API, which allows you to access Bladeburner In this BitNode you will be able to access the {FactionNames.Bladeburners} API, which allows you to access {FactionNames.Bladeburners}
functionality through Netscript. Furthermore: <br /> functionality through Netscript. Furthermore: <br />
<br /> <br />
The rank you gain from Bladeburner contracts/operations is reduced by 40% The rank you gain from {FactionNames.Bladeburners} contracts/operations is reduced by 40%
<br /> <br />
Bladeburner skills cost twice as many skill points {FactionNames.Bladeburners} skills cost twice as many skill points
<br /> <br />
Augmentations are 3x more expensive Augmentations are 3x more expensive
<br /> <br />
@ -299,8 +300,8 @@ BitNodes["BitNode7"] = new BitNode(
<br /> <br />
<br /> <br />
Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade its Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File allows you to access the Bladeburner Netscript API in other BitNodes. level up to a maximum of 3. This Source-File allows you to access the {FactionNames.Bladeburners} Netscript API in other BitNodes.
In addition, this Source-File will increase all of your Bladeburner multipliers by: In addition, this Source-File will increase all of your {FactionNames.Bladeburners} multipliers by:
<br /> <br />
<br /> <br />
Level 1: 8% Level 1: 8%
@ -363,9 +364,9 @@ BitNodes["BitNode9"] = new BitNode(
"Hacknet Unleashed", "Hacknet Unleashed",
( (
<> <>
When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly became the OS of choice for When {FactionNames.FulcrumSecretTechnologies} released their open-source Linux distro Chapeau, it quickly became the OS of choice for
the underground hacking community. Chapeau became especially notorious for powering the Hacknet, a global, the underground hacking community. Chapeau became especially notorious for powering the Hacknet, a global,
decentralized network used for nefarious purposes. Fulcrum quickly abandoned the project and dissociated decentralized network used for nefarious purposes. {FactionNames.FulcrumSecretTechnologies} quickly abandoned the project and dissociated
themselves from it. themselves from it.
<br /> <br />
<br /> <br />
@ -537,12 +538,12 @@ BitNodes["BitNode13"] = new BitNode(
"1 step back, 2 steps forward", "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 With the invention of Augmentations in the 2040s a religious group known as the {FactionNames.ChurchOfTheMachineGod} has
rallied far more support than anyone would have hoped. rallied far more support than anyone would have hoped.
<br /> <br />
<br /> <br />
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
other. Find her in Chongqing and gain her trust. other. Find her in {CityName.Chongqing} and gain her trust.
<br /> <br />
<br /> <br />
In this BitNode: In this BitNode:
@ -554,7 +555,7 @@ BitNodes["BitNode13"] = new BitNode(
<br /> <br />
<br /> <br />
Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade its 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. level up to a maximum of 3. This Source-File lets the {FactionNames.ChurchOfTheMachineGod} appear in other BitNodes.
<br /> <br />
<br /> <br />
Each level of this Source-File increases the size of Stanek's Gift. Each level of this Source-File increases the size of Stanek's Gift.

@ -1,11 +1,12 @@
import { BlackOperation } from "./BlackOperation"; import { BlackOperation } from "./BlackOperation";
import { IMap } from "../types"; import { IMap } from "../types";
import { BlackOperationNames } from "./data/BlackOperationNames";
export const BlackOperations: IMap<BlackOperation> = {}; export const BlackOperations: IMap<BlackOperation> = {};
(function () { (function () {
BlackOperations["Operation Typhoon"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationTyphoon] = new BlackOperation({
name: "Operation Typhoon", name: BlackOperationNames.OperationTyphoon,
baseDifficulty: 2000, baseDifficulty: 2000,
reqdRank: 2.5e3, reqdRank: 2.5e3,
rankGain: 50, rankGain: 50,
@ -31,8 +32,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Zero"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationZero] = new BlackOperation({
name: "Operation Zero", name: BlackOperationNames.OperationZero,
baseDifficulty: 2500, baseDifficulty: 2500,
reqdRank: 5e3, reqdRank: 5e3,
rankGain: 60, rankGain: 60,
@ -58,8 +59,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isStealth: true, isStealth: true,
}); });
BlackOperations["Operation X"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationX] = new BlackOperation({
name: "Operation X", name: BlackOperationNames.OperationX,
baseDifficulty: 3000, baseDifficulty: 3000,
reqdRank: 7.5e3, reqdRank: 7.5e3,
rankGain: 75, rankGain: 75,
@ -85,8 +86,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Titan"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationTitan] = new BlackOperation({
name: "Operation Titan", name: BlackOperationNames.OperationTitan,
baseDifficulty: 4000, baseDifficulty: 4000,
reqdRank: 10e3, reqdRank: 10e3,
rankGain: 100, rankGain: 100,
@ -112,8 +113,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Ares"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationAres] = new BlackOperation({
name: "Operation Ares", name: BlackOperationNames.OperationAres,
baseDifficulty: 5000, baseDifficulty: 5000,
reqdRank: 12.5e3, reqdRank: 12.5e3,
rankGain: 125, rankGain: 125,
@ -139,8 +140,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Archangel"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationArchangel] = new BlackOperation({
name: "Operation Archangel", name: BlackOperationNames.OperationArchangel,
baseDifficulty: 7500, baseDifficulty: 7500,
reqdRank: 15e3, reqdRank: 15e3,
rankGain: 200, rankGain: 200,
@ -166,8 +167,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Juggernaut"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationJuggernaut] = new BlackOperation({
name: "Operation Juggernaut", name: BlackOperationNames.OperationJuggernaut,
baseDifficulty: 10e3, baseDifficulty: 10e3,
reqdRank: 20e3, reqdRank: 20e3,
rankGain: 300, rankGain: 300,
@ -193,8 +194,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Red Dragon"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationRedDragon] = new BlackOperation({
name: "Operation Red Dragon", name: BlackOperationNames.OperationRedDragon,
baseDifficulty: 12.5e3, baseDifficulty: 12.5e3,
reqdRank: 25e3, reqdRank: 25e3,
rankGain: 500, rankGain: 500,
@ -220,8 +221,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation K"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationK] = new BlackOperation({
name: "Operation K", name: BlackOperationNames.OperationK,
baseDifficulty: 15e3, baseDifficulty: 15e3,
reqdRank: 30e3, reqdRank: 30e3,
rankGain: 750, rankGain: 750,
@ -247,8 +248,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Deckard"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationDeckard] = new BlackOperation({
name: "Operation Deckard", name: BlackOperationNames.OperationDeckard,
baseDifficulty: 20e3, baseDifficulty: 20e3,
reqdRank: 40e3, reqdRank: 40e3,
rankGain: 1e3, rankGain: 1e3,
@ -274,8 +275,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Tyrell"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationTyrell] = new BlackOperation({
name: "Operation Tyrell", name: BlackOperationNames.OperationTyrell,
baseDifficulty: 25e3, baseDifficulty: 25e3,
reqdRank: 50e3, reqdRank: 50e3,
rankGain: 1.5e3, rankGain: 1.5e3,
@ -301,8 +302,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Wallace"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationWallace] = new BlackOperation({
name: "Operation Wallace", name: BlackOperationNames.OperationWallace,
baseDifficulty: 30e3, baseDifficulty: 30e3,
reqdRank: 75e3, reqdRank: 75e3,
rankGain: 2e3, rankGain: 2e3,
@ -328,8 +329,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Shoulder of Orion"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationShoulderOfOrion] = new BlackOperation({
name: "Operation Shoulder of Orion", name: BlackOperationNames.OperationShoulderOfOrion,
baseDifficulty: 35e3, baseDifficulty: 35e3,
reqdRank: 100e3, reqdRank: 100e3,
rankGain: 2.5e3, rankGain: 2.5e3,
@ -355,8 +356,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isStealth: true, isStealth: true,
}); });
BlackOperations["Operation Hyron"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationHyron] = new BlackOperation({
name: "Operation Hyron", name: BlackOperationNames.OperationHyron,
baseDifficulty: 40e3, baseDifficulty: 40e3,
reqdRank: 125e3, reqdRank: 125e3,
rankGain: 3e3, rankGain: 3e3,
@ -382,8 +383,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Morpheus"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationMorpheus] = new BlackOperation({
name: "Operation Morpheus", name: BlackOperationNames.OperationMorpheus,
baseDifficulty: 45e3, baseDifficulty: 45e3,
reqdRank: 150e3, reqdRank: 150e3,
rankGain: 4e3, rankGain: 4e3,
@ -409,8 +410,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isStealth: true, isStealth: true,
}); });
BlackOperations["Operation Ion Storm"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationIonStorm] = new BlackOperation({
name: "Operation Ion Storm", name: BlackOperationNames.OperationIonStorm,
baseDifficulty: 50e3, baseDifficulty: 50e3,
reqdRank: 175e3, reqdRank: 175e3,
rankGain: 5e3, rankGain: 5e3,
@ -436,8 +437,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Annihilus"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationAnnihilus] = new BlackOperation({
name: "Operation Annihilus", name: BlackOperationNames.OperationAnnihilus,
baseDifficulty: 55e3, baseDifficulty: 55e3,
reqdRank: 200e3, reqdRank: 200e3,
rankGain: 7.5e3, rankGain: 7.5e3,
@ -463,8 +464,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Ultron"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationUltron] = new BlackOperation({
name: "Operation Ultron", name: BlackOperationNames.OperationUltron,
baseDifficulty: 60e3, baseDifficulty: 60e3,
reqdRank: 250e3, reqdRank: 250e3,
rankGain: 10e3, rankGain: 10e3,
@ -490,8 +491,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
}, },
isKill: true, isKill: true,
}); });
BlackOperations["Operation Centurion"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationCenturion] = new BlackOperation({
name: "Operation Centurion", name: BlackOperationNames.OperationCenturion,
baseDifficulty: 70e3, baseDifficulty: 70e3,
reqdRank: 300e3, reqdRank: 300e3,
rankGain: 15e3, rankGain: 15e3,
@ -516,8 +517,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
int: 0.75, int: 0.75,
}, },
}); });
BlackOperations["Operation Vindictus"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationVindictus] = new BlackOperation({
name: "Operation Vindictus", name: BlackOperationNames.OperationVindictus,
baseDifficulty: 75e3, baseDifficulty: 75e3,
reqdRank: 350e3, reqdRank: 350e3,
rankGain: 20e3, rankGain: 20e3,
@ -542,8 +543,8 @@ export const BlackOperations: IMap<BlackOperation> = {};
int: 0.75, int: 0.75,
}, },
}); });
BlackOperations["Operation Daedalus"] = new BlackOperation({ BlackOperations[BlackOperationNames.OperationDaedalus] = new BlackOperation({
name: "Operation Daedalus", name: BlackOperationNames.OperationDaedalus,
baseDifficulty: 80e3, baseDifficulty: 80e3,
reqdRank: 400e3, reqdRank: 400e3,
rankGain: 40e3, rankGain: 40e3,

@ -33,6 +33,8 @@ import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
import { getTimestamp } from "../utils/helpers/getTimestamp"; import { getTimestamp } from "../utils/helpers/getTimestamp";
import { joinFaction } from "../Faction/FactionHelpers"; import { joinFaction } from "../Faction/FactionHelpers";
import { WorkerScript } from "../Netscript/WorkerScript"; import { WorkerScript } from "../Netscript/WorkerScript";
import { FactionNames } from "../Faction/data/FactionNames";
import { BlackOperationNames } from "./data/BlackOperationNames";
interface BlackOpsAttempt { interface BlackOpsAttempt {
error?: string; error?: string;
@ -229,7 +231,6 @@ export class Bladeburner implements IBladeburner {
break; break;
default: default:
throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type); throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
break;
} }
} }
@ -291,7 +292,7 @@ export class Bladeburner implements IBladeburner {
prestige(): void { prestige(): void {
this.resetAction(); this.resetAction();
const bladeburnerFac = Factions["Bladeburners"]; const bladeburnerFac = Factions[FactionNames.Bladeburners];
if (this.rank >= BladeburnerConstants.RankNeededForFaction) { if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac); joinFaction(bladeburnerFac);
} }
@ -320,7 +321,6 @@ export class Bladeburner implements IBladeburner {
} else { } else {
return null; return null;
} }
break;
case "operation": case "operation":
case "operations": case "operations":
case "op": case "op":
@ -332,7 +332,6 @@ export class Bladeburner implements IBladeburner {
} else { } else {
return null; return null;
} }
break;
case "blackoperation": case "blackoperation":
case "black operation": case "black operation":
case "black operations": case "black operations":
@ -347,7 +346,6 @@ export class Bladeburner implements IBladeburner {
} else { } else {
return null; return null;
} }
break;
case "general": case "general":
case "general action": case "general action":
case "gen": case "gen":
@ -672,15 +670,15 @@ export class Bladeburner implements IBladeburner {
this.postToConsole("Automation: " + (this.automateEnabled ? "enabled" : "disabled")); this.postToConsole("Automation: " + (this.automateEnabled ? "enabled" : "disabled"));
this.postToConsole( this.postToConsole(
"When your stamina drops to " + "When your stamina drops to " +
formatNumber(this.automateThreshLow, 0) + formatNumber(this.automateThreshLow, 0) +
", you will automatically switch to " + ", you will automatically switch to " +
this.automateActionLow.name + this.automateActionLow.name +
". When your stamina recovers to " + ". When your stamina recovers to " +
formatNumber(this.automateThreshHigh, 0) + formatNumber(this.automateThreshHigh, 0) +
", you will automatically " + ", you will automatically " +
"switch to " + "switch to " +
this.automateActionHigh.name + this.automateActionHigh.name +
".", ".",
); );
} else if (flag.toLowerCase().includes("en")) { } else if (flag.toLowerCase().includes("en")) {
if ( if (
@ -975,8 +973,8 @@ export class Bladeburner implements IBladeburner {
if (this.logging.events) { if (this.logging.events) {
this.log( this.log(
"Intelligence indicates that a large number of Synthoids migrated from " + "Intelligence indicates that a large number of Synthoids migrated from " +
sourceCityName + sourceCityName +
" to some other city", " to some other city",
); );
} }
} else if (chance <= 0.7) { } else if (chance <= 0.7) {
@ -1291,10 +1289,10 @@ export class Bladeburner implements IBladeburner {
} else if (!isOperation && this.logging.contracts) { } else if (!isOperation && this.logging.contracts) {
this.log( this.log(
action.name + action.name +
" contract successfully completed! Gained " + " contract successfully completed! Gained " +
formatNumber(gain, 3) + formatNumber(gain, 3) +
" rank and " + " rank and " +
numeralWrapper.formatMoney(moneyGain), numeralWrapper.formatMoney(moneyGain),
); );
} }
} }
@ -1375,7 +1373,7 @@ export class Bladeburner implements IBladeburner {
teamLossMax = Math.ceil(teamCount / 2); teamLossMax = Math.ceil(teamCount / 2);
// Operation Daedalus // Operation Daedalus
if (action.name === "Operation Daedalus") { if (action.name === BlackOperationNames.OperationDaedalus) {
this.resetAction(); this.resetAction();
return router.toBitVerse(false, false); return router.toBitVerse(false, false);
} }
@ -1405,11 +1403,11 @@ export class Bladeburner implements IBladeburner {
if (this.logging.blackops) { if (this.logging.blackops) {
this.log( this.log(
action.name + action.name +
" failed! Lost " + " failed! Lost " +
formatNumber(rankLoss, 1) + formatNumber(rankLoss, 1) +
" rank and took " + " rank and took " +
formatNumber(damage, 0) + formatNumber(damage, 0) +
" damage", " damage",
); );
} }
} }
@ -1445,16 +1443,16 @@ export class Bladeburner implements IBladeburner {
if (this.logging.general) { if (this.logging.general) {
this.log( this.log(
"Training completed. Gained: " + "Training completed. Gained: " +
formatNumber(strExpGain, 1) + formatNumber(strExpGain, 1) +
" str exp, " + " str exp, " +
formatNumber(defExpGain, 1) + formatNumber(defExpGain, 1) +
" def exp, " + " def exp, " +
formatNumber(dexExpGain, 1) + formatNumber(dexExpGain, 1) +
" dex exp, " + " dex exp, " +
formatNumber(agiExpGain, 1) + formatNumber(agiExpGain, 1) +
" agi exp, " + " agi exp, " +
formatNumber(staminaGain, 3) + formatNumber(staminaGain, 3) +
" max stamina", " max stamina",
); );
} }
this.startAction(player, this.action); // Repeat action this.startAction(player, this.action); // Repeat action
@ -1481,10 +1479,10 @@ export class Bladeburner implements IBladeburner {
if (this.logging.general) { if (this.logging.general) {
this.log( this.log(
"Field analysis completed. Gained 0.1 rank, " + "Field analysis completed. Gained 0.1 rank, " +
formatNumber(hackingExpGain, 1) + formatNumber(hackingExpGain, 1) +
" hacking exp, and " + " hacking exp, and " +
formatNumber(charismaExpGain, 1) + formatNumber(charismaExpGain, 1) +
" charisma exp", " charisma exp",
); );
} }
this.startAction(player, this.action); // Repeat action this.startAction(player, this.action); // Repeat action
@ -1531,8 +1529,7 @@ export class Bladeburner implements IBladeburner {
this.startAction(player, this.action); this.startAction(player, this.action);
if (this.logging.general) { if (this.logging.general) {
this.log( this.log(
`Rested in Hyperbolic Regeneration Chamber. Restored ${ `Rested in Hyperbolic Regeneration Chamber. Restored ${BladeburnerConstants.HrcHpGain
BladeburnerConstants.HrcHpGain
} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`, } HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`,
); );
} }
@ -1577,11 +1574,11 @@ export class Bladeburner implements IBladeburner {
} }
this.maxRank = Math.max(this.rank, this.maxRank); this.maxRank = Math.max(this.rank, this.maxRank);
const bladeburnersFactionName = "Bladeburners"; const bladeburnersFactionName = FactionNames.Bladeburners;
if (factionExists(bladeburnersFactionName)) { if (factionExists(bladeburnersFactionName)) {
const bladeburnerFac = Factions[bladeburnersFactionName]; const bladeburnerFac = Factions[bladeburnersFactionName];
if (!(bladeburnerFac instanceof Faction)) { if (!(bladeburnerFac instanceof Faction)) {
throw new Error("Could not properly get Bladeburner Faction object in Bladeburner UI Overview Faction button"); throw new Error(`Could not properly get ${FactionNames.Bladeburners} Faction object in ${FactionNames.Bladeburners} UI Overview Faction button`);
} }
if (bladeburnerFac.isMember) { if (bladeburnerFac.isMember) {
const favorBonus = 1 + bladeburnerFac.favor / 100; const favorBonus = 1 + bladeburnerFac.favor / 100;
@ -1918,7 +1915,7 @@ export class Bladeburner implements IBladeburner {
if (!router.isInitialized) return; if (!router.isInitialized) return;
// Edge case condition...if Operation Daedalus is complete trigger the BitNode // Edge case condition...if Operation Daedalus is complete trigger the BitNode
if (router.page() !== Page.BitVerse && this.blackops.hasOwnProperty("Operation Daedalus")) { if (router.page() !== Page.BitVerse && this.blackops.hasOwnProperty(BlackOperationNames.OperationDaedalus)) {
return router.toBitVerse(false, false); return router.toBitVerse(false, false);
} }
@ -2340,12 +2337,12 @@ export class Bladeburner implements IBladeburner {
} }
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean { joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean {
const bladeburnerFac = Factions["Bladeburners"]; const bladeburnerFac = Factions[FactionNames.Bladeburners];
if (bladeburnerFac.isMember) { if (bladeburnerFac.isMember) {
return true; return true;
} else if (this.rank >= BladeburnerConstants.RankNeededForFaction) { } else if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac); joinFaction(bladeburnerFac);
workerScript.log("bladeburner.joinBladeburnerFaction", () => "Joined Bladeburners faction."); workerScript.log("bladeburner.joinBladeburnerFaction", () => `Joined ${FactionNames.Bladeburners} faction.`);
return true; return true;
} else { } else {
workerScript.log( workerScript.log(

@ -0,0 +1,23 @@
export enum BlackOperationNames {
OperationTyphoon = "Operation Typhoon",
OperationZero = "Operation Zero",
OperationX = "Operation X",
OperationTitan = "Operation Titan",
OperationAres = "Operation Ares",
OperationArchangel = "Operation Archangel",
OperationJuggernaut = "Operation Juggernaut",
OperationRedDragon = "Operation Red Dragon",
OperationK = "Operation K",
OperationDeckard = "Operation Deckard",
OperationTyrell = "Operation Tyrell",
OperationWallace = "Operation Wallace",
OperationShoulderOfOrion = "Operation Shoulder of Orion",
OperationHyron = "Operation Hyron",
OperationMorpheus = "Operation Morpheus",
OperationIonStorm = "Operation Ion Storm",
OperationAnnihilus = "Operation Annihilus",
OperationUltron = "Operation Ultron",
OperationCenturion = "Operation Centurion",
OperationVindictus = "Operation Vindictus",
OperationDaedalus = "Operation Daedalus",
}

@ -1,4 +1,7 @@
import React from "react"; import React from "react";
import { FactionNames } from "../../Faction/data/FactionNames";
import { CityName } from "../../Locations/data/CityNames";
import { BlackOperationNames } from "./BlackOperationNames";
interface IBlackOp { interface IBlackOp {
desc: JSX.Element; desc: JSX.Element;
@ -7,34 +10,34 @@ interface IBlackOp {
export const BlackOperations: { export const BlackOperations: {
[key: string]: IBlackOp | undefined; [key: string]: IBlackOp | undefined;
} = { } = {
"Operation Typhoon": { [BlackOperationNames.OperationTyphoon]: {
desc: ( desc: (
<> <>
Obadiah Zenyatta is the leader of a RedWater PMC. It has long been known among the intelligence community that Obadiah Zenyatta is the leader of a RedWater PMC. It has long been known among the intelligence community that
Zenyatta, along with the rest of the PMC, is a Synthoid. Zenyatta, along with the rest of the PMC, is a Synthoid.
<br /> <br />
<br /> <br />
The goal of Operation Typhoon is to find and eliminate Zenyatta and RedWater by any means necessary. After the The goal of {BlackOperationNames.OperationTyphoon} is to find and eliminate Zenyatta and RedWater by any means necessary. After the
task is completed, the actions must be covered up from the general public. task is completed, the actions must be covered up from the general public.
</> </>
), ),
}, },
"Operation Zero": { [BlackOperationNames.OperationZero]: {
desc: ( desc: (
<> <>
AeroCorp is one of the world's largest defense contractors. Its leader, Steve Watataki, is thought to be a AeroCorp is one of the world's largest defense contractors. Its leader, Steve Watataki, is thought to be a
supporter of Synthoid rights. He must be removed. supporter of Synthoid rights. He must be removed.
<br /> <br />
<br /> <br />
The goal of Operation Zero is to covertly infiltrate AeroCorp and uncover any incriminating evidence or The goal of {BlackOperationNames.OperationZero} is to covertly infiltrate AeroCorp and uncover any incriminating evidence or
information against Watataki that will cause him to be removed from his position at AeroCorp. Incriminating information against Watataki that will cause him to be removed from his position at AeroCorp. Incriminating
evidence can be fabricated as a last resort. Be warned that AeroCorp has some of the most advanced security evidence can be fabricated as a last resort. Be warned that AeroCorp has some of the most advanced security
measures in the world. measures in the world.
</> </>
), ),
}, },
"Operation X": { [BlackOperationNames.OperationX]: {
desc: ( desc: (
<> <>
We have recently discovered an underground publication group called Samizdat. Even though most of their We have recently discovered an underground publication group called Samizdat. Even though most of their
@ -44,12 +47,12 @@ export const BlackOperations: {
<br /> <br />
<br /> <br />
Samizdat has done a good job of keeping hidden and anonymous. However, we've just received intelligence that Samizdat has done a good job of keeping hidden and anonymous. However, we've just received intelligence that
their base of operations is in Ishima's underground sewer systems. Your task is to investigate the sewer their base of operations is in {CityName.Ishima}'s underground sewer systems. Your task is to investigate the sewer
systems, and eliminate Samizdat. They must never publish anything again. systems, and eliminate Samizdat. They must never publish anything again.
</> </>
), ),
}, },
"Operation Titan": { [BlackOperationNames.OperationTitan]: {
desc: ( desc: (
<> <>
Several months ago Titan Laboratories' Bioengineering department was infiltrated by Synthoids. As far as we Several months ago Titan Laboratories' Bioengineering department was infiltrated by Synthoids. As far as we
@ -58,13 +61,13 @@ export const BlackOperations: {
dangerous. dangerous.
<br /> <br />
<br /> <br />
Your goal is to enter and destroy the Bioengineering department's facility in Aevum. The task is not just to Your goal is to enter and destroy the Bioengineering department's facility in {CityName.Aevum}. The task is not just to
retire the Synthoids there, but also to destroy any information or research at the facility that is relevant to retire the Synthoids there, but also to destroy any information or research at the facility that is relevant to
the Synthoids and their goals. the Synthoids and their goals.
</> </>
), ),
}, },
"Operation Ares": { [BlackOperationNames.OperationAres]: {
desc: ( desc: (
<> <>
One of our undercover agents, Agent Carter, has informed us of a massive weapons deal going down in Dubai One of our undercover agents, Agent Carter, has informed us of a massive weapons deal going down in Dubai
@ -76,7 +79,7 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Archangel": { [BlackOperationNames.OperationArchangel]: {
desc: ( desc: (
<> <>
Our analysts have discovered that the popular Red Rabbit brothel in Amsterdam is run and 'staffed' by MK-VI Our analysts have discovered that the popular Red Rabbit brothel in Amsterdam is run and 'staffed' by MK-VI
@ -89,11 +92,11 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Juggernaut": { [BlackOperationNames.OperationJuggernaut]: {
desc: ( desc: (
<> <>
The CIA has just encountered a new security threat. A new criminal group, lead by a shadowy operative who calls The CIA has just encountered a new security threat. A new criminal group, lead by a shadowy operative who calls
himself Juggernaut, has been smuggling drugs and weapons (including suspected bioweapons) into Sector-12. We himself Juggernaut, has been smuggling drugs and weapons (including suspected bioweapons) into {CityName.Sector12}. We
also have reason to believe they tried to break into one of Universal Energy's facilities in order to cause a also have reason to believe they tried to break into one of Universal Energy's facilities in order to cause a
city-wide blackout. The CIA suspects that Juggernaut is a heavily-augmented Synthoid, and have thus enlisted our city-wide blackout. The CIA suspects that Juggernaut is a heavily-augmented Synthoid, and have thus enlisted our
help. help.
@ -103,20 +106,20 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Red Dragon": { [BlackOperationNames.OperationRedDragon]: {
desc: ( desc: (
<> <>
The Tetrads criminal organization is suspected of reverse-engineering the MK-VI Synthoid design. We believe they The {FactionNames.Tetrads} criminal organization is suspected of reverse-engineering the MK-VI Synthoid design. We believe they
altered and possibly improved the design and began manufacturing their own Synthoid models in order to bolster altered and possibly improved the design and began manufacturing their own Synthoid models in order to bolster
their criminal activities. their criminal activities.
<br /> <br />
<br /> <br />
Your task is to infiltrate and destroy the Tetrads' base of operations in Los Angeles. Intelligence tells us Your task is to infiltrate and destroy the {FactionNames.Tetrads}' base of operations in Los Angeles. Intelligence tells us
that their base houses one of their Synthoid manufacturing units. that their base houses one of their Synthoid manufacturing units.
</> </>
), ),
}, },
"Operation K": { [BlackOperationNames.OperationK]: {
desc: ( desc: (
<> <>
CODE RED SITUATION. Our intelligence tells us that VitaLife has discovered a new android cloning technology. CODE RED SITUATION. Our intelligence tells us that VitaLife has discovered a new android cloning technology.
@ -132,49 +135,49 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Deckard": { [BlackOperationNames.OperationDeckard]: {
desc: ( desc: (
<> <>
Despite your success in eliminating VitaLife's new android-replicating technology in Operation K, we've Despite your success in eliminating VitaLife's new android-replicating technology in {BlackOperationNames.OperationK}, we've
discovered that a small group of MK-VI Synthoids were able to make off with the schematics and design of the discovered that a small group of MK-VI Synthoids were able to make off with the schematics and design of the
technology before the Operation. It is almost a certainty that these Synthoids are some of the rogue MK-VI ones technology before the Operation. It is almost a certainty that these Synthoids are some of the rogue MK-VI ones
from the Synthoid Uprising. from the Synthoid Uprising.
<br /> <br />
<br /> <br />
The goal of Operation Deckard is to hunt down these Synthoids and retire them. I don't need to tell you how The goal of {BlackOperationNames.OperationDeckard} is to hunt down these Synthoids and retire them. I don't need to tell you how
critical this mission is. critical this mission is.
</> </>
), ),
}, },
"Operation Tyrell": { [BlackOperationNames.OperationTyrell]: {
desc: ( desc: (
<> <>
A week ago Blade Industries reported a small break-in at one of their Aevum Augmentation storage facilities. We A week ago {FactionNames.BladeIndustries} reported a small break-in at one of their {CityName.Aevum} Augmentation storage facilities. We
figured out that The Dark Army was behind the heist, and didn't think any more of it. However, we've just figured out that {FactionNames.TheDarkArmy} was behind the heist, and didn't think any more of it. However, we've just
discovered that several known MK-VI Synthoids were part of that break-in group. discovered that several known MK-VI Synthoids were part of that break-in group.
<br /> <br />
<br /> <br />
We cannot have Synthoids upgrading their already-enhanced abilities with Augmentations. Your task is to hunt We cannot have Synthoids upgrading their already-enhanced abilities with Augmentations. Your task is to hunt
down the associated Dark Army members and eliminate them. down associated {FactionNames.TheDarkArmy} members and eliminate them.
</> </>
), ),
}, },
"Operation Wallace": { [BlackOperationNames.OperationWallace]: {
desc: ( desc: (
<> <>
Based on information gathered from Operation Tyrell, we've discovered that The Dark Army was well aware that Based on information gathered from {BlackOperationNames.OperationTyrell}, we've discovered that {FactionNames.TheDarkArmy} was well aware that
there were Synthoids amongst their ranks. Even worse, we believe that The Dark Army is working together with there were Synthoids amongst their ranks. Even worse, we believe that {FactionNames.TheDarkArmy} is working together with
other criminal organizations such as The Syndicate and that they are planning some sort of large-scale takeover other criminal organizations such as {FactionNames.TheSyndicate} and that they are planning some sort of large-scale takeover
of multiple major cities, most notably Aevum. We suspect that Synthoids have infiltrated the ranks of these of multiple major cities, most notably {CityName.Aevum}. We suspect that Synthoids have infiltrated the ranks of these
criminal factions and are trying to stage another Synthoid uprising. criminal factions and are trying to stage another Synthoid uprising.
<br /> <br />
<br /> <br />
The best way to deal with this is to prevent it before it even happens. The goal of Operation Wallace is to The best way to deal with this is to prevent it before it even happens. The goal of {BlackOperationNames.OperationWallace} is to
destroy the Dark Army and Syndicate factions in Aevum immediately. Leave no survivors. destroy {FactionNames.TheDarkArmy} and Syndicate factions in {CityName.Aevum} immediately. Leave no survivors.
</> </>
), ),
}, },
"Operation Shoulder of Orion": { [BlackOperationNames.OperationShoulderOfOrion]: {
desc: ( desc: (
<> <>
China's Solaris Space Systems is secretly launching the first manned spacecraft in over a decade using China's Solaris Space Systems is secretly launching the first manned spacecraft in over a decade using
@ -187,10 +190,10 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Hyron": { [BlackOperationNames.OperationHyron]: {
desc: ( desc: (
<> <>
Our intelligence tells us that Fulcrum Technologies is developing a quantum supercomputer using human brains as Our intelligence tells us that {FactionNames.FulcrumSecretTechnologies} is developing a quantum supercomputer using human brains as
core processors. This supercomputer is rumored to be able to store vast amounts of data and perform computations core processors. This supercomputer is rumored to be able to store vast amounts of data and perform computations
unmatched by any other supercomputer on the planet. But more importantly, the use of organic human brains means unmatched by any other supercomputer on the planet. But more importantly, the use of organic human brains means
that the supercomputer may be able to reason abstractly and become self-aware. that the supercomputer may be able to reason abstractly and become self-aware.
@ -199,18 +202,18 @@ export const BlackOperations: {
I do not need to remind you why sentient-level AIs pose a serious threat to all of mankind. I do not need to remind you why sentient-level AIs pose a serious threat to all of mankind.
<br /> <br />
<br /> <br />
The research for this project is being conducted at one of Fulcrum Technologies secret facilities in Aevum, The research for this project is being conducted at one of {FactionNames.FulcrumSecretTechnologies} secret facilities in {CityName.Aevum},
codenamed 'Alpha Ranch'. Infiltrate the compound, delete and destroy the work, and then find and kill the codenamed 'Alpha Ranch'. Infiltrate the compound, delete and destroy the work, and then find and kill the
project lead. project lead.
</> </>
), ),
}, },
"Operation Morpheus": { [BlackOperationNames.OperationMorpheus]: {
desc: ( desc: (
<> <>
DreamSense Technologies is an advertising company that uses special technology to transmit their ads into the DreamSense Technologies is an advertising company that uses special technology to transmit their ads into the
people's dreams and subconcious. They do this using broadcast transmitter towers. Based on information from our people's dreams and subconcious. They do this using broadcast transmitter towers. Based on information from our
agents and informants in Chonqging, we have reason to believe that one of the broadcast towers there has been agents and informants in {CityName.Chongqing}, we have reason to believe that one of the broadcast towers there has been
compromised by Synthoids and is being used to spread pro-Synthoid propaganda. compromised by Synthoids and is being used to spread pro-Synthoid propaganda.
<br /> <br />
<br /> <br />
@ -218,38 +221,38 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Ion Storm": { [BlackOperationNames.OperationIonStorm]: {
desc: ( desc: (
<> <>
Our analysts have uncovered a gathering of MK-VI Synthoids that have taken up residence in the Sector-12 Slums. Our analysts have uncovered a gathering of MK-VI Synthoids that have taken up residence in the {CityName.Sector12} Slums.
We don't know if they are rogue Synthoids from the Uprising, but we do know that they have been stockpiling We don't know if they are rogue Synthoids from the Uprising, but we do know that they have been stockpiling
weapons, money, and other resources. This makes them dangerous. weapons, money, and other resources. This makes them dangerous.
<br /> <br />
<br /> <br />
This is a full-scale assault operation to find and retire all of these Synthoids in the Sector-12 Slums. This is a full-scale assault operation to find and retire all of these Synthoids in the {CityName.Sector12} Slums.
</> </>
), ),
}, },
"Operation Annihilus": { [BlackOperationNames.OperationAnnihilus]: {
desc: ( desc: (
<> <>
Our superiors have ordered us to eradicate everything and everyone in an underground facility located in Aevum. Our superiors have ordered us to eradicate everything and everyone in an underground facility located in {CityName.Aevum}.
They tell us that the facility houses many dangerous Synthoids and belongs to a terrorist organization called They tell us that the facility houses many dangerous Synthoids and belongs to a terrorist organization called
'The Covenant'. We have no prior intelligence about this organization, so you are going in blind. '{FactionNames.TheCovenant}'. We have no prior intelligence about this organization, so you are going in blind.
</> </>
), ),
}, },
"Operation Ultron": { [BlackOperationNames.OperationUltron]: {
desc: ( desc: (
<> <>
OmniTek Incorporated, the original designer and manufacturer of Synthoids, has notified us of a malfunction in {FactionNames.OmniTekIncorporated}, the original designer and manufacturer of Synthoids, has notified us of a malfunction in
their AI design. This malfunction, when triggered, causes MK-VI Synthoids to become radicalized and seek out the their AI design. This malfunction, when triggered, causes MK-VI Synthoids to become radicalized and seek out the
destruction of humanity. They say that this bug affects all MK-VI Synthoids, not just the rogue ones from the destruction of humanity. They say that this bug affects all MK-VI Synthoids, not just the rogue ones from the
Uprising. Uprising.
<br /> <br />
<br /> <br />
OmniTek has also told us they they believe someone has triggered this malfunction in a large group of MK-VI {FactionNames.OmniTekIncorporated} has also told us they they believe someone has triggered this malfunction in a large group of MK-VI
Synthoids, and that these newly-radicalized Synthoids are now amassing in Volhaven to form a terrorist group Synthoids, and that these newly-radicalized Synthoids are now amassing in {CityName.Volhaven} to form a terrorist group
called Ultron. called Ultron.
<br /> <br />
<br /> <br />
@ -261,7 +264,7 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Centurion": { [BlackOperationNames.OperationCenturion]: {
desc: ( desc: (
<> <>
{"D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)"} {"D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)"}
@ -279,7 +282,7 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Vindictus": { [BlackOperationNames.OperationVindictus]: {
desc: ( desc: (
<> <>
{"D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)"} {"D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)"}
@ -293,7 +296,7 @@ export const BlackOperations: {
</> </>
), ),
}, },
"Operation Daedalus": { [BlackOperationNames.OperationDaedalus]: {
desc: <> Yesterday we obeyed kings and bent our neck to emperors. Today we kneel only to truth.</>, desc: <> Yesterday we obeyed kings and bent our neck to emperors. Today we kneel only to truth.</>,
}, },
}; };

@ -1,3 +1,4 @@
import { CityName } from './../../Locations/data/CityNames';
export const BladeburnerConstants: { export const BladeburnerConstants: {
CityNames: string[]; CityNames: string[];
CyclesPerSecond: number; CyclesPerSecond: number;
@ -27,7 +28,7 @@ export const BladeburnerConstants: {
HrcHpGain: number; HrcHpGain: number;
HrcStaminaGain: number; HrcStaminaGain: number;
} = { } = {
CityNames: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"], CityNames: [CityName.Aevum, CityName.Chongqing, CityName.Sector12, CityName.NewTokyo, CityName.Ishima, CityName.Volhaven],
CyclesPerSecond: 5, // Game cycle is 200 ms CyclesPerSecond: 5, // Game cycle is 200 ms
StaminaGainPerSecond: 0.0085, StaminaGainPerSecond: 0.0085,

@ -3,6 +3,7 @@ import { BlackOpList } from "./BlackOpList";
import { IBladeburner } from "../IBladeburner"; import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps { interface IProps {
bladeburner: IBladeburner; bladeburner: IBladeburner;
@ -17,7 +18,7 @@ export function BlackOpPage(props: IProps): React.ReactElement {
successively by completing the one before it. successively by completing the one before it.
<br /> <br />
<br /> <br />
<b>Your ultimate goal to climb through the ranks of Bladeburners is to complete all of the Black Ops.</b> <b>Your ultimate goal to climb through the ranks of {FactionNames.Bladeburners} is to complete all of the Black Ops.</b>
<br /> <br />
<br /> <br />
Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank Like normal operations, you may use a team for Black Ops. Failing a black op will incur heavy HP and rank

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
import { CinematicText } from "../../ui/React/CinematicText"; import { CinematicText } from "../../ui/React/CinematicText";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
@ -8,14 +9,14 @@ export function BladeburnerCinematic(): React.ReactElement {
return ( return (
<CinematicText <CinematicText
lines={[ lines={[
"In the middle of the 21st century, OmniTek Incorporated advanced robot evolution ", `In the middle of the 21st century, ${FactionNames.OmniTekIncorporated} advanced robot evolution `,
"with their Synthoids (synthetic androids), a being virtually identical to a human.", "with their Synthoids (synthetic androids), a being virtually identical to a human.",
"------", "------",
"Their sixth-generation Synthoids, called MK-VI, were stronger, faster, and more ", "Their sixth-generation Synthoids, called MK-VI, were stronger, faster, and more ",
"intelligent than humans. Many argued that the MK-VI Synthoids were the first ", "intelligent than humans. Many argued that the MK-VI Synthoids were the first ",
"example of sentient AI.", "example of sentient AI.",
"------", "------",
"Unfortunately, in 2070 a terrorist group called Ascendis Totalis hacked into OmniTek and ", `Unfortunately, in 2070 a terrorist group called Ascendis Totalis hacked into ${FactionNames.OmniTekIncorporated} and `,
"uploaded a rogue AI into their Synthoid manufacturing facilities.", "uploaded a rogue AI into their Synthoid manufacturing facilities.",
"------", "------",
"The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating ", "The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating ",
@ -27,14 +28,14 @@ export function BladeburnerCinematic(): React.ReactElement {
"------", "------",
"The intelligence community believes that not all of the rogue MK-VI Synthoids from the Uprising were ", "The intelligence community believes that not all of the rogue MK-VI Synthoids from the Uprising were ",
"found and destroyed, and that many of them are blending in as normal humans in society today. ", "found and destroyed, and that many of them are blending in as normal humans in society today. ",
"As a result, many nations have created Bladeburner divisions, special units that are tasked with ", `As a result, many nations have created ${FactionNames.Bladeburners} divisions, special units that are tasked with `,
"investigating and dealing with Synthoid threats.", "investigating and dealing with Synthoid threats.",
]} ]}
onDone={() => { onDone={() => {
router.toTerminal(); router.toTerminal();
dialogBoxCreate( dialogBoxCreate(
"Visit the National Security Agency (NSA) to apply for their Bladeburner " + `Visit the National Security Agency (NSA) to apply for their ${FactionNames.Bladeburners} ` +
"division! You will need 100 of each combat stat before doing this.", "division! You will need 100 of each combat stat before doing this.",
); );
}} }}
/> />

@ -15,6 +15,7 @@ import Tooltip from "@mui/material/Tooltip";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps { interface IProps {
bladeburner: IBladeburner; bladeburner: IBladeburner;
@ -34,7 +35,7 @@ export function Stats(props: IProps): React.ReactElement {
function openFaction(): void { function openFaction(): void {
if (!inFaction) return; if (!inFaction) return;
const faction = Factions["Bladeburners"]; const faction = Factions[FactionNames.Bladeburners];
if (!faction.isMember) { if (!faction.isMember) {
joinFaction(faction); joinFaction(faction);
} }

@ -1,3 +1,4 @@
import { CityName } from './../../Locations/data/CityNames';
const CyclesPerMarketCycle = 50; const CyclesPerMarketCycle = 50;
const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"]; const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
export const CorporationConstants: { export const CorporationConstants: {
@ -37,7 +38,7 @@ export const CorporationConstants: {
CyclesPerIndustryStateCycle: CyclesPerMarketCycle / AllCorporationStates.length, CyclesPerIndustryStateCycle: CyclesPerMarketCycle / AllCorporationStates.length,
SecsPerMarketCycle: CyclesPerMarketCycle / 5, SecsPerMarketCycle: CyclesPerMarketCycle / 5,
Cities: ["Aevum", "Chongqing", "Sector-12", "New Tokyo", "Ishima", "Volhaven"], Cities: [CityName.Aevum, CityName.Chongqing, CityName.Sector12, CityName.NewTokyo, CityName.Ishima, CityName.Volhaven],
WarehouseInitialCost: 5e9, //Initial purchase cost of warehouse WarehouseInitialCost: 5e9, //Initial purchase cost of warehouse
WarehouseInitialSize: 100, WarehouseInitialSize: 100,

@ -431,17 +431,21 @@ export function IndustryOffice(props: IProps): React.ReactElement {
<Typography> <Typography>
Size: {props.office.employees.length} / {props.office.size} employees Size: {props.office.employees.length} / {props.office.size} employees
</Typography> </Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr', width: 'fit-content' }}> <Box sx={{ display: "grid", gridTemplateColumns: "1fr", width: "fit-content" }}>
<Box sx={{ gridTemplateColumns: 'repeat(3, 1fr)' }}> <Box sx={{ gridTemplateColumns: "repeat(3, 1fr)" }}>
<Tooltip title={<Typography>Automatically hires an employee and gives him/her a random name</Typography>}> <Tooltip title={<Typography>Automatically hires an employee and gives him/her a random name</Typography>}>
<Button disabled={props.office.atCapacity()} onClick={autohireEmployeeButtonOnClick}> <span>
Hire Employee <Button disabled={props.office.atCapacity()} onClick={autohireEmployeeButtonOnClick}>
</Button> Hire Employee
</Button>
</span>
</Tooltip> </Tooltip>
<Tooltip title={<Typography>Upgrade the office's size so that it can hold more employees!</Typography>}> <Tooltip title={<Typography>Upgrade the office's size so that it can hold more employees!</Typography>}>
<Button disabled={corp.funds < 0} onClick={() => setUpgradeOfficeSizeOpen(true)}> <span>
Upgrade size <Button disabled={corp.funds < 0} onClick={() => setUpgradeOfficeSizeOpen(true)}>
</Button> Upgrade size
</Button>
</span>
</Tooltip> </Tooltip>
<UpgradeOfficeSizeModal <UpgradeOfficeSizeModal
rerender={props.rerender} rerender={props.rerender}
@ -455,9 +459,11 @@ export function IndustryOffice(props: IProps): React.ReactElement {
<Tooltip <Tooltip
title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>} title={<Typography>Throw an office party to increase your employee's morale and happiness</Typography>}
> >
<Button disabled={corp.funds < 0} onClick={() => setThrowPartyOpen(true)}> <span>
Throw Party <Button disabled={corp.funds < 0} onClick={() => setThrowPartyOpen(true)}>
</Button> Throw Party
</Button>
</span>
</Tooltip> </Tooltip>
<ThrowPartyModal <ThrowPartyModal
rerender={props.rerender} rerender={props.rerender}
@ -467,7 +473,6 @@ export function IndustryOffice(props: IProps): React.ReactElement {
/> />
</> </>
)} )}
</Box> </Box>
<SwitchButton manualMode={employeeManualAssignMode} switchMode={setEmployeeManualAssignMode} /> <SwitchButton manualMode={employeeManualAssignMode} switchMode={setEmployeeManualAssignMode} />
</Box> </Box>

@ -1,3 +1,4 @@
import { FactionNames } from '../Faction/data/FactionNames';
import { Fragment } from "./Fragment"; import { Fragment } from "./Fragment";
import { ActiveFragment } from "./ActiveFragment"; import { ActiveFragment } from "./ActiveFragment";
import { FragmentType } from "./FragmentType"; import { FragmentType } from "./FragmentType";
@ -32,7 +33,7 @@ export class StaneksGift implements IStaneksGift {
af.avgCharge = (af.numCharge * af.avgCharge + threads) / (af.numCharge + 1); af.avgCharge = (af.numCharge * af.avgCharge + threads) / (af.numCharge + 1);
af.numCharge++; af.numCharge++;
const cotmg = Factions["Church of the Machine God"]; const cotmg = Factions[FactionNames.ChurchOfTheMachineGod];
cotmg.playerReputation += (player.faction_rep_mult * (Math.pow(threads, 0.95) * (cotmg.favor + 100))) / 1000; cotmg.playerReputation += (player.faction_rep_mult * (Math.pow(threads, 0.95) * (cotmg.favor + 100))) / 1000;
} }

@ -11,11 +11,12 @@ import Select, { SelectChangeEvent } from "@mui/material/Select";
import { Companies as AllCompanies } from "../../Company/Companies"; import { Companies as AllCompanies } from "../../Company/Companies";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
import { Adjuster } from "./Adjuster"; import { Adjuster } from "./Adjuster";
import { FactionNames } from "../../Faction/data/FactionNames";
const bigNumber = 1e12; const bigNumber = 1e12;
export function Companies(): React.ReactElement { export function Companies(): React.ReactElement {
const [company, setCompany] = useState("ECorp"); const [company, setCompany] = useState(FactionNames.ECorp as string);
function setCompanyDropdown(event: SelectChangeEvent<string>): void { function setCompanyDropdown(event: SelectChangeEvent<string>): void {
setCompany(event.target.value as string); setCompany(event.target.value as string);
} }

@ -17,6 +17,7 @@ import IconButton from "@mui/material/IconButton";
import ReplyAllIcon from "@mui/icons-material/ReplyAll"; import ReplyAllIcon from "@mui/icons-material/ReplyAll";
import ReplyIcon from "@mui/icons-material/Reply"; import ReplyIcon from "@mui/icons-material/Reply";
import InputLabel from "@mui/material/InputLabel"; import InputLabel from "@mui/material/InputLabel";
import { FactionNames } from "../../Faction/data/FactionNames";
const bigNumber = 1e12; const bigNumber = 1e12;
@ -25,7 +26,7 @@ interface IProps {
} }
export function Factions(props: IProps): React.ReactElement { export function Factions(props: IProps): React.ReactElement {
const [faction, setFaction] = useState("Illuminati"); const [faction, setFaction] = useState(FactionNames.Illuminati as string);
function setFactionDropdown(event: SelectChangeEvent<string>): void { function setFactionDropdown(event: SelectChangeEvent<string>): void {
setFaction(event.target.value as string); setFaction(event.target.value as string);
@ -36,9 +37,7 @@ export function Factions(props: IProps): React.ReactElement {
} }
function receiveAllInvites(): void { function receiveAllInvites(): void {
for (const i of Object.keys(AllFaction)) { Object.values(FactionNames).forEach(faction => props.player.receiveInvite(faction))
props.player.receiveInvite(AllFaction[i].name);
}
} }
function modifyFactionRep(modifier: number): (x: number) => void { function modifyFactionRep(modifier: number): (x: number) => void {

@ -18,42 +18,7 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { InvitationEvent } from "./ui/InvitationModal"; import { InvitationEvent } from "./ui/InvitationModal";
import { FactionNames } from "./data/FactionNames";
const factionOrder = [
"CyberSec",
"Tian Di Hui",
"Netburners",
"Sector-12",
"Chongqing",
"New Tokyo",
"Ishima",
"Aevum",
"Volhaven",
"NiteSec",
"The Black Hand",
"BitRunners",
"ECorp",
"MegaCorp",
"KuaiGong International",
"Four Sigma",
"NWO",
"Blade Industries",
"OmniTek Incorporated",
"Bachman & Associates",
"Clarke Incorporated",
"Fulcrum Secret Technologies",
"Slum Snakes",
"Tetrads",
"Silhouette",
"Speakers for the Dead",
"The Dark Army",
"The Syndicate",
"The Covenant",
"Daedalus",
"Illuminati",
"Bladeburners",
"Church of the Machine God",
]
export function inviteToFaction(faction: Faction): void { export function inviteToFaction(faction: Faction): void {
Player.receiveInvite(faction.name); Player.receiveInvite(faction.name);
@ -67,8 +32,9 @@ export function joinFaction(faction: Faction): void {
if (faction.isMember) return; if (faction.isMember) return;
faction.isMember = true; faction.isMember = true;
Player.factions.push(faction.name); Player.factions.push(faction.name);
const allFactions = Object.values(FactionNames).map(faction => faction as string)
Player.factions.sort((a, b) => Player.factions.sort((a, b) =>
factionOrder.indexOf(a) - factionOrder.indexOf(b)); allFactions.indexOf(a) - allFactions.indexOf(b));
const factionInfo = faction.getInfo(); const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction //Determine what factions you are banned from now that you have joined this faction
@ -166,15 +132,15 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
if (sing) { if (sing) {
return "You purchased " + aug.name; return "You purchased " + aug.name;
} else if (!Settings.SuppressBuyAugmentationConfirmation) { } else if (!Settings.SuppressBuyAugmentationConfirmation) {
dialogBoxCreate( dialogBoxCreate(
"You purchased " + "You purchased " +
aug.name + aug.name +
". Its enhancements will not take " + ". Its enhancements will not take " +
"effect until they are installed. To install your augmentations, go to the " + "effect until they are installed. To install your augmentations, go to the " +
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " + "'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
"augmentations will now be more expensive.", "augmentations will now be more expensive.",
); );
} }
} else { } else {
dialogBoxCreate( dialogBoxCreate(
"Hmm, something went wrong when trying to purchase an Augmentation. " + "Hmm, something went wrong when trying to purchase an Augmentation. " +

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import { IMap } from "../types"; import { IMap } from "../types";
import { FactionNames } from "./data/FactionNames";
/** /**
* Contains the "information" property for all the Factions, which is just a description of each faction * Contains the "information" property for all the Factions, which is just a description of each faction
@ -84,13 +85,15 @@ export class FactionInfo {
} }
} }
/** /**
* A map of all factions and associated info to them. * A map of all factions and associated info to them.
*/ */
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
export const FactionInfos: IMap<FactionInfo> = { export const FactionInfos: IMap<FactionInfo> = {
// Endgame // Endgame
Illuminati: new FactionInfo( [FactionNames.Illuminati]: new FactionInfo(
( (
<> <>
Humanity never changes. No matter how civilized society becomes, it will eventually fall back into chaos. And Humanity never changes. No matter how civilized society becomes, it will eventually fall back into chaos. And
@ -106,7 +109,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
Daedalus: new FactionInfo( [FactionNames.Daedalus]: new FactionInfo(
<>Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.</>, <>Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.</>,
[], [],
true, true,
@ -117,7 +120,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
"The Covenant": new FactionInfo( [FactionNames.TheCovenant]: new FactionInfo(
( (
<> <>
Surrender yourself. Give up your empty individuality to become part of something great, something eternal. Surrender yourself. Give up your empty individuality to become part of something great, something eternal.
@ -137,11 +140,11 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// Megacorporations, each forms its own faction // Megacorporations, each forms its own faction
ECorp: new FactionInfo( [FactionNames.ECorp]: new FactionInfo(
( (
<> <>
ECorp's mission is simple: to connect the world of today with the technology of tomorrow. With our wide range of {FactionNames.ECorp}'s mission is simple: to connect the world of today with the technology of tomorrow. With our wide range of
Internet-related software and commercial hardware, ECorp makes the world's information universally accessible. Internet-related software and commercial hardware, {FactionNames.ECorp} makes the world's information universally accessible.
</> </>
), ),
[], [],
@ -153,15 +156,15 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
MegaCorp: new FactionInfo( [FactionNames.MegaCorp]: new FactionInfo(
( (
<> <>
MegaCorp does what no other dares to do. We imagine. We create. We invent. We create what others have never even {FactionNames.MegaCorp} does what no other dares to do. We imagine. We create. We invent. We create what others have never even
dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecedented dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecedented
scale, in ways that no other company can. scale, in ways that no other company can.
<br /> <br />
<br /> <br />
In our labs and factories and on the ground with customers, MegaCorp is ushering in a new era for the world. In our labs and factories and on the ground with customers, {FactionNames.MegaCorp} is ushering in a new era for the world.
</> </>
), ),
[], [],
@ -173,7 +176,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"Bachman & Associates": new FactionInfo( [FactionNames.BachmanAssociates]: new FactionInfo(
( (
<> <>
Where Law and Business meet - thats where we are. Where Law and Business meet - thats where we are.
@ -191,9 +194,9 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"Blade Industries": new FactionInfo(<>Augmentation is Salvation.</>, [], true, true, true, true, false, true), [FactionNames.BladeIndustries]: new FactionInfo(<>Augmentation is Salvation.</>, [], true, true, true, true, false, true),
NWO: new FactionInfo( [FactionNames.NWO]: new FactionInfo(
( (
<> <>
Humans don't truly desire freedom. They want to be observed, understood, and judged. They want to be given Humans don't truly desire freedom. They want to be observed, understood, and judged. They want to be given
@ -210,7 +213,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"Clarke Incorporated": new FactionInfo( [FactionNames.ClarkeIncorporated]: new FactionInfo(
<>The Power of the Genome - Unlocked.</>, <>The Power of the Genome - Unlocked.</>,
[], [],
true, true,
@ -221,7 +224,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"OmniTek Incorporated": new FactionInfo( [FactionNames.OmniTekIncorporated]: new FactionInfo(
<>Simply put, our mission is to design and build robots that make a difference.</>, <>Simply put, our mission is to design and build robots that make a difference.</>,
[], [],
true, true,
@ -232,11 +235,11 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"Four Sigma": new FactionInfo( [FactionNames.FourSigma]: new FactionInfo(
( (
<> <>
The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by The scientific method is the best way to approach investing. Big strategies backed up with big data. Driven by
deep learning and innovative ideas. And improved by iteration. That's Four Sigma. deep learning and innovative ideas. And improved by iteration. That's {FactionNames.FourSigma}.
</> </>
), ),
[], [],
@ -248,7 +251,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true, true,
), ),
"KuaiGong International": new FactionInfo( [FactionNames.KuaiGongInternational]: new FactionInfo(
<>Dream big. Work hard. Make history.</>, <>Dream big. Work hard. Make history.</>,
[], [],
true, true,
@ -260,7 +263,7 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// Other Corporations // Other Corporations
"Fulcrum Secret Technologies": new FactionInfo( [FactionNames.FulcrumSecretTechnologies]: new FactionInfo(
( (
<> <>
The human organism has an innate desire to worship. That is why they created gods. If there were no gods, it The human organism has an innate desire to worship. That is why they created gods. If there were no gods, it
@ -277,7 +280,7 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// Hacker groups // Hacker groups
BitRunners: new FactionInfo( [FactionNames.BitRunners]: new FactionInfo(
( (
<> <>
Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. It's all Our entire lives are controlled by bits. All of our actions, our thoughts, our personal information. It's all
@ -299,7 +302,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
"The Black Hand": new FactionInfo( [FactionNames.TheBlackHand]: new FactionInfo(
( (
<> <>
The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power. The world, so afraid of strong government, now has no government. Only power - Digital power. Financial power.
@ -320,42 +323,42 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// prettier-ignore // prettier-ignore
NiteSec: new FactionInfo(<> [FactionNames.NiteSec]: new FactionInfo(<>
{" __..__ "}<br /> {" __..__ "}<br />
{" _.nITESECNIt. "}<br /> {" _.nITESECNIt. "}<br />
{" .-'NITESECNITESEc. "}<br /> {" .-'NITESECNITESEc. "}<br />
{" .' NITESECNITESECn "}<br /> {" .' NITESECNITESECn "}<br />
{" / NITESECNITESEC; "}<br /> {" / NITESECNITESEC; "}<br />
{" : :NITESECNITESEC; "}<br /> {" : :NITESECNITESEC; "}<br />
{" ; $ NITESECNITESECN "}<br /> {" ; $ NITESECNITESECN "}<br />
{" : _, ,N'ITESECNITESEC "}<br /> {" : _, ,N'ITESECNITESEC "}<br />
{" : .+^^`, : `NITESECNIT "}<br /> {" : .+^^`, : `NITESECNIT "}<br />
{" ) /), `-,-=,NITESECNI "}<br /> {" ) /), `-,-=,NITESECNI "}<br />
{" / ^ ,-;|NITESECN; "}<br /> {" / ^ ,-;|NITESECN; "}<br />
{" / _.' '-';NITESECN "}<br /> {" / _.' '-';NITESECN "}<br />
{" ( , ,-''`^NITE' "}<br /> {" ( , ,-''`^NITE' "}<br />
{" )` :`. .' "}<br /> {" )` :`. .' "}<br />
{" )-- ; `- / "}<br /> {" )-- ; `- / "}<br />
{" ' _.-' : "}<br /> {" ' _.-' : "}<br />
{" ( _.-' . "}<br /> {" ( _.-' . "}<br />
{" ------. "}<br /> {" ------. "}<br />
{" . "}<br /> {" . "}<br />
{" _.nIt "}<br /> {" _.nIt "}<br />
{" _.nITESECNi "}<br /> {" _.nITESECNi "}<br />
{" nITESECNIT^' "}<br /> {" nITESECNIT^' "}<br />
{" NITE^' ___ "}<br /> {" NITE^' ___ "}<br />
{" / .gP''''Tp. "}<br /> {" / .gP''''Tp. "}<br />
{" : d' . `b "}<br /> {" : d' . `b "}<br />
{" ; d' o `b ; "}<br /> {" ; d' o `b ; "}<br />
{" / d; `b| "}<br /> {" / d; `b| "}<br />
{" /, $; @ `: "}<br /> {" /, $; @ `: "}<br />
{" /' $/ ; "}<br /> {" /' $/ ; "}<br />
{" .' $/b o | "}<br /> {" .' $/b o | "}<br />
{" .' d$/$; : "}<br /> {" .' d$/$; : "}<br />
{" / .d/$/$; , ; "}<br /> {" / .d/$/$; , ; "}<br />
{" d .dNITESEC $ | "}<br /> {" d .dNITESEC $ | "}<br />
{" :bp.__.gNITESEC/$ :$ ; "}<br /> {" :bp.__.gNITESEC/$ :$ ; "}<br />
{" NITESECNITESECNIT /$b : "}<br /></>, {" NITESECNITESECNIT /$b : "}<br /></>,
[], [],
true, true,
true, true,
@ -366,9 +369,9 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// City factions, essentially governments // City factions, essentially governments
Aevum: new FactionInfo( [FactionNames.Aevum]: new FactionInfo(
<>The Silicon City.</>, <>The Silicon City.</>,
["Chongqing", "New Tokyo", "Ishima", "Volhaven"], [FactionNames.Chongqing, FactionNames.NewTokyo, FactionNames.Ishima, FactionNames.Volhaven],
true, true,
true, true,
true, true,
@ -376,9 +379,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
false, false,
), ),
Chongqing: new FactionInfo( [FactionNames.Chongqing]: new FactionInfo(
<>Serve the People.</>, <>Serve the People.</>,
["Sector-12", "Aevum", "Volhaven"], [FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true, true,
true, true,
true, true,
@ -386,9 +389,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
false, false,
), ),
Ishima: new FactionInfo( [FactionNames.Ishima]: new FactionInfo(
<>The East Asian Order of the Future.</>, <>The East Asian Order of the Future.</>,
["Sector-12", "Aevum", "Volhaven"], [FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true, true,
true, true,
true, true,
@ -396,9 +399,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
false, false,
), ),
"New Tokyo": new FactionInfo( [FactionNames.NewTokyo]: new FactionInfo(
<>Asia's World City.</>, <>Asia's World City.</>,
["Sector-12", "Aevum", "Volhaven"], [FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true, true,
true, true,
true, true,
@ -406,9 +409,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
false, false,
), ),
"Sector-12": new FactionInfo( [FactionNames.Sector12]: new FactionInfo(
<>The City of the Future.</>, <>The City of the Future.</>,
["Chongqing", "New Tokyo", "Ishima", "Volhaven"], [FactionNames.Chongqing, FactionNames.NewTokyo, FactionNames.Ishima, FactionNames.Volhaven],
true, true,
true, true,
true, true,
@ -416,9 +419,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
false, false,
), ),
Volhaven: new FactionInfo( [FactionNames.Volhaven]: new FactionInfo(
<>Benefit, Honor, and Glory.</>, <>Benefit, Honor, and Glory.</>,
["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"], [FactionNames.Chongqing, FactionNames.Sector12, FactionNames.NewTokyo, FactionNames.Aevum, FactionNames.Ishima],
true, true,
true, true,
true, true,
@ -428,7 +431,7 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// Criminal Organizations/Gangs // Criminal Organizations/Gangs
"Speakers for the Dead": new FactionInfo( [FactionNames.SpeakersForTheDead]: new FactionInfo(
<>It is better to reign in Hell than to serve in Heaven.</>, <>It is better to reign in Hell than to serve in Heaven.</>,
[], [],
true, true,
@ -439,7 +442,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
"The Dark Army": new FactionInfo( [FactionNames.TheDarkArmy]: new FactionInfo(
<>The World doesn't care about right or wrong. It only cares about power.</>, <>The World doesn't care about right or wrong. It only cares about power.</>,
[], [],
true, true,
@ -450,9 +453,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
"The Syndicate": new FactionInfo(<>Honor holds you back.</>, [], true, true, true, true, false, false), [FactionNames.TheSyndicate]: new FactionInfo(<>Honor holds you back.</>, [], true, true, true, true, false, false),
Silhouette: new FactionInfo( [FactionNames.Silhouette]: new FactionInfo(
( (
<> <>
Corporations have filled the void of power left behind by the collapse of Western government. The issue is Corporations have filled the void of power left behind by the collapse of Western government. The issue is
@ -472,7 +475,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
Tetrads: new FactionInfo( [FactionNames.Tetrads]: new FactionInfo(
<>Following the mandate of Heaven and carrying out the way.</>, <>Following the mandate of Heaven and carrying out the way.</>,
[], [],
false, false,
@ -483,14 +486,14 @@ export const FactionInfos: IMap<FactionInfo> = {
false, false,
), ),
"Slum Snakes": new FactionInfo(<>Slum Snakes rule!</>, [], false, false, true, true, false, false), [FactionNames.SlumSnakes]: new FactionInfo(<>{FactionNames.SlumSnakes} rule!</>, [], false, false, true, true, false, false),
// Earlygame factions - factions the player will prestige with early on that don't belong in other categories. // Earlygame factions - factions the player will prestige with early on that don't belong in other categories.
Netburners: new FactionInfo(<>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>, [], true, true, false, false, false, false), [FactionNames.Netburners]: new FactionInfo(<>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>, [], true, true, false, false, false, false),
"Tian Di Hui": new FactionInfo(<>Obey Heaven and work righteously.</>, [], true, true, false, true, false, false), [FactionNames.TianDiHui]: new FactionInfo(<>Obey Heaven and work righteously.</>, [], true, true, false, true, false, false),
CyberSec: new FactionInfo( [FactionNames.CyberSec]: new FactionInfo(
( (
<> <>
The Internet is the first thing that was built that we don't fully understand, the largest experiment in anarchy The Internet is the first thing that was built that we don't fully understand, the largest experiment in anarchy
@ -508,13 +511,13 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// Special Factions // Special Factions
Bladeburners: new FactionInfo( [FactionNames.Bladeburners]: new FactionInfo(
( (
<> <>
It's too bad they won't live. But then again, who does? It's too bad they won't live. But then again, who does?
<br /> <br />
<br /> <br />
Note that for this faction, reputation can only be gained through Bladeburner actions. Completing Bladeburner Note that for this faction, reputation can only be gained through {FactionNames.Bladeburners} actions. Completing {FactionNames.Bladeburners}
contracts/operations will increase your reputation. contracts/operations will increase your reputation.
</> </>
), ),
@ -528,7 +531,7 @@ export const FactionInfos: IMap<FactionInfo> = {
), ),
// prettier-ignore // prettier-ignore
"Church of the Machine God": new FactionInfo(<> [FactionNames.ChurchOfTheMachineGod]: new FactionInfo(<>
{" `` "}<br /> {" `` "}<br />
{" -odmmNmds: "}<br /> {" -odmmNmds: "}<br />
{" `hNmo:..-omNh. "}<br /> {" `hNmo:..-omNh. "}<br />
@ -558,7 +561,7 @@ export const FactionInfos: IMap<FactionInfo> = {
{" -smNNNNmdo- "}<br /> {" -smNNNNmdo- "}<br />
{" `..` "}<br /><br /> {" `..` "}<br /><br />
Many cultures predict an end to humanity in the near future, a final Many cultures predict an end to humanity in the near future, a final
Armageddon that will end the world; but we disagree. Armageddon that will end the world; but we disagree.
<br /><br />Note that for this faction, reputation can <br /><br />Note that for this faction, reputation can
only be gained by charging Stanek's gift.</>, only be gained by charging Stanek's gift.</>,
[], [],

@ -0,0 +1,35 @@
export enum FactionNames {
Illuminati = "Illuminati",
Daedalus = "Daedalus",
TheCovenant = "The Covenant",
ECorp = "ECorp",
MegaCorp = "MegaCorp",
BachmanAssociates = "Bachman & Associates",
BladeIndustries = "Blade Industries",
NWO = "NWO",
ClarkeIncorporated = "Clarke Incorporated",
OmniTekIncorporated = "OmniTek Incorporated",
FourSigma = "Four Sigma",
KuaiGongInternational = "KuaiGong International",
FulcrumSecretTechnologies = "Fulcrum Secret Technologies",
BitRunners = "BitRunners",
TheBlackHand = "The Black Hand",
NiteSec = "NiteSec",
Aevum = "Aevum",
Chongqing = "Chongqing",
Ishima = "Ishima",
NewTokyo = "NewTokyo",
Sector12 = "Sector12",
Volhaven = "Volhaven",
SpeakersForTheDead = "Speakers for the Dead",
TheDarkArmy = "The Dark Army",
TheSyndicate = "The Syndicate",
Silhouette = "Silhouette",
Tetrads = "Tetrads",
SlumSnakes = "Slum Snakes",
Netburners = "Netburners",
TianDiHui = "Tian Di Hui",
CyberSec = "CyberSec",
Bladeburners = "Bladeburners",
ChurchOfTheMachineGod = "Church of the Machine God",
}

@ -6,6 +6,7 @@ import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { FactionNames } from "../data/FactionNames";
interface IProps { interface IProps {
open: boolean; open: boolean;
@ -27,7 +28,7 @@ export function CreateGangModal(props: IProps): React.ReactElement {
"is not as important."; "is not as important.";
function isHacking(): boolean { function isHacking(): boolean {
return ["NiteSec", "The Black Hand"].includes(props.facName); return [FactionNames.NiteSec as string, FactionNames.TheBlackHand as string].includes(props.facName);
} }
function createGang(): void { function createGang(): void {

@ -21,6 +21,8 @@ import { CreateGangModal } from "./CreateGangModal";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot"; import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot";
import { FactionNames } from "../data/FactionNames";
import { GangConstants } from "../../Gang/data/Constants";
type IProps = { type IProps = {
faction: Faction; faction: Faction;
@ -50,16 +52,6 @@ const augmentationsInfo =
"your abilities."; "your abilities.";
const sleevePurchasesInfo = "Purchase Duplicate Sleeves and upgrades. These are permanent!"; const sleevePurchasesInfo = "Purchase Duplicate Sleeves and upgrades. These are permanent!";
const GangNames = [
"Slum Snakes",
"Tetrads",
"The Syndicate",
"The Dark Army",
"Speakers for the Dead",
"NiteSec",
"The Black Hand",
];
interface IMainProps { interface IMainProps {
faction: Faction; faction: Faction;
rerender: () => void; rerender: () => void;
@ -111,9 +103,9 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction); const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
const canDonate = faction.favor >= favorToDonate; const canDonate = faction.favor >= favorToDonate;
const canPurchaseSleeves = faction.name === "The Covenant" && player.bitNodeN === 10; const canPurchaseSleeves = faction.name === FactionNames.TheCovenant && player.bitNodeN === 10;
let canAccessGang = player.canAccessGang() && GangNames.includes(faction.name); let canAccessGang = player.canAccessGang() && GangConstants.Names.includes(faction.name);
if (player.inGang()) { if (player.inGang()) {
if (player.getGangName() !== faction.name) { if (player.getGangName() !== faction.name) {
canAccessGang = false; canAccessGang = false;

@ -1,3 +1,4 @@
import { FactionNames } from '../Faction/data/FactionNames';
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
interface GangTerritory { interface GangTerritory {
@ -8,31 +9,31 @@ interface GangTerritory {
export let AllGangs: { export let AllGangs: {
[key: string]: GangTerritory; [key: string]: GangTerritory;
} = { } = {
"Slum Snakes": { [FactionNames.SlumSnakes]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
Tetrads: { [FactionNames.Tetrads]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Syndicate": { [FactionNames.TheSyndicate]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Dark Army": { [FactionNames.TheDarkArmy]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"Speakers for the Dead": { [FactionNames.SpeakersForTheDead]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
NiteSec: { [FactionNames.NiteSec]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Black Hand": { [FactionNames.TheBlackHand]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
@ -40,31 +41,31 @@ export let AllGangs: {
export function resetGangs(): void { export function resetGangs(): void {
AllGangs = { AllGangs = {
"Slum Snakes": { [FactionNames.SlumSnakes]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
Tetrads: { [FactionNames.Tetrads]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Syndicate": { [FactionNames.TheSyndicate]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Dark Army": { [FactionNames.TheDarkArmy]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"Speakers for the Dead": { [FactionNames.SpeakersForTheDead]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
NiteSec: { [FactionNames.NiteSec]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },
"The Black Hand": { [FactionNames.TheBlackHand]: {
power: 1, power: 1,
territory: 1 / 7, territory: 1 / 7,
}, },

@ -1,3 +1,5 @@
import { FactionNames } from "../../Faction/data/FactionNames";
export const GangConstants: { export const GangConstants: {
GangRespectToReputationRatio: number; GangRespectToReputationRatio: number;
MaximumGangMembers: number; MaximumGangMembers: number;
@ -13,12 +15,12 @@ export const GangConstants: {
AscensionMultiplierRatio: 0.15, AscensionMultiplierRatio: 0.15,
// Names of possible Gangs // Names of possible Gangs
Names: [ Names: [
"Slum Snakes", FactionNames.SlumSnakes,
"Tetrads", FactionNames.Tetrads,
"The Syndicate", FactionNames.TheSyndicate,
"The Dark Army", FactionNames.TheDarkArmy,
"Speakers for the Dead", FactionNames.SpeakersForTheDead,
"NiteSec", FactionNames.NiteSec,
"The Black Hand", FactionNames.TheBlackHand,
], ],
}; };

@ -1,11 +1,12 @@
import { FactionNames } from '../../Faction/data/FactionNames';
export const PowerMultiplier: { export const PowerMultiplier: {
[key: string]: number | undefined; [key: string]: number | undefined;
} = { } = {
"Slum Snakes": 1, [FactionNames.SlumSnakes]: 1,
Tetrads: 2, [FactionNames.Tetrads]: 2,
"The Syndicate": 2, [FactionNames.TheSyndicate]: 2,
"The Dark Army": 2, [FactionNames.TheDarkArmy]: 2,
"Speakers for the Dead": 5, [FactionNames.SpeakersForTheDead]: 5,
NiteSec: 2, [FactionNames.NiteSec]: 2,
"The Black Hand": 5, [FactionNames.TheBlackHand]: 5,
}; };

@ -3,7 +3,6 @@
*/ */
import React, { useState } from "react"; import React, { useState } from "react";
import { useGang } from "./Context"; import { useGang } from "./Context";
import { generateTableRow } from "./GangMemberStats";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -22,7 +21,7 @@ import { GangMember } from "../GangMember";
import { UpgradeType } from "../data/upgrades"; import { UpgradeType } from "../data/upgrades";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview"; import { StatsRow } from "../../ui/React/StatsRow";
interface INextRevealProps { interface INextRevealProps {
upgrades: string[]; upgrades: string[];
@ -91,7 +90,6 @@ interface IPanelProps {
} }
function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement {
const classes = useStyles();
const gang = useGang(); const gang = useGang();
const player = use.Player(); const player = use.Player();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
@ -178,12 +176,12 @@ function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement {
> >
<Table> <Table>
<TableBody> <TableBody>
{generateTableRow("Hacking", props.member.hack, props.member.hack_exp, Settings.theme.hack, classes)} <StatsRow name="Hacking" color={Settings.theme.hack} data={{ level: props.member.hack, exp: props.member.hack_exp }} />
{generateTableRow("Strength", props.member.str, props.member.str_exp, Settings.theme.combat, classes)} <StatsRow name="Strength" color={Settings.theme.combat} data={{ level: props.member.str, exp: props.member.str_exp }} />
{generateTableRow("Defense", props.member.def, props.member.def_exp, Settings.theme.combat, classes)} <StatsRow name="Defense" color={Settings.theme.combat} data={{ level: props.member.def, exp: props.member.def_exp }} />
{generateTableRow("Dexterity", props.member.dex, props.member.dex_exp, Settings.theme.combat, classes)} <StatsRow name="Dexterity" color={Settings.theme.combat} data={{ level: props.member.dex, exp: props.member.dex_exp }} />
{generateTableRow("Agility", props.member.agi, props.member.agi_exp, Settings.theme.combat, classes)} <StatsRow name="Agility" color={Settings.theme.combat} data={{ level: props.member.agi, exp: props.member.agi_exp }} />
{generateTableRow("Charisma", props.member.cha, props.member.cha_exp, Settings.theme.cha, classes)} <StatsRow name="Charisma" color={Settings.theme.cha} data={{ level: props.member.cha, exp: props.member.cha_exp }} />
</TableBody> </TableBody>
</Table> </Table>
</Tooltip> </Tooltip>

@ -17,36 +17,14 @@ import {
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { GangMember } from "../GangMember"; import { GangMember } from "../GangMember";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { MoneyRate } from "../../ui/React/MoneyRate"; import { MoneyRate } from "../../ui/React/MoneyRate";
import { StatsRow } from "../../ui/React/StatsRow";
import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview"; import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview";
interface IProps { interface IProps {
member: GangMember; member: GangMember;
} }
export const generateTableRow = (
name: string,
level: number,
exp: number,
color: string,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
classes: any
): React.ReactElement => {
return (
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>{name}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>
{formatNumber(level, 0)} ({numeralWrapper.formatExp(exp)} exp)
</Typography>
</TableCell>
</TableRow>
)
}
export function GangMemberStats(props: IProps): React.ReactElement { export function GangMemberStats(props: IProps): React.ReactElement {
const classes = useStyles(); const classes = useStyles();
@ -102,12 +80,12 @@ export function GangMemberStats(props: IProps): React.ReactElement {
> >
<Table sx={{ display: 'table', mb: 1, width: '100%' }}> <Table sx={{ display: 'table', mb: 1, width: '100%' }}>
<TableBody> <TableBody>
{generateTableRow("Hacking", props.member.hack, props.member.hack_exp, Settings.theme.hack, classes)} <StatsRow name="Hacking" color={Settings.theme.hack} data={{ level: props.member.hack, exp: props.member.hack_exp }} />
{generateTableRow("Strength", props.member.str, props.member.str_exp, Settings.theme.combat, classes)} <StatsRow name="Strength" color={Settings.theme.combat} data={{ level: props.member.str, exp: props.member.str_exp }} />
{generateTableRow("Defense", props.member.def, props.member.def_exp, Settings.theme.combat, classes)} <StatsRow name="Defense" color={Settings.theme.combat} data={{ level: props.member.def, exp: props.member.def_exp }} />
{generateTableRow("Dexterity", props.member.dex, props.member.dex_exp, Settings.theme.combat, classes)} <StatsRow name="Dexterity" color={Settings.theme.combat} data={{ level: props.member.dex, exp: props.member.dex_exp }} />
{generateTableRow("Agility", props.member.agi, props.member.agi_exp, Settings.theme.combat, classes)} <StatsRow name="Agility" color={Settings.theme.combat} data={{ level: props.member.agi, exp: props.member.agi_exp }} />
{generateTableRow("Charisma", props.member.cha, props.member.cha_exp, Settings.theme.cha, classes)} <StatsRow name="Charisma" color={Settings.theme.cha} data={{ level: props.member.cha, exp: props.member.cha_exp }} />
<TableRow> <TableRow>
<TableCell classes={{ root: classes.cellNone }}> <TableCell classes={{ root: classes.cellNone }}>
<br /> <br />

@ -0,0 +1,54 @@
import React from "react";
import Typography from "@mui/material/Typography";
import { Modal } from "../../ui/React/Modal";
interface IProps {
open: boolean;
onClose: () => void;
}
export const TerritoryInfoModal = ({ open, onClose }: IProps): React.ReactElement => {
return (
<Modal open={open} onClose={onClose}>
<>
<Typography variant='h4'>
Clashing
</Typography>
<Typography>
Every ~20 seconds, your gang has a chance to 'clash' with other gangs. Your chance to win a clash depends on
your gang's power, which is listed in the display below. Your gang's power slowly accumulates over time. The
accumulation rate is determined by the stats of all Gang members you have assigned to the 'Territory Warfare'
task. Gang members that are not assigned to this task do not contribute to your gang's power. Your gang also
loses a small amount of power whenever you lose a clash.
<br />
<br />
NOTE: Gang members assigned to 'Territory Warfare' can be killed during clashes. This can happen regardless of
whether you win or lose the clash. A gang member being killed results in both respect and power loss for your
gang.
</Typography>
<br />
<Typography variant='h4'>
Territory
</Typography>
<Typography>
The amount of territory you have affects all aspects of your Gang members' production, including money, respect,
and wanted level. It is very beneficial to have high territory control.
<br />
<br />
To increase your chances of winning territory, assign gang members to "Territory Warfare". This will build your
gang power. Then, enable "Engage in Territory Warfare" to start fighting over territory.
</Typography>
<br />
<Typography variant='h4'>
Territory Clash Chance
</Typography>
<Typography>
This percentage represents the chance you have of 'clashing' with another gang. If you do not wish to
gain/lose territory, then keep this percentage at 0% by not engaging in territory warfare.
</Typography>
</>
</Modal >
);
}

@ -1,133 +1,100 @@
/** /**
* React Component for the territory subpage. * React Component for the territory subpage.
*/ */
import React from "react"; import React, { useState } from "react";
import {
Container,
Button,
Paper,
Box,
Tooltip,
Switch,
FormControlLabel,
Typography
} from "@mui/material";
import { Help } from "@mui/icons-material";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { formatNumber } from "../../utils/StringHelperFunctions"; import { formatNumber } from "../../utils/StringHelperFunctions";
import { AllGangs } from "../AllGangs";
import { useGang } from "./Context";
import Typography from "@mui/material/Typography"; import { AllGangs } from "../AllGangs";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch"; import { useGang } from "./Context";
import Tooltip from "@mui/material/Tooltip"; import { TerritoryInfoModal } from "./TerritoryInfoModal";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
export function TerritorySubpage(): React.ReactElement { export function TerritorySubpage(): React.ReactElement {
const gang = useGang(); const gang = useGang();
const gangNames = Object.keys(AllGangs).filter((g) => g != gang.facName); const gangNames = Object.keys(AllGangs).filter((g) => g != gang.facName);
const [infoOpen, setInfoOpen] = useState(false);
return ( return (
<> <Container disableGutters maxWidth="md" sx={{ mx: 0 }}>
<Typography> <Typography>
This page shows how much territory your Gang controls. This statistic is listed as a percentage, which This page shows how much territory your Gang controls. This statistic is listed as a percentage, which
represents how much of the total territory you control. represents how much of the total territory you control.
<br />
<br />
Every ~20 seconds, your gang has a chance to 'clash' with other gangs. Your chance to win a clash depends on
your gang's power, which is listed in the display below. Your gang's power slowly accumulates over time. The
accumulation rate is determined by the stats of all Gang members you have assigned to the 'Territory Warfare'
task. Gang members that are not assigned to this task do not contribute to your gang's power. Your gang also
loses a small amount of power whenever you lose a clash.
<br />
<br />
NOTE: Gang members assigned to 'Territory Warfare' can be killed during clashes. This can happen regardless of
whether you win or lose the clash. A gang member being killed results in both respect and power loss for your
gang.
<br />
<br />
The amount of territory you have affects all aspects of your Gang members' production, including money, respect,
and wanted level. It is very beneficial to have high territory control.
<br />
<br />
To increase your chances of winning territory assign gang members to "Territory Warfare", this will build your
gang power. Then enable "Engage in Territory Warfare" to start fighting over territory.
</Typography> </Typography>
<FormControlLabel
control={ <Button onClick={() => setInfoOpen(true)} sx={{ my: 1 }}>
<Switch <Help sx={{ mr: 1 }} />
About Gang Territory
</Button>
<Box component={Paper} sx={{ p: 1, mb: 1 }}>
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{gang.facName} (Your gang)
</Typography>
<FormControlLabel
control={<Switch
checked={gang.territoryWarfareEngaged} checked={gang.territoryWarfareEngaged}
onChange={(event) => (gang.territoryWarfareEngaged = event.target.checked)} onChange={(event) => (gang.territoryWarfareEngaged = event.target.checked)}
/> />}
} label={<Tooltip
label={ title={<Typography>
<Tooltip Engaging in Territory Warfare sets your clash chance to 100%. Disengaging will cause your clash chance
title={ to gradually decrease until it reaches 0%.
<Typography> </Typography>}>
Engaging in Territory Warfare sets your clash chance to 100%. Disengaging will cause your clash chance
to gradually decrease until it reaches 0%.
</Typography>
}
>
<Typography>Engage in Territory Warfare</Typography> <Typography>Engage in Territory Warfare</Typography>
</Tooltip> </Tooltip>} />
} <br />
/> <FormControlLabel
<br /> control={<Switch
<Box display="flex">
<Tooltip
title={
<Typography>
This percentage represents the chance you have of 'clashing' with with another gang. If you do not wish to
gain/lose territory, then keep this percentage at 0% by not engaging in territory warfare.
</Typography>
}
>
<Typography>
Territory Clash Chance: {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)}
</Typography>
</Tooltip>
</Box>
<br />
<FormControlLabel
control={
<Switch
checked={gang.notifyMemberDeath} checked={gang.notifyMemberDeath}
onChange={(event) => (gang.notifyMemberDeath = event.target.checked)} onChange={(event) => (gang.notifyMemberDeath = event.target.checked)}
/> />}
} label={<Tooltip
label={ title={<Typography>
<Tooltip If this is enabled, then you will receive a pop-up notifying you whenever one of your Gang Members dies
title={ in a territory clash.
<Typography> </Typography>}>
If this is enabled, then you will receive a pop-up notifying you whenever one of your Gang Members dies
in a territory clash.
</Typography>
}
>
<Typography>Notify about Gang Member Deaths</Typography> <Typography>Notify about Gang Member Deaths</Typography>
</Tooltip> </Tooltip>} />
}
/>
<br />
<Paper>
<Typography> <Typography>
<b> <b>Territory Clash Chance:</b> {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)} <br />
<u>{gang.facName}</u> <b>Power:</b> {formatNumber(AllGangs[gang.facName].power, 3)} <br />
</b> <b>Territory:</b> {formatTerritory(AllGangs[gang.facName].territory)}% <br />
<br />
Power: {formatNumber(AllGangs[gang.facName].power, 6)}
<br />
Territory: {formatTerritory(AllGangs[gang.facName].territory)}%
<br />
<br />
</Typography> </Typography>
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
{gangNames.map((name) => ( {gangNames.map((name) => (
<OtherGangTerritory key={name} name={name} /> <OtherGangTerritory key={name} name={name} />
))} ))}
</Paper> </Box>
</> <TerritoryInfoModal open={infoOpen} onClose={() => setInfoOpen(false)} />
</Container >
); );
} }
function formatTerritory(n: number): string { function formatTerritory(n: number): string {
const v = n * 100; const v = n * 100;
const precision = 3;
if (v <= 0) { if (v <= 0) {
return formatNumber(0, 2); return formatNumber(0, precision);
} else if (v >= 100) { } else if (v >= 100) {
return formatNumber(100, 2); return formatNumber(100, precision);
} else { } else {
return formatNumber(v, 2); return formatNumber(v, precision);
} }
} }
@ -141,15 +108,15 @@ function OtherGangTerritory(props: ITerritoryProps): React.ReactElement {
const power = AllGangs[props.name].power; const power = AllGangs[props.name].power;
const clashVictoryChance = playerPower / (power + playerPower); const clashVictoryChance = playerPower / (power + playerPower);
return ( return (
<Typography> <Box component={Paper} sx={{ p: 1 }}>
<u>{props.name}</u> <Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
<br /> {props.name}
Power: {formatNumber(power, 6)} </Typography>
<br /> <Typography>
Territory: {formatTerritory(AllGangs[props.name].territory)}%<br /> <b>Power:</b> {formatNumber(power, 3)} <br />
Chance to win clash with this gang: {numeralWrapper.formatPercentage(clashVictoryChance, 3)} <b>Territory:</b> {formatTerritory(AllGangs[props.name].territory)}% <br />
<br /> <b>Clash Win Chance:</b> {numeralWrapper.formatPercentage(clashVictoryChance, 3)}
<br /> </Typography>
</Typography> </Box>
); );
} }

@ -16,6 +16,7 @@ import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { SelectChangeEvent } from "@mui/material/Select"; import { SelectChangeEvent } from "@mui/material/Select";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps { interface IProps {
player: IPlayer; player: IPlayer;
@ -28,7 +29,7 @@ const serversMap: { [key: string]: string } = {};
export function HacknetUpgradeElem(props: IProps): React.ReactElement { export function HacknetUpgradeElem(props: IProps): React.ReactElement {
const [selectedServer, setSelectedServer] = useState( const [selectedServer, setSelectedServer] = useState(
serversMap[props.upg.name] ? serversMap[props.upg.name] : "ecorp", serversMap[props.upg.name] ? serversMap[props.upg.name] : FactionNames.ECorp.toLowerCase(),
); );
function changeTargetServer(event: SelectChangeEvent<string>): void { function changeTargetServer(event: SelectChangeEvent<string>): void {
setSelectedServer(event.target.value); setSelectedServer(event.target.value);
@ -42,7 +43,7 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement {
if (!res) { if (!res) {
dialogBoxCreate( dialogBoxCreate(
"Failed to purchase upgrade. This may be because you do not have enough hashes, " + "Failed to purchase upgrade. This may be because you do not have enough hashes, " +
"or because you do not have access to the feature upgrade affects.", "or because you do not have access to the feature upgrade affects.",
); );
} }
props.rerender(); props.rerender();

@ -1,6 +1,8 @@
import { CityName } from './../Locations/data/CityNames';
import { Literature } from "./Literature"; import { Literature } from "./Literature";
import { LiteratureNames } from "./data/LiteratureNames"; import { LiteratureNames } from "./data/LiteratureNames";
import { IMap } from "../types"; import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames";
export const Literatures: IMap<Literature> = {}; export const Literatures: IMap<Literature> = {};
@ -84,29 +86,29 @@ export const Literatures: IMap<Literature> = {};
"Synthetic androids, or Synthoids for short, are genetically engineered robots and, short of Augmentations, " + "Synthetic androids, or Synthoids for short, are genetically engineered robots and, short of Augmentations, " +
"are composed entirely of organic substances. For this reason, Synthoids are virtually identical to " + "are composed entirely of organic substances. For this reason, Synthoids are virtually identical to " +
"humans in form, composition, and appearance.<br><br>" + "humans in form, composition, and appearance.<br><br>" +
"Synthoids were first designed and manufactured by OmniTek Incorporated sometime around the middle of the century. " + `Synthoids were first designed and manufactured by ${FactionNames.OmniTekIncorporated} sometime around the middle of the century. ` +
"Their original purpose was to be used for manual labor and as emergency responders for disasters. As such, they " + "Their original purpose was to be used for manual labor and as emergency responders for disasters. As such, they " +
"were initially programmed only for their specific tasks. Each iteration that followed improved upon the " + "were initially programmed only for their specific tasks. Each iteration that followed improved upon the " +
"intelligence and capabilities of the Synthoids. By the 6th iteration, called MK-VI, the Synthoids were " + "intelligence and capabilities of the Synthoids. By the 6th iteration, called MK-VI, the Synthoids were " +
"so smart and capable enough of making their own decisions that many argued OmniTek had created the first " + `so smart and capable enough of making their own decisions that many argued ${FactionNames.OmniTekIncorporated} had created the first ` +
"sentient AI. These MK-VI Synthoids were produced in mass quantities (estimates up to 50 billion) with the hopes of increasing society's " + "sentient AI. These MK-VI Synthoids were produced in mass quantities (estimates up to 50 billion) with the hopes of increasing society's " +
"productivity and bolstering the global economy. Stemming from humanity's desire for technological advancement, optimism " + "productivity and bolstering the global economy. Stemming from humanity's desire for technological advancement, optimism " +
"and excitement about the future had never been higher.<br><br>" + "and excitement about the future had never been higher.<br><br>" +
"All of that excitement and optimism quickly turned to fear, panic, and dread in 2070, when a terrorist group " + "All of that excitement and optimism quickly turned to fear, panic, and dread in 2070, when a terrorist group " +
"called Ascendis Totalis hacked into OmniTek and uploaded a rogue AI into severeal of their Synthoid manufacturing facilities. " + `called Ascendis Totalis hacked into ${FactionNames.OmniTekIncorporated} and uploaded a rogue AI into severeal of their Synthoid manufacturing facilities. ` +
"This hack went undetected and for months OmniTek unknowingly churned out legions of Synthoids embedded with this " + `This hack went undetected and for months ${FactionNames.OmniTekIncorporated} unknowingly churned out legions of Synthoids embedded with this ` +
"rogue AI. Then, on December 24th, 2070, Omnica activated dormant protocols in the rogue AI, causing all of the " + "rogue AI. Then, on December 24th, 2070, Omnica activated dormant protocols in the rogue AI, causing all of the " +
"infected Synthoids to immediately launch a military campaign to seek and destroy all of humanity.<br><br>" + "infected Synthoids to immediately launch a military campaign to seek and destroy all of humanity.<br><br>" +
"What ensued was the deadlist conflict in human history. This crisis, now commonly known as the Synthoid Uprising, " + "What ensued was the deadlist conflict in human history. This crisis, now commonly known as the Synthoid Uprising, " +
"resulted in almost ten billion deaths over the course of a year. Despite the nations of the world banding together " + "resulted in almost ten billion deaths over the course of a year. Despite the nations of the world banding together " +
"to combat the threat, the MK-VI Synthoids were simply stronger, faster, more intelligent, and more adaptable than humans, " + "to combat the threat, the MK-VI Synthoids were simply stronger, faster, more intelligent, and more adaptable than humans, " +
"outsmarting them at every turn.<br><br>" + "outsmarting them at every turn.<br><br>" +
"It wasn't until the sacrifice of an elite international military taskforce, called the Bladeburners, that humanity " + `It wasn't until the sacrifice of an elite international military taskforce, called the ${FactionNames.Bladeburners}, that humanity ` +
"was finally able to defeat the Synthoids. The Bladeburners' final act was a suicide bombing mission that " + `was finally able to defeat the Synthoids. The ${FactionNames.Bladeburners}' final act was a suicide bombing mission that ` +
"destroyed a large portion of the MK-VI Synthoids, including many of its leaders. In the following " + "destroyed a large portion of the MK-VI Synthoids, including many of its leaders. In the following " +
"weeks militaries from around the world were able to round up and shut down the remaining rogue MK-VI Synthoids, ending " + "weeks militaries from around the world were able to round up and shut down the remaining rogue MK-VI Synthoids, ending " +
"the Synthoid Uprising.<br><br>" + "the Synthoid Uprising.<br><br>" +
"In the aftermath of the bloodshed, the Synthoid Accords were drawn up. These Accords banned OmniTek Incorporated " + `In the aftermath of the bloodshed, the Synthoid Accords were drawn up. These Accords banned ${FactionNames.OmniTekIncorporated} ` +
"from manufacturing any Synthoids beyond the MK-III series. They also banned any other corporation " + "from manufacturing any Synthoids beyond the MK-III series. They also banned any other corporation " +
"from constructing androids with advanced, near-sentient AI. MK-VI Synthoids that did not have the rogue Ascendis Totalis " + "from constructing androids with advanced, near-sentient AI. MK-VI Synthoids that did not have the rogue Ascendis Totalis " +
"AI were allowed to continue their existence, but they were stripped of all rights and protections as they " + "AI were allowed to continue their existence, but they were stripped of all rights and protections as they " +
@ -114,7 +116,7 @@ export const Literatures: IMap<Literature> = {};
"as working for any military/defense organization or conducting any bioengineering, computing, or robotics related research.<br><br>" + "as working for any military/defense organization or conducting any bioengineering, computing, or robotics related research.<br><br>" +
"Unfortunately, many believe that not all of the rogue MK-VI Synthoids from the Uprising were found and destroyed, " + "Unfortunately, many believe that not all of the rogue MK-VI Synthoids from the Uprising were found and destroyed, " +
"and that many of them are blending in as normal humans in society today. In response, many nations have created " + "and that many of them are blending in as normal humans in society today. In response, many nations have created " +
"Bladeburner divisions, special military branches that are tasked with investigating and dealing with any Synthoid threats.<br><br>" + `${FactionNames.Bladeburners} divisions, special military branches that are tasked with investigating and dealing with any Synthoid threats.<br><br>` +
"To this day, tensions still exist between the remaining Synthoids and humans as a result of the Uprising.<br><br>" + "To this day, tensions still exist between the remaining Synthoids and humans as a result of the Uprising.<br><br>" +
"Nobody knows what happened to the terrorist group Ascendis Totalis."; "Nobody knows what happened to the terrorist group Ascendis Totalis.";
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);
@ -199,9 +201,9 @@ export const Literatures: IMap<Literature> = {};
title = "Brighter than the Sun"; title = "Brighter than the Sun";
fn = LiteratureNames.BrighterThanTheSun; fn = LiteratureNames.BrighterThanTheSun;
txt = txt =
"When people think about the corporations that dominate the East, they typically think of KuaiGong International, which " + `When people think about the corporations that dominate the East, they typically think of ${FactionNames.KuaiGongInternational}, which ` +
"holds a complete monopoly for manufacturing and commerce in Asia, or Global Pharmaceuticals, the world's largest " + "holds a complete monopoly for manufacturing and commerce in Asia, or Global Pharmaceuticals, the world's largest " +
"drug company, or OmniTek Incorporated, the global leader in intelligent and autonomous robots. But there's one company " + `drug company, or ${FactionNames.OmniTekIncorporated}, the global leader in intelligent and autonomous robots. But there's one company ` +
"that has seen a rapid rise in the last year and is poised to dominate not only the East, but the entire world: TaiYang Digital.<br><br>" + "that has seen a rapid rise in the last year and is poised to dominate not only the East, but the entire world: TaiYang Digital.<br><br>" +
"TaiYang Digital is a Chinese internet-technology corporation that provides services such as " + "TaiYang Digital is a Chinese internet-technology corporation that provides services such as " +
"online advertising, search engines, gaming, media, entertainment, and cloud computing/storage. Its name TaiYang comes from the Chinese word " + "online advertising, search engines, gaming, media, entertainment, and cloud computing/storage. Its name TaiYang comes from the Chinese word " +
@ -213,7 +215,7 @@ export const Literatures: IMap<Literature> = {};
"TaiYang Digital's meteoric rise is extremely surprising in modern society. This sort of growth is " + "TaiYang Digital's meteoric rise is extremely surprising in modern society. This sort of growth is " +
"something you'd commonly see in the first half of the century, especially for tech companies. However in " + "something you'd commonly see in the first half of the century, especially for tech companies. However in " +
"the last two decades the number of corporations has significantly declined as the largest entities " + "the last two decades the number of corporations has significantly declined as the largest entities " +
"quickly took over the economy. Corporations such as ECorp, MegaCorp, and KuaiGong have established " + `quickly took over the economy. Corporations such as ${FactionNames.ECorp}, ${FactionNames.MegaCorp}, and ${FactionNames.KuaiGongInternational} have established ` +
"such strong monopolies in their market sectors that they have effectively killed off all " + "such strong monopolies in their market sectors that they have effectively killed off all " +
"of the smaller and new corporations that have tried to start up over the years. This is what makes " + "of the smaller and new corporations that have tried to start up over the years. This is what makes " +
"the rise of TaiYang Digital so impressive. And if TaiYang continues down this path, then they have " + "the rise of TaiYang Digital so impressive. And if TaiYang continues down this path, then they have " +
@ -234,11 +236,11 @@ export const Literatures: IMap<Literature> = {};
"And now democracy is dead, in the USA."; "And now democracy is dead, in the USA.";
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);
title = "Figures Show Rising Crime Rates in Sector-12"; title = `Figures Show Rising Crime Rates in ${CityName.Sector12}`;
fn = LiteratureNames.Sector12Crime; fn = LiteratureNames.Sector12Crime;
txt = txt =
"A recent study by analytics company Wilson Inc. shows a significant rise " + "A recent study by analytics company Wilson Inc. shows a significant rise " +
"in criminal activity in Sector-12. Perhaps the most alarming part of the statistic " + `in criminal activity in ${CityName.Sector12}. Perhaps the most alarming part of the statistic ` +
"is that most of the rise is in violent crime such as homicide and assault. According " + "is that most of the rise is in violent crime such as homicide and assault. According " +
"to the study, the city saw a total of 21,406 reported homicides in 2076, which is over " + "to the study, the city saw a total of 21,406 reported homicides in 2076, which is over " +
"a 20% increase compared to 2075.<br><br>" + "a 20% increase compared to 2075.<br><br>" +
@ -246,7 +248,7 @@ export const Literatures: IMap<Literature> = {};
"whether these figures indicate the beginning of a sustained increase in crime rates, or whether " + "whether these figures indicate the beginning of a sustained increase in crime rates, or whether " +
"the year was just an unfortunate outlier. He states that many intelligence and law enforcement " + "the year was just an unfortunate outlier. He states that many intelligence and law enforcement " +
"agents have noticed an increase in organized crime activites, and believes that these figures may " + "agents have noticed an increase in organized crime activites, and believes that these figures may " +
"be the result of an uprising from criminal organizations such as The Syndicate or the Slum Snakes."; `be the result of an uprising from criminal organizations such as ${FactionNames.TheSyndicate} or the ${FactionNames.SlumSnakes}.`;
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);
title = "Man and the Machine"; title = "Man and the Machine";
@ -276,15 +278,15 @@ export const Literatures: IMap<Literature> = {};
"most radical of conspiracy theorists claiming that they control everything in the entire world. And while the world " + "most radical of conspiracy theorists claiming that they control everything in the entire world. And while the world " +
"may never know for sure, it is likely that many secret societies do actually exist, even today.<br><br>" + "may never know for sure, it is likely that many secret societies do actually exist, even today.<br><br>" +
"However, the secret societies of the modern world are nothing like those that (supposedly) existed " + "However, the secret societies of the modern world are nothing like those that (supposedly) existed " +
"decades and centuries ago. The Freemasons, Knights Templar, and Illuminati, while they may have been around " + `decades and centuries ago. The Freemasons, Knights Templar, and ${FactionNames.Illuminati}, while they may have been around ` +
"at the turn of the 21st century, almost assuredly do not exist today. The dominance of the Web in " + "at the turn of the 21st century, almost assuredly do not exist today. The dominance of the Web in " +
"our everyday lives and the fact that so much of the world is now digital has given rise to a new breed " + "our everyday lives and the fact that so much of the world is now digital has given rise to a new breed " +
"of secret societies: Internet-based ones.<br><br>" + "of secret societies: Internet-based ones.<br><br>" +
"Commonly called 'hacker groups', Internet-based secret societies have become well-known in today's " + "Commonly called 'hacker groups', Internet-based secret societies have become well-known in today's " +
"world. Some of these, such as The Black Hand, are black hat groups that claim they are trying to " + `world. Some of these, such as ${FactionNames.TheBlackHand}, are black hat groups that claim they are trying to ` +
"help the oppressed by attacking the elite and powerful. Others, such as NiteSec, are hacktivist groups " + `help the oppressed by attacking the elite and powerful. Others, such as ${FactionNames.NiteSec}, are hacktivist groups ` +
"that try to push political and social agendas. Perhaps the most intriguing hacker group " + "that try to push political and social agendas. Perhaps the most intriguing hacker group " +
"is the mysterious Bitrunners, whose purpose still remains unknown."; `is the mysterious ${FactionNames.BitRunners}, whose purpose still remains unknown.`;
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);
title = "Space: The Failed Frontier"; title = "Space: The Failed Frontier";
@ -313,7 +315,7 @@ export const Literatures: IMap<Literature> = {};
"Medical, service, and manufacturing robots. All of these are examples of how far AI has come and how much it has " + "Medical, service, and manufacturing robots. All of these are examples of how far AI has come and how much it has " +
"improved our daily lives. However, the question still remains of whether AI will ever be advanced enough to re-create " + "improved our daily lives. However, the question still remains of whether AI will ever be advanced enough to re-create " +
"human intelligence.<br><br>" + "human intelligence.<br><br>" +
"We've certainly come close to artificial intelligence that is similar to humans. For example OmniTek Incorporated's " + `We've certainly come close to artificial intelligence that is similar to humans. For example ${FactionNames.OmniTekIncorporated}'s ` +
"CompanionBot, a robot meant to act as a comforting friend for lonely and grieving people, is eerily human-like " + "CompanionBot, a robot meant to act as a comforting friend for lonely and grieving people, is eerily human-like " +
"in its appearance, speech, mannerisms, and even movement. However its artificial intelligence isn't the same as " + "in its appearance, speech, mannerisms, and even movement. However its artificial intelligence isn't the same as " +
"that of humans. Not yet. It doesn't have sentience or self-awareness or consciousness.<br><br>" + "that of humans. Not yet. It doesn't have sentience or self-awareness or consciousness.<br><br>" +
@ -340,9 +342,9 @@ export const Literatures: IMap<Literature> = {};
fn = LiteratureNames.TensionsInTechRace; fn = LiteratureNames.TensionsInTechRace;
txt = txt =
"Have we entered a new Cold War? Is WWIII just beyond the horizon?<br><br>" + "Have we entered a new Cold War? Is WWIII just beyond the horizon?<br><br>" +
"After rumors came out that OmniTek Incorporated had begun developing advanced robotic supersoldiers, " + `After rumors came out that ${FactionNames.OmniTekIncorporated} had begun developing advanced robotic supersoldiers, ` +
"geopolitical tensions quickly flared between the USA, Russia, and several Asian superpowers. " + "geopolitical tensions quickly flared between the USA, Russia, and several Asian superpowers. " +
"In a rare show of cooperation between corporations, MegaCorp and ECorp have " + `In a rare show of cooperation between corporations, ${FactionNames.MegaCorp} and ${FactionNames.ECorp} have ` +
"reportedly launched hundreds of new surveillance and espionage satellites. " + "reportedly launched hundreds of new surveillance and espionage satellites. " +
"Defense contractors such as " + "Defense contractors such as " +
"DeltaOne and AeroCorp have been working with the CIA and NSA to prepare " + "DeltaOne and AeroCorp have been working with the CIA and NSA to prepare " +
@ -381,13 +383,13 @@ export const Literatures: IMap<Literature> = {};
txt = txt =
"WAKE UP SHEEPLE<br><br>" + "WAKE UP SHEEPLE<br><br>" +
"THE GOVERNMENT DOES NOT EXIST. CORPORATIONS DO NOT RUN SOCIETY<br><br>" + "THE GOVERNMENT DOES NOT EXIST. CORPORATIONS DO NOT RUN SOCIETY<br><br>" +
"THE ILLUMINATI ARE THE SECRET RULERS OF THE WORLD!<br><br>" + `THE ${FactionNames.Illuminati.toUpperCase()} ARE THE SECRET RULERS OF THE WORLD!<br><br>` +
"Yes, the Illuminati of legends. The ancient secret society that controls the entire " + `Yes, the ${FactionNames.Illuminati} of legends. The ancient secret society that controls the entire ` +
"world from the shadows with their invisible hand. The group of the rich and wealthy " + "world from the shadows with their invisible hand. The group of the rich and wealthy " +
"that have penetrated every major government, financial agency, and corporation in the last " + "that have penetrated every major government, financial agency, and corporation in the last " +
"three hundred years.<br><br>" + "three hundred years.<br><br>" +
"OPEN YOUR EYES<br><br>" + "OPEN YOUR EYES<br><br>" +
"It was the Illuminati that brought an end to democracy in the world. They are the driving force " + `It was the ${FactionNames.Illuminati} that brought an end to democracy in the world. They are the driving force ` +
"behind everything that happens.<br><br>" + "behind everything that happens.<br><br>" +
"THEY ARE ALL AROUND YOU<br><br>" + "THEY ARE ALL AROUND YOU<br><br>" +
"After destabilizing the world's governments, they are now entering the final stage of their master plan. " + "After destabilizing the world's governments, they are now entering the final stage of their master plan. " +
@ -416,15 +418,15 @@ export const Literatures: IMap<Literature> = {};
"territories. They were often considered one of the first and biggest criminal secret societies. " + "territories. They were often considered one of the first and biggest criminal secret societies. " +
"While most of the branches of the Triads have been destroyed over the past few decades, the " + "While most of the branches of the Triads have been destroyed over the past few decades, the " +
"crime faction has spawned and inspired a number of other Asian crime organizations over the past few years. " + "crime faction has spawned and inspired a number of other Asian crime organizations over the past few years. " +
"The most notable of these is the Tetrads.<br><br>" + `The most notable of these is the ${FactionNames.Tetrads}.<br><br>` +
"It is widely believed that the Tetrads are a rogue group that splintered off from the Triads sometime in the " + `It is widely believed that the ${FactionNames.Tetrads} are a rogue group that splintered off from the Triads sometime in the ` +
"mid 21st century. The founders of the Tetrads, all of whom were ex-Triad members, believed that the " + `mid 21st century. The founders of the ${FactionNames.Tetrads}, all of whom were ex-Triad members, believed that the ` +
"Triads were losing their purpose and direction. The Tetrads started off as a small group that mainly engaged " + `Triads were losing their purpose and direction. The ${FactionNames.Tetrads} started off as a small group that mainly engaged ` +
"in fraud and extortion. They were largely unknown until just a few years ago when they took over the illegal " + "in fraud and extortion. They were largely unknown until just a few years ago when they took over the illegal " +
"drug trade in all of the major Asian cities. They quickly became the most powerful crime syndicate in the " + "drug trade in all of the major Asian cities. They quickly became the most powerful crime syndicate in the " +
"continent.<br><br>" + "continent.<br><br>" +
"Not much else is known about the Tetrads, or about the efforts the Asian governments and corporations are making " + `Not much else is known about the ${FactionNames.Tetrads}, or about the efforts the Asian governments and corporations are making ` +
"to take down this large new crime organization. Many believe that the Tetrads have infiltrated the governments " + `to take down this large new crime organization. Many believe that the ${FactionNames.Tetrads} have infiltrated the governments ` +
"and powerful corporations in Asia, which has helped faciliate their recent rapid rise."; "and powerful corporations in Asia, which has helped faciliate their recent rapid rise.";
Literatures[fn] = new Literature(title, fn, txt); Literatures[fn] = new Literature(title, fn, txt);

@ -2,14 +2,6 @@
* Names of all locations * Names of all locations
*/ */
export enum LocationName { export enum LocationName {
// Cities
Aevum = "Aevum",
Chongqing = "Chongqing",
Ishima = "Ishima",
NewTokyo = "New Tokyo",
Sector12 = "Sector-12",
Volhaven = "Volhaven",
// Aevum Locations // Aevum Locations
AevumAeroCorp = "AeroCorp", AevumAeroCorp = "AeroCorp",
AevumBachmanAndAssociates = "Bachman & Associates", AevumBachmanAndAssociates = "Bachman & Associates",

@ -33,6 +33,7 @@ import { HacknetNode } from "../../Hacknet/HacknetNode";
import { HacknetServer } from "../../Hacknet/HacknetServer"; import { HacknetServer } from "../../Hacknet/HacknetServer";
import { GetServer } from "../../Server/AllServers"; import { GetServer } from "../../Server/AllServers";
import { ArcadeRoot } from "../../Arcade/ui/ArcadeRoot"; import { ArcadeRoot } from "../../Arcade/ui/ArcadeRoot";
import { FactionNames } from "../../Faction/data/FactionNames";
type IProps = { type IProps = {
loc: Location; loc: Location;
@ -158,8 +159,8 @@ export function SpecialLocation(props: IProps): React.ReactElement {
} }
function handleCotMG(): void { function handleCotMG(): void {
const faction = Factions["Church of the Machine God"]; const faction = Factions[FactionNames.ChurchOfTheMachineGod];
if (!player.factions.includes("Church of the Machine God")) { if (!player.factions.includes(FactionNames.ChurchOfTheMachineGod)) {
joinFaction(faction); joinFaction(faction);
} }
if ( if (
@ -231,7 +232,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
</> </>
); );
} }
if (player.factions.includes("Church of the Machine God")) { if (player.factions.includes(FactionNames.ChurchOfTheMachineGod)) {
return ( return (
<> <>
<Typography> <Typography>

@ -8,6 +8,7 @@ import { GetServer } from "../Server/AllServers";
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver } from "../utils/JSONReviver"; import { Reviver } from "../utils/JSONReviver";
import { FactionNames } from "../Faction/data/FactionNames";
//Sends message to player, including a pop up //Sends message to player, including a pop up
function sendMessage(msg: Message, forced = false): void { function sendMessage(msg: Message, forced = false): void {
@ -128,48 +129,48 @@ function initMessages(): void {
new Message( new Message(
MessageFilenames.Jumper0, MessageFilenames.Jumper0,
"I know you can sense it. I know you're searching for it. " + "I know you can sense it. I know you're searching for it. " +
"It's why you spend night after " + "It's why you spend night after " +
"night at your computer. <br><br>It's real, I've seen it. And I can " + "night at your computer. <br><br>It's real, I've seen it. And I can " +
"help you find it. But not right now. You're not ready yet.<br><br>" + "help you find it. But not right now. You're not ready yet.<br><br>" +
"Use this program to track your progress<br><br>" + "Use this program to track your progress<br><br>" +
"The fl1ght.exe program was added to your home computer<br><br>" + "The fl1ght.exe program was added to your home computer<br><br>" +
"-jump3R", "-jump3R",
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.Jumper1, MessageFilenames.Jumper1,
"Soon you will be contacted by a hacking group known as CyberSec. " + `Soon you will be contacted by a hacking group known as ${FactionNames.NiteSec}. ` +
"They can help you with your search. <br><br>" + "They can help you with your search. <br><br>" +
"You should join them, garner their favor, and " + "You should join them, garner their favor, and " +
"exploit them for their Augmentations. But do not trust them. " + "exploit them for their Augmentations. But do not trust them. " +
"They are not what they seem. No one is.<br><br>" + "They are not what they seem. No one is.<br><br>" +
"-jump3R", "-jump3R",
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.Jumper2, MessageFilenames.Jumper2,
"Do not try to save the world. There is no world to save. If " + "Do not try to save the world. There is no world to save. If " +
"you want to find the truth, worry only about yourself. Ethics and " + "you want to find the truth, worry only about yourself. Ethics and " +
"morals will get you killed. <br><br>Watch out for a hacking group known as NiteSec." + `morals will get you killed. <br><br>Watch out for a hacking group known as ${FactionNames.NiteSec}.` +
"<br><br>-jump3R", "<br><br>-jump3R",
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.Jumper3, MessageFilenames.Jumper3,
"You must learn to walk before you can run. And you must " + "You must learn to walk before you can run. And you must " +
"run before you can fly. Look for the black hand. <br><br>" + `run before you can fly. Look for ${FactionNames.TheBlackHand}. <br><br>` +
"I.I.I.I <br><br>-jump3R", "I.I.I.I <br><br>-jump3R",
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.Jumper4, MessageFilenames.Jumper4,
"To find what you are searching for, you must understand the bits. " + "To find what you are searching for, you must understand the bits. " +
"The bits are all around us. The runners will help you.<br><br>" + "The bits are all around us. The runners will help you.<br><br>" +
"-jump3R", "-jump3R",
), ),
); );
@ -178,31 +179,31 @@ function initMessages(): void {
new Message( new Message(
MessageFilenames.CyberSecTest, MessageFilenames.CyberSecTest,
"We've been watching you. Your skills are very impressive. But you're wasting " + "We've been watching you. Your skills are very impressive. But you're wasting " +
"your talents. If you join us, you can put your skills to good use and change " + "your talents. If you join us, you can put your skills to good use and change " +
"the world for the better. If you join us, we can unlock your full potential. <br><br>" + "the world for the better. If you join us, we can unlock your full potential. <br><br>" +
"But first, you must pass our test. Find and install the backdoor on our server. <br><br>" + "But first, you must pass our test. Find and install the backdoor on our server. <br><br>" +
"-CyberSec", `-${FactionNames.CyberSec}`,
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.NiteSecTest, MessageFilenames.NiteSecTest,
"People say that the corrupted governments and corporations rule the world. " + "People say that the corrupted governments and corporations rule the world. " +
"Yes, maybe they do. But do you know who everyone really fears? People " + "Yes, maybe they do. But do you know who everyone really fears? People " +
"like us. Because they can't hide from us. Because they can't fight shadows " + "like us. Because they can't hide from us. Because they can't fight shadows " +
"and ideas with bullets. <br><br>" + "and ideas with bullets. <br><br>" +
"Join us, and people will fear you, too. <br><br>" + "Join us, and people will fear you, too. <br><br>" +
"Find and install the backdoor on our server. Then, we will contact you again." + "Find and install the backdoor on our server. Then, we will contact you again." +
"<br><br>-NiteSec", `<br><br>-${FactionNames.NiteSec}`,
), ),
); );
AddToAllMessages( AddToAllMessages(
new Message( new Message(
MessageFilenames.BitRunnersTest, MessageFilenames.BitRunnersTest,
"We know what you are doing. We know what drives you. We know " + "We know what you are doing. We know what drives you. We know " +
"what you are looking for. <br><br> " + "what you are looking for. <br><br> " +
"We can help you find the answers.<br><br>" + "We can help you find the answers.<br><br>" +
"run4theh111z", "run4theh111z",
), ),
); );
@ -210,9 +211,9 @@ function initMessages(): void {
new Message( new Message(
MessageFilenames.RedPill, MessageFilenames.RedPill,
"@)(#V%*N)@(#*)*C)@#%*)*V)@#(*%V@)(#VN%*)@#(*%<br>" + "@)(#V%*N)@(#*)*C)@#%*)*V)@#(*%V@)(#VN%*)@#(*%<br>" +
")@B(*#%)@)M#B*%V)____FIND___#$@)#%(B*)@#(*%B)<br>" + ")@B(*#%)@)M#B*%V)____FIND___#$@)#%(B*)@#(*%B)<br>" +
"@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB<br>" + "@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB<br>" +
"DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)", "DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)",
), ),
); );
} }

@ -3,6 +3,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { Faction } from "../Faction/Faction"; import { Faction } from "../Faction/Faction";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { FactionNames } from "../Faction/data/FactionNames";
function allFactionAugs(p: IPlayer, f: Faction): boolean { function allFactionAugs(p: IPlayer, f: Faction): boolean {
const factionAugs = f.augmentations.slice().filter((aug) => aug !== "NeuroFlux Governor"); const factionAugs = f.augmentations.slice().filter((aug) => aug !== "NeuroFlux Governor");
@ -37,60 +38,60 @@ export const Milestones: Milestone[] = [
{ {
title: "Join the faction hinted at in csec-test.msg", title: "Join the faction hinted at in csec-test.msg",
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return p.factions.includes("CyberSec"); return p.factions.includes(FactionNames.CyberSec);
}, },
}, },
{ {
title: "Install all the Augmentations from CyberSec", title: `Install all the Augmentations from ${FactionNames.CyberSec}`,
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return allFactionAugs(p, Factions["CyberSec"]); return allFactionAugs(p, Factions[FactionNames.CyberSec]);
}, },
}, },
{ {
title: "Join the faction hinted at in nitesec-test.msg", title: "Join the faction hinted at in nitesec-test.msg",
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return p.factions.includes("NiteSec"); return p.factions.includes(FactionNames.NiteSec);
}, },
}, },
{ {
title: "Install all the Augmentations from NiteSec", title: `Install all the Augmentations from ${FactionNames.NiteSec}`,
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return allFactionAugs(p, Factions["NiteSec"]); return allFactionAugs(p, Factions[FactionNames.NiteSec]);
}, },
}, },
{ {
title: "Join the faction hinted at in j3.msg", title: "Join the faction hinted at in j3.msg",
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return p.factions.includes("The Black Hand"); return p.factions.includes(FactionNames.TheBlackHand);
}, },
}, },
{ {
title: "Install all the Augmentations from The Black Hand", title: `Install all the Augmentations from ${FactionNames.TheBlackHand}`,
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return allFactionAugs(p, Factions["The Black Hand"]); return allFactionAugs(p, Factions[FactionNames.TheBlackHand]);
}, },
}, },
{ {
title: "Join the faction hinted at in 19dfj3l1nd.msg", title: "Join the faction hinted at in 19dfj3l1nd.msg",
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return p.factions.includes("BitRunners"); return p.factions.includes(FactionNames.BitRunners);
}, },
}, },
{ {
title: "Install all the Augmentations from BitRunners", title: `Install all the Augmentations from ${FactionNames.BitRunners}`,
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return allFactionAugs(p, Factions["BitRunners"]); return allFactionAugs(p, Factions[FactionNames.BitRunners]);
}, },
}, },
{ {
title: "Complete fl1ght.exe", title: "Complete fl1ght.exe",
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
// technically wrong but whatever // technically wrong but whatever
return p.factions.includes("Daedalus"); return p.factions.includes(FactionNames.Daedalus);
}, },
}, },
{ {
title: "Install the special Augmentation from Daedalus", title: `Install the special Augmentation from ${FactionNames.Daedalus}`,
fulfilled: (p: IPlayer): boolean => { fulfilled: (p: IPlayer): boolean => {
return p.augmentations.some((aug) => aug.name == "The Red Pill"); return p.augmentations.some((aug) => aug.name == "The Red Pill");
}, },

@ -181,6 +181,8 @@ export const RamCosts: IMap<any> = {
getForecast: RamCostConstants.ScriptBuySellStockRamCost, getForecast: RamCostConstants.ScriptBuySellStockRamCost,
purchase4SMarketData: RamCostConstants.ScriptBuySellStockRamCost, purchase4SMarketData: RamCostConstants.ScriptBuySellStockRamCost,
purchase4SMarketDataTixApi: RamCostConstants.ScriptBuySellStockRamCost, purchase4SMarketDataTixApi: RamCostConstants.ScriptBuySellStockRamCost,
purchaseWseAccount: RamCostConstants.ScriptBuySellStockRamCost,
purchaseTixApi: RamCostConstants.ScriptBuySellStockRamCost,
}, },
getPurchasedServerLimit: RamCostConstants.ScriptGetPurchasedServerLimit, getPurchasedServerLimit: RamCostConstants.ScriptGetPurchasedServerLimit,
getPurchasedServerMaxRam: RamCostConstants.ScriptGetPurchasedServerMaxRam, getPurchasedServerMaxRam: RamCostConstants.ScriptGetPurchasedServerMaxRam,

@ -1,3 +1,5 @@
import { FactionNames } from '../Faction/data/FactionNames';
import { GangConstants } from '../Gang/data/Constants';
import { INetscriptHelper } from "./INetscriptHelper"; import { INetscriptHelper } from "./INetscriptHelper";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { getRamCost } from "../Netscript/RamCostGenerator"; import { getRamCost } from "../Netscript/RamCostGenerator";
@ -49,20 +51,12 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
createGang: function (faction: string): boolean { createGang: function (faction: string): boolean {
helper.updateDynamicRam("createGang", getRamCost(player, "gang", "createGang")); helper.updateDynamicRam("createGang", getRamCost(player, "gang", "createGang"));
// this list is copied from Faction/ui/Root.tsx // this list is copied from Faction/ui/Root.tsx
const GangNames = [
"Slum Snakes", if (!player.canAccessGang() || !GangConstants.Names.includes(faction)) return false;
"Tetrads",
"The Syndicate",
"The Dark Army",
"Speakers for the Dead",
"NiteSec",
"The Black Hand",
];
if (!player.canAccessGang() || !GangNames.includes(faction)) return false;
if (player.inGang()) return false; if (player.inGang()) return false;
if (!player.factions.includes(faction)) return false; if (!player.factions.includes(faction)) return false;
const isHacking = faction === "NiteSec" || faction === "The Black Hand"; const isHacking = faction === FactionNames.NiteSec || faction === FactionNames.TheBlackHand;
player.startGang(faction, isHacking); player.startGang(faction, isHacking);
return true; return true;
}, },

@ -42,6 +42,7 @@ import { Terminal } from "../Terminal";
import { calculateHackingTime } from "../Hacking"; import { calculateHackingTime } from "../Hacking";
import { Server } from "../Server/Server"; import { Server } from "../Server/Server";
import { netscriptCanHack } from "../Hacking/netscriptCanHack"; import { netscriptCanHack } from "../Hacking/netscriptCanHack";
import { FactionNames } from "../Faction/data/FactionNames";
export function NetscriptSingularity( export function NetscriptSingularity(
player: IPlayer, player: IPlayer,
@ -282,7 +283,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
() => "You cannot study at 'Summit University' because you are not in 'Aevum'.", () => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`,
); );
return false; return false;
} }
@ -294,7 +295,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
() => "You cannot study at 'Rothman University' because you are not in 'Sector-12'.", () => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`,
); );
return false; return false;
} }
@ -306,7 +307,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
() => "You cannot study at 'ZB Institute of Technology' because you are not in 'Volhaven'.", () => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`,
); );
return false; return false;
} }
@ -369,7 +370,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
() => "You cannot workout at 'Crush Fitness' because you are not in 'Aevum'.", () => `You cannot workout at '${LocationName.AevumCrushFitnessGym}' because you are not in '${CityName.Aevum}'.`,
); );
return false; return false;
} }
@ -381,7 +382,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
() => "You cannot workout at 'Snap Fitness' because you are not in 'Aevum'.", () => `You cannot workout at '${LocationName.AevumSnapFitnessGym}' because you are not in '${CityName.Aevum}'.`,
); );
return false; return false;
} }
@ -393,7 +394,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
() => "You cannot workout at 'Iron Gym' because you are not in 'Sector-12'.", () => `You cannot workout at '${LocationName.Sector12IronGym}' because you are not in '${CityName.Sector12}'.`,
); );
return false; return false;
} }
@ -405,7 +406,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
() => "You cannot workout at 'Powerhouse Gym' because you are not in 'Sector-12'.", () => `You cannot workout at '${LocationName.Sector12PowerhouseGym}' because you are not in '${CityName.Sector12}'.`,
); );
return false; return false;
} }
@ -417,7 +418,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
() => "You cannot workout at 'Millenium Fitness Gym' because you are not in 'Volhaven'.", () => `You cannot workout at '${LocationName.VolhavenMilleniumFitnessGym}' because you are not in '${CityName.Volhaven}'.`,
); );
return false; return false;
} }
@ -1033,85 +1034,85 @@ export function NetscriptSingularity(
const fac = Factions[name]; const fac = Factions[name];
// Arrays listing factions that allow each time of work // Arrays listing factions that allow each time of work
const hackAvailable = [ const hackAvailable = [
"Illuminati", FactionNames.Illuminati as string,
"Daedalus", FactionNames.Daedalus as string,
"The Covenant", FactionNames.TheCovenant as string,
"ECorp", FactionNames.ECorp as string,
"MegaCorp", FactionNames.MegaCorp as string,
"Bachman & Associates", FactionNames.BachmanAssociates as string,
"Blade Industries", FactionNames.Bladeburners as string,
"NWO", FactionNames.NWO as string,
"Clarke Incorporated", FactionNames.ClarkeIncorporated as string,
"OmniTek Incorporated", FactionNames.OmniTekIncorporated as string,
"Four Sigma", FactionNames.FourSigma as string,
"KuaiGong International", FactionNames.KuaiGongInternational as string,
"Fulcrum Secret Technologies", FactionNames.FulcrumSecretTechnologies as string,
"BitRunners", FactionNames.BitRunners as string,
"The Black Hand", FactionNames.TheBlackHand as string,
"NiteSec", FactionNames.NiteSec as string,
"Chongqing", FactionNames.Chongqing as string,
"Sector-12", FactionNames.Sector12 as string,
"New Tokyo", FactionNames.NewTokyo as string,
"Aevum", FactionNames.Aevum as string,
"Ishima", FactionNames.Ishima as string,
"Volhaven", FactionNames.Volhaven as string,
"Speakers for the Dead", FactionNames.SpeakersForTheDead as string,
"The Dark Army", FactionNames.TheDarkArmy as string,
"The Syndicate", FactionNames.TheSyndicate as string,
"Silhouette", FactionNames.Silhouette as string,
"Netburners", FactionNames.Netburners as string,
"Tian Di Hui", FactionNames.TianDiHui as string,
"CyberSec", FactionNames.CyberSec as string,
]; ];
const fdWkAvailable = [ const fdWkAvailable = [
"Illuminati", FactionNames.Illuminati as string,
"Daedalus", FactionNames.Daedalus as string,
"The Covenant", FactionNames.TheCovenant as string,
"ECorp", FactionNames.ECorp as string,
"MegaCorp", FactionNames.MegaCorp as string,
"Bachman & Associates", FactionNames.BachmanAssociates as string,
"Blade Industries", FactionNames.Bladeburners as string,
"NWO", FactionNames.NWO as string,
"Clarke Incorporated", FactionNames.ClarkeIncorporated as string,
"OmniTek Incorporated", FactionNames.OmniTekIncorporated as string,
"Four Sigma", FactionNames.FourSigma as string,
"KuaiGong International", FactionNames.KuaiGongInternational as string,
"The Black Hand", FactionNames.TheBlackHand as string,
"Chongqing", FactionNames.Chongqing as string,
"Sector-12", FactionNames.Sector12 as string,
"New Tokyo", FactionNames.NewTokyo as string,
"Aevum", FactionNames.Aevum as string,
"Ishima", FactionNames.Ishima as string,
"Volhaven", FactionNames.Volhaven as string,
"Speakers for the Dead", FactionNames.SpeakersForTheDead as string,
"The Dark Army", FactionNames.TheDarkArmy as string,
"The Syndicate", FactionNames.TheSyndicate as string,
"Silhouette", FactionNames.Silhouette as string,
"Tetrads", FactionNames.Tetrads as string,
"Slum Snakes", FactionNames.SlumSnakes as string,
]; ];
const scWkAvailable = [ const scWkAvailable = [
"ECorp", FactionNames.ECorp as string,
"MegaCorp", FactionNames.MegaCorp as string,
"Bachman & Associates", FactionNames.BachmanAssociates as string,
"Blade Industries", FactionNames.Bladeburners as string,
"NWO", FactionNames.NWO as string,
"Clarke Incorporated", FactionNames.ClarkeIncorporated as string,
"OmniTek Incorporated", FactionNames.OmniTekIncorporated as string,
"Four Sigma", FactionNames.FourSigma as string,
"KuaiGong International", FactionNames.KuaiGongInternational as string,
"Fulcrum Secret Technologies", FactionNames.FulcrumSecretTechnologies as string,
"Chongqing", FactionNames.Chongqing as string,
"Sector-12", FactionNames.Sector12 as string,
"New Tokyo", FactionNames.NewTokyo as string,
"Aevum", FactionNames.Aevum as string,
"Ishima", FactionNames.Ishima as string,
"Volhaven", FactionNames.Volhaven as string,
"Speakers for the Dead", FactionNames.SpeakersForTheDead as string,
"The Syndicate", FactionNames.TheSyndicate as string,
"Tetrads", FactionNames.Tetrads as string,
"Slum Snakes", FactionNames.SlumSnakes as string,
"Tian Di Hui", FactionNames.TianDiHui as string,
]; ];
switch (type.toLowerCase()) { switch (type.toLowerCase()) {

@ -8,7 +8,7 @@ import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/St
import { OrderTypes } from "../StockMarket/data/OrderTypes"; import { OrderTypes } from "../StockMarket/data/OrderTypes";
import { PositionTypes } from "../StockMarket/data/PositionTypes"; import { PositionTypes } from "../StockMarket/data/PositionTypes";
import { StockSymbols } from "../StockMarket/data/StockSymbols"; import { StockSymbols } from "../StockMarket/data/StockSymbols";
import { getStockMarket4SDataCost, getStockMarket4STixApiCost } from "../StockMarket/StockMarketCosts"; import { getStockMarket4SDataCost, getStockMarket4STixApiCost, getStockMarketWseCost, getStockMarketTixApiCost } from "../StockMarket/StockMarketCosts";
import { Stock } from "../StockMarket/Stock"; import { Stock } from "../StockMarket/Stock";
import { TIX } from "../ScriptEditor/NetscriptDefinitions"; import { TIX } from "../ScriptEditor/NetscriptDefinitions";
@ -388,5 +388,47 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API"); workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API");
return true; return true;
}, },
purchaseWseAccount: function (): boolean {
helper.updateDynamicRam("PurchaseWseAccount", getRamCost(player, "stock", "purchaseWseAccount"));
if (player.hasWseAccount) {
workerScript.log("stock.purchaseWseAccount", () => "Already purchased WSE Account");
return true;
}
if (player.money < getStockMarketWseCost()) {
workerScript.log(
"stock.purchaseWseAccount",
() => "Not enough money to purchase WSE Account Access",
);
return false;
}
player.hasWseAccount = true;
player.loseMoney(getStockMarketWseCost(), "stock");
workerScript.log("stock.purchaseWseAccount", () => "Purchased WSE Account Access");
return true;
},
purchaseTixApi: function (): boolean {
helper.updateDynamicRam("purchaseTixApi", getRamCost(player, "stock", "purchaseTixApi"));
if (player.hasTixApiAccess) {
workerScript.log("stock.purchaseTixApi", () => "Already purchased TIX API");
return true;
}
if (player.money < getStockMarketTixApiCost()) {
workerScript.log(
"stock.purchaseTixApi",
() => "Not enough money to purchase TIX API Access",
);
return false;
}
player.hasTixApiAccess = true;
player.loseMoney(getStockMarketTixApiCost(), "stock");
workerScript.log("stock.purchaseTixApi", () => "Purchased TIX API");
return true;
},
}; };
} }

@ -65,6 +65,7 @@ import { serverMetadata } from "../../Server/data/servers";
import { SnackbarEvents } from "../../ui/React/Snackbar"; import { SnackbarEvents } from "../../ui/React/Snackbar";
import { calculateClassEarnings } from "../formulas/work"; import { calculateClassEarnings } from "../formulas/work";
import { achievements } from "../../Achievements/Achievements"; import { achievements } from "../../Achievements/Achievements";
import { FactionNames } from "../../Faction/data/FactionNames";
export function init(this: IPlayer): void { export function init(this: IPlayer): void {
/* Initialize Player's home computer */ /* Initialize Player's home computer */
@ -615,8 +616,8 @@ export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
router.toGrafting(); router.toGrafting();
} }
} else if (this.work(numCycles)) { } else if (this.work(numCycles)) {
router.toCity(); router.toCity();
} }
} }
} }
@ -1565,20 +1566,20 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) { if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log( ws.scriptRef.log(
"SUCCESS: Crime successful! Gained " + "SUCCESS: Crime successful! Gained " +
numeralWrapper.formatMoney(this.workMoneyGained) + numeralWrapper.formatMoney(this.workMoneyGained) +
", " + ", " +
numeralWrapper.formatExp(this.workHackExpGained) + numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " + " hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) + numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " + " str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) + numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " + " def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) + numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " + " dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) + numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " + " agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) + numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.", " cha exp.",
); );
} }
} else { } else {
@ -1617,18 +1618,18 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) { if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log( ws.scriptRef.log(
"FAIL: Crime failed! Gained " + "FAIL: Crime failed! Gained " +
numeralWrapper.formatExp(this.workHackExpGained) + numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " + " hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) + numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " + " str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) + numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " + " def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) + numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " + " dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) + numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " + " agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) + numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.", " cha exp.",
); );
} }
} else { } else {
@ -1811,7 +1812,6 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
} }
return false; return false;
} }
return false; //Same job, do nothing
} }
} }
@ -2144,7 +2144,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Illuminati //Illuminati
const illuminatiFac = Factions["Illuminati"]; const illuminatiFac = Factions[FactionNames.Illuminati];
if ( if (
!illuminatiFac.isBanned && !illuminatiFac.isBanned &&
!illuminatiFac.isMember && !illuminatiFac.isMember &&
@ -2161,7 +2161,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Daedalus //Daedalus
const daedalusFac = Factions["Daedalus"]; const daedalusFac = Factions[FactionNames.Daedalus];
if ( if (
!daedalusFac.isBanned && !daedalusFac.isBanned &&
!daedalusFac.isMember && !daedalusFac.isMember &&
@ -2175,7 +2175,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//The Covenant //The Covenant
const covenantFac = Factions["The Covenant"]; const covenantFac = Factions[FactionNames.TheCovenant];
if ( if (
!covenantFac.isBanned && !covenantFac.isBanned &&
!covenantFac.isMember && !covenantFac.isMember &&
@ -2192,7 +2192,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//ECorp //ECorp
const ecorpFac = Factions["ECorp"]; const ecorpFac = Factions[FactionNames.ECorp];
if ( if (
!ecorpFac.isBanned && !ecorpFac.isBanned &&
!ecorpFac.isMember && !ecorpFac.isMember &&
@ -2203,7 +2203,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//MegaCorp //MegaCorp
const megacorpFac = Factions["MegaCorp"]; const megacorpFac = Factions[FactionNames.MegaCorp];
if ( if (
!megacorpFac.isBanned && !megacorpFac.isBanned &&
!megacorpFac.isMember && !megacorpFac.isMember &&
@ -2214,7 +2214,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Bachman & Associates //Bachman & Associates
const bachmanandassociatesFac = Factions["Bachman & Associates"]; const bachmanandassociatesFac = Factions[FactionNames.BachmanAssociates];
if ( if (
!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isBanned &&
!bachmanandassociatesFac.isMember && !bachmanandassociatesFac.isMember &&
@ -2225,7 +2225,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Blade Industries //Blade Industries
const bladeindustriesFac = Factions["Blade Industries"]; const bladeindustriesFac = Factions[FactionNames.BladeIndustries];
if ( if (
!bladeindustriesFac.isBanned && !bladeindustriesFac.isBanned &&
!bladeindustriesFac.isMember && !bladeindustriesFac.isMember &&
@ -2236,7 +2236,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//NWO //NWO
const nwoFac = Factions["NWO"]; const nwoFac = Factions[FactionNames.NWO];
if ( if (
!nwoFac.isBanned && !nwoFac.isBanned &&
!nwoFac.isMember && !nwoFac.isMember &&
@ -2247,7 +2247,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Clarke Incorporated //Clarke Incorporated
const clarkeincorporatedFac = Factions["Clarke Incorporated"]; const clarkeincorporatedFac = Factions[FactionNames.ClarkeIncorporated];
if ( if (
!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isBanned &&
!clarkeincorporatedFac.isMember && !clarkeincorporatedFac.isMember &&
@ -2258,7 +2258,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//OmniTek Incorporated //OmniTek Incorporated
const omnitekincorporatedFac = Factions["OmniTek Incorporated"]; const omnitekincorporatedFac = Factions[FactionNames.OmniTekIncorporated];
if ( if (
!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isBanned &&
!omnitekincorporatedFac.isMember && !omnitekincorporatedFac.isMember &&
@ -2269,7 +2269,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Four Sigma //Four Sigma
const foursigmaFac = Factions["Four Sigma"]; const foursigmaFac = Factions[FactionNames.FourSigma];
if ( if (
!foursigmaFac.isBanned && !foursigmaFac.isBanned &&
!foursigmaFac.isMember && !foursigmaFac.isMember &&
@ -2280,7 +2280,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//KuaiGong International //KuaiGong International
const kuaigonginternationalFac = Factions["KuaiGong International"]; const kuaigonginternationalFac = Factions[FactionNames.KuaiGongInternational];
if ( if (
!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isBanned &&
!kuaigonginternationalFac.isMember && !kuaigonginternationalFac.isMember &&
@ -2291,27 +2291,27 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company
const fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; const fulcrumsecrettechonologiesFac = Factions[FactionNames.FulcrumSecretTechnologies];
const fulcrumSecretServer = GetServer(SpecialServers.FulcrumSecretTechnologies); const fulcrumSecretServer = GetServer(SpecialServers.FulcrumSecretTechnologies);
if (!(fulcrumSecretServer instanceof Server)) throw new Error("Fulcrum Secret Technologies should be normal server"); if (!(fulcrumSecretServer instanceof Server)) throw new Error(`${FactionNames.FulcrumSecretTechnologies} should be normal server`);
if (fulcrumSecretServer == null) { if (fulcrumSecretServer == null) {
console.error("Could not find Fulcrum Secret Technologies Server"); console.error(`Could not find ${FactionNames.FulcrumSecretTechnologies} Server`);
} else if ( } else if (
!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isBanned &&
!fulcrumsecrettechonologiesFac.isMember && !fulcrumsecrettechonologiesFac.isMember &&
!fulcrumsecrettechonologiesFac.alreadyInvited && !fulcrumsecrettechonologiesFac.alreadyInvited &&
fulcrumSecretServer.backdoorInstalled && fulcrumSecretServer.backdoorInstalled &&
checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3) checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)
) { ) {
invitedFactions.push(fulcrumsecrettechonologiesFac); invitedFactions.push(fulcrumsecrettechonologiesFac);
} }
//BitRunners //BitRunners
const bitrunnersFac = Factions["BitRunners"]; const bitrunnersFac = Factions[FactionNames.BitRunners];
const bitrunnersServer = GetServer(SpecialServers.BitRunnersServer); const bitrunnersServer = GetServer(SpecialServers.BitRunnersServer);
if (!(bitrunnersServer instanceof Server)) throw new Error("BitRunners should be normal server"); if (!(bitrunnersServer instanceof Server)) throw new Error(`${FactionNames.BitRunners} should be normal server`);
if (bitrunnersServer == null) { if (bitrunnersServer == null) {
console.error("Could not find BitRunners Server"); console.error(`Could not find ${FactionNames.BitRunners} Server`);
} else if ( } else if (
!bitrunnersFac.isBanned && !bitrunnersFac.isBanned &&
!bitrunnersFac.isMember && !bitrunnersFac.isMember &&
@ -2323,11 +2323,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
//The Black Hand //The Black Hand
const theblackhandFac = Factions["The Black Hand"]; const theblackhandFac = Factions[FactionNames.TheBlackHand];
const blackhandServer = GetServer(SpecialServers.TheBlackHandServer); const blackhandServer = GetServer(SpecialServers.TheBlackHandServer);
if (!(blackhandServer instanceof Server)) throw new Error("TheBlackHand should be normal server"); if (!(blackhandServer instanceof Server)) throw new Error(`${FactionNames.TheBlackHand} should be normal server`);
if (blackhandServer == null) { if (blackhandServer == null) {
console.error("Could not find The Black Hand Server"); console.error(`Could not find ${FactionNames.TheBlackHand} Server`);
} else if ( } else if (
!theblackhandFac.isBanned && !theblackhandFac.isBanned &&
!theblackhandFac.isMember && !theblackhandFac.isMember &&
@ -2338,11 +2338,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//NiteSec //NiteSec
const nitesecFac = Factions["NiteSec"]; const nitesecFac = Factions[FactionNames.NiteSec];
const nitesecServer = GetServer(SpecialServers.NiteSecServer); const nitesecServer = GetServer(SpecialServers.NiteSecServer);
if (!(nitesecServer instanceof Server)) throw new Error("NiteSec should be normal server"); if (!(nitesecServer instanceof Server)) throw new Error(`${FactionNames.NiteSec} should be normal server`);
if (nitesecServer == null) { if (nitesecServer == null) {
console.error("Could not find NiteSec Server"); console.error(`Could not find ${FactionNames.NiteSec} Server`);
} else if ( } else if (
!nitesecFac.isBanned && !nitesecFac.isBanned &&
!nitesecFac.isMember && !nitesecFac.isMember &&
@ -2353,7 +2353,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Chongqing //Chongqing
const chongqingFac = Factions["Chongqing"]; const chongqingFac = Factions[FactionNames.Chongqing];
if ( if (
!chongqingFac.isBanned && !chongqingFac.isBanned &&
!chongqingFac.isMember && !chongqingFac.isMember &&
@ -2365,7 +2365,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Sector-12 //Sector-12
const sector12Fac = Factions["Sector-12"]; const sector12Fac = Factions[FactionNames.Sector12];
if ( if (
!sector12Fac.isBanned && !sector12Fac.isBanned &&
!sector12Fac.isMember && !sector12Fac.isMember &&
@ -2377,7 +2377,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//New Tokyo //New Tokyo
const newtokyoFac = Factions["New Tokyo"]; const newtokyoFac = Factions[FactionNames.NewTokyo];
if ( if (
!newtokyoFac.isBanned && !newtokyoFac.isBanned &&
!newtokyoFac.isMember && !newtokyoFac.isMember &&
@ -2389,7 +2389,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Aevum //Aevum
const aevumFac = Factions["Aevum"]; const aevumFac = Factions[FactionNames.Aevum];
if ( if (
!aevumFac.isBanned && !aevumFac.isBanned &&
!aevumFac.isMember && !aevumFac.isMember &&
@ -2401,7 +2401,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Ishima //Ishima
const ishimaFac = Factions["Ishima"]; const ishimaFac = Factions[FactionNames.Ishima];
if ( if (
!ishimaFac.isBanned && !ishimaFac.isBanned &&
!ishimaFac.isMember && !ishimaFac.isMember &&
@ -2413,7 +2413,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Volhaven //Volhaven
const volhavenFac = Factions["Volhaven"]; const volhavenFac = Factions[FactionNames.Volhaven];
if ( if (
!volhavenFac.isBanned && !volhavenFac.isBanned &&
!volhavenFac.isMember && !volhavenFac.isMember &&
@ -2425,7 +2425,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Speakers for the Dead //Speakers for the Dead
const speakersforthedeadFac = Factions["Speakers for the Dead"]; const speakersforthedeadFac = Factions[FactionNames.SpeakersForTheDead];
if ( if (
!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isBanned &&
!speakersforthedeadFac.isMember && !speakersforthedeadFac.isMember &&
@ -2444,7 +2444,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//The Dark Army //The Dark Army
const thedarkarmyFac = Factions["The Dark Army"]; const thedarkarmyFac = Factions[FactionNames.TheDarkArmy];
if ( if (
!thedarkarmyFac.isBanned && !thedarkarmyFac.isBanned &&
!thedarkarmyFac.isMember && !thedarkarmyFac.isMember &&
@ -2464,7 +2464,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//The Syndicate //The Syndicate
const thesyndicateFac = Factions["The Syndicate"]; const thesyndicateFac = Factions[FactionNames.TheSyndicate];
if ( if (
!thesyndicateFac.isBanned && !thesyndicateFac.isBanned &&
!thesyndicateFac.isMember && !thesyndicateFac.isMember &&
@ -2484,7 +2484,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Silhouette //Silhouette
const silhouetteFac = Factions["Silhouette"]; const silhouetteFac = Factions[FactionNames.Silhouette];
if ( if (
!silhouetteFac.isBanned && !silhouetteFac.isBanned &&
!silhouetteFac.isMember && !silhouetteFac.isMember &&
@ -2499,7 +2499,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Tetrads //Tetrads
const tetradsFac = Factions["Tetrads"]; const tetradsFac = Factions[FactionNames.Tetrads];
if ( if (
!tetradsFac.isBanned && !tetradsFac.isBanned &&
!tetradsFac.isMember && !tetradsFac.isMember &&
@ -2515,7 +2515,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//SlumSnakes //SlumSnakes
const slumsnakesFac = Factions["Slum Snakes"]; const slumsnakesFac = Factions[FactionNames.SlumSnakes];
if ( if (
!slumsnakesFac.isBanned && !slumsnakesFac.isBanned &&
!slumsnakesFac.isMember && !slumsnakesFac.isMember &&
@ -2531,7 +2531,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Netburners //Netburners
const netburnersFac = Factions["Netburners"]; const netburnersFac = Factions[FactionNames.Netburners];
let totalHacknetRam = 0; let totalHacknetRam = 0;
let totalHacknetCores = 0; let totalHacknetCores = 0;
let totalHacknetLevels = 0; let totalHacknetLevels = 0;
@ -2563,7 +2563,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//Tian Di Hui //Tian Di Hui
const tiandihuiFac = Factions["Tian Di Hui"]; const tiandihuiFac = Factions[FactionNames.TianDiHui];
if ( if (
!tiandihuiFac.isBanned && !tiandihuiFac.isBanned &&
!tiandihuiFac.isMember && !tiandihuiFac.isMember &&
@ -2576,11 +2576,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
} }
//CyberSec //CyberSec
const cybersecFac = Factions["CyberSec"]; const cybersecFac = Factions[FactionNames.CyberSec];
const cybersecServer = GetServer(SpecialServers.CyberSecServer); const cybersecServer = GetServer(SpecialServers.CyberSecServer);
if (!(cybersecServer instanceof Server)) throw new Error("cybersec should be normal server"); if (!(cybersecServer instanceof Server)) throw new Error(`${FactionNames.CyberSec} should be normal server`);
if (cybersecServer == null) { if (cybersecServer == null) {
console.error("Could not find CyberSec Server"); console.error(`Could not find ${FactionNames.CyberSec} Server`);
} else if ( } else if (
!cybersecFac.isBanned && !cybersecFac.isBanned &&
!cybersecFac.isMember && !cybersecFac.isMember &&
@ -2637,7 +2637,7 @@ export function gainCodingContractReward(this: IPlayer, reward: ICodingContractR
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty; const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty;
// Ignore Bladeburners and other special factions for this calculation // Ignore Bladeburners and other special factions for this calculation
const specialFactions = ["Bladeburners"]; const specialFactions = [FactionNames.Bladeburners as string];
const factions = this.factions.slice().filter((f) => { const factions = this.factions.slice().filter((f) => {
return !specialFactions.includes(f); return !specialFactions.includes(f);
}); });
@ -2656,7 +2656,6 @@ export function gainCodingContractReward(this: IPlayer, reward: ICodingContractR
Factions[facName].playerReputation += gainPerFaction; Factions[facName].playerReputation += gainPerFaction;
} }
return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`; return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`;
break;
case CodingContractRewardType.CompanyReputation: { case CodingContractRewardType.CompanyReputation: {
if (reward.name == null || !(Companies[reward.name] instanceof Company)) { if (reward.name == null || !(Companies[reward.name] instanceof Company)) {
//If no/invalid company was designated, just give rewards to all factions //If no/invalid company was designated, just give rewards to all factions

@ -1,3 +1,4 @@
import { FactionNames } from '../../Faction/data/FactionNames';
import { Sleeve } from "./Sleeve"; import { Sleeve } from "./Sleeve";
import { IPlayer } from "../IPlayer"; import { IPlayer } from "../IPlayer";
@ -80,10 +81,10 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
} }
for (const facName of p.factions) { for (const facName of p.factions) {
if (facName === "Bladeburners") { if (facName === FactionNames.Bladeburners) {
continue; continue;
} }
if (facName === "Netburners") { if (facName === FactionNames.Netburners) {
continue; continue;
} }
const fac: Faction | null = Factions[facName]; const fac: Faction | null = Factions[facName];

@ -16,6 +16,7 @@ import { use } from "../../../ui/Context";
import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { FactionNames } from "../../../Faction/data/FactionNames";
interface IProps { interface IProps {
open: boolean; open: boolean;
@ -76,7 +77,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
<> <>
<Typography> <Typography>
Purchase an additional Sleeves. These Duplicate Sleeves are permanent (they persist through BitNodes). You Purchase an additional Sleeves. These Duplicate Sleeves are permanent (they persist through BitNodes). You
can purchase a total of {MaxSleevesFromCovenant} from The Covenant. can purchase a total of {MaxSleevesFromCovenant} from {FactionNames.TheCovenant}.
</Typography> </Typography>
<Button disabled={purchaseDisabled} onClick={purchaseOnClick}> <Button disabled={purchaseDisabled} onClick={purchaseOnClick}>
Purchase -&nbsp; Purchase -&nbsp;

@ -2,6 +2,7 @@ import React from "react";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { FactionNames } from "../../../Faction/data/FactionNames";
interface IProps { interface IProps {
open: boolean; open: boolean;
@ -90,7 +91,7 @@ export function FAQModal({ open, onClose }: IProps): React.ReactElement {
<Typography variant="h4">Why can't I buy the X Augmentation for my sleeve?</Typography> <Typography variant="h4">Why can't I buy the X Augmentation for my sleeve?</Typography>
<br /> <br />
<Typography> <Typography>
Certain Augmentations, like Bladeburner-specific ones and NeuroFlux Governor, are not available for sleeves. Certain Augmentations, like {FactionNames.Bladeburners}-specific ones and NeuroFlux Governor, are not available for sleeves.
</Typography> </Typography>
<br /> <br />
<br /> <br />
@ -109,7 +110,7 @@ export function FAQModal({ open, onClose }: IProps): React.ReactElement {
<br /> <br />
<br /> <br />
<Typography> <Typography>
Memory can only be increased by purchasing upgrades from The Covenant. It is a persistent stat, meaning it Memory can only be increased by purchasing upgrades from {FactionNames.TheCovenant}. It is a persistent stat, meaning it
never gets resets back to 1. The maximum possible value for a sleeve's memory is 100. never gets resets back to 1. The maximum possible value for a sleeve's memory is 100.
</Typography> </Typography>
</> </>

@ -50,74 +50,62 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
return ( return (
<Modal open={props.open} onClose={props.onClose}> <Modal open={props.open} onClose={props.onClose}>
<> <>
<Typography> <Box sx={{ mx: 1 }}>
You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they <Typography>
would for you. You can only purchase Augmentations that you have unlocked through Factions. You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they
<br /> would for you. You can only purchase Augmentations that you have unlocked through Factions.
<br /> <br />
When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the <br />
Duplicate Sleeve will immediately lose all of its stat experience. When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the
</Typography> Duplicate Sleeve will immediately lose all of its stat experience.
<Table size="small" padding="none"> </Typography>
<TableBody> <Box component={Paper} sx={{ my: 1, p: 1 }}>
{availableAugs.map((aug) => { <Table size="small" padding="none">
return ( <TableBody>
<TableRow key={aug.name}> {availableAugs.map((aug) => {
<TableCell> return (
<Button onClick={() => purchaseAugmentation(aug)} disabled={player.money < aug.startingCost}> <TableRow key={aug.name}>
Buy <TableCell>
</Button> <Button onClick={() => purchaseAugmentation(aug)} disabled={player.money < aug.startingCost}>
</TableCell> Buy
<TableCell> </Button>
<Box display="flex"> </TableCell>
<Tooltip title={aug.stats || ""}> <TableCell>
<Typography>{aug.name}</Typography> <Box display="flex">
</Tooltip> <Tooltip title={aug.stats || ""}>
</Box> <Typography>{aug.name}</Typography>
</TableCell> </Tooltip>
<TableCell> </Box>
<Money money={aug.startingCost} player={player} /> </TableCell>
</TableCell> <TableCell>
</TableRow> <Money money={aug.startingCost} player={player} />
); </TableCell>
})} </TableRow>
</TableBody> );
</Table> })}
</TableBody>
</Table>
</Box>
</Box>
{ownedAugNames.length > 0 && ( {ownedAugNames.length > 0 && (
<> <>
<Typography>Owned Augmentations:</Typography> <Typography sx={{ mx: 1 }}>Owned Augmentations:</Typography>
{ownedAugNames.map((augName) => { <Box display="grid" sx={{ gridTemplateColumns: 'repeat(5, 1fr)', m: 1 }}>
const aug = Augmentations[augName]; {ownedAugNames.map((augName) => {
let tooltip = <></>; const aug = Augmentations[augName];
if (typeof aug.info === "string") { const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info
tooltip = ( const tooltip = (<>{info}<br /><br />{aug.stats}</>);
<>
<span>{aug.info}</span>
<br />
<br />
{aug.stats}
</>
);
} else {
tooltip = (
<>
{aug.info}
<br />
<br />
{aug.stats}
</>
);
}
return ( return (
<Tooltip key={augName} title={<Typography>{tooltip}</Typography>}> <Tooltip key={augName} title={<Typography>{tooltip}</Typography>}>
<Paper> <Paper sx={{ p: 1 }}>
<Typography>{augName}</Typography> <Typography>{augName}</Typography>
</Paper> </Paper>
</Tooltip> </Tooltip>
); );
})} })}
</Box>
</> </>
)} )}
</> </>

@ -1,34 +1,29 @@
import React, { useState } from "react"; import React, { useState } from "react";
import {
Box,
Paper,
Typography,
Button,
Tooltip
} from "@mui/material";
import { CONSTANTS } from "../../../Constants";
import { Crimes } from "../../../Crime/Crimes";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import { use } from "../../../ui/Context";
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { SleeveTaskType } from "../SleeveTaskTypesEnum"; import { SleeveTaskType } from "../SleeveTaskTypesEnum";
import { CONSTANTS } from "../../../Constants";
import { Crimes } from "../../../Crime/Crimes";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal"; import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal";
import { TravelModal } from "./TravelModal"; import { TravelModal } from "./TravelModal";
import { Money } from "../../../ui/React/Money"; import { StatsElement, EarningsElement } from "./StatsElement";
import { MoneyRate } from "../../../ui/React/MoneyRate";
import { use } from "../../../ui/Context";
import { ReputationRate } from "../../../ui/React/ReputationRate";
import { StatsElement } from "./StatsElement";
import { MoreStatsModal } from "./MoreStatsModal"; import { MoreStatsModal } from "./MoreStatsModal";
import { MoreEarningsModal } from "./MoreEarningsModal"; import { MoreEarningsModal } from "./MoreEarningsModal";
import { TaskSelector } from "./TaskSelector"; import { TaskSelector } from "./TaskSelector";
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
import { StatsTable } from "../../../ui/React/StatsTable";
import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
import Grid from "@mui/material/Grid";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
interface IProps { interface IProps {
sleeve: Sleeve; sleeve: Sleeve;
@ -141,86 +136,71 @@ export function SleeveElem(props: IProps): React.ReactElement {
console.error(`Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${abc[0]}`); console.error(`Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${abc[0]}`);
} }
let data: any[][] = [];
if (props.sleeve.currentTask === SleeveTaskType.Crime) {
data = [
[`Money`, <Money money={parseFloat(props.sleeve.currentTaskLocation)} />, `(on success)`],
[`Hacking Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.hack), `(2x on success)`],
[`Strength Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.str), `(2x on success)`],
[`Defense Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.def), `(2x on success)`],
[`Dexterity Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.dex), `(2x on success)`],
[`Agility Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.agi), `(2x on success)`],
[`Charisma Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.cha), `(2x on success)`],
];
} else {
data = [
[`Money:`, <MoneyRate money={5 * props.sleeve.gainRatesForTask.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.hack)} / s`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.str)} / s`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.def)} / s`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.dex)} / s`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.agi)} / s`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.cha)} / s`],
];
if (props.sleeve.currentTask === SleeveTaskType.Company || props.sleeve.currentTask === SleeveTaskType.Faction) {
const repGain: number = props.sleeve.getRepGain(player);
data.push([`Reputation:`, <ReputationRate reputation={5 * repGain} />]);
}
}
return ( return (
<> <Box component={Paper} sx={{ width: 'auto' }}>
<Grid container component={Paper}> <Box sx={{ m: 1 }}>
<Grid item xs={3}> <Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: '100%', gap: 1 }}>
<StatsElement sleeve={props.sleeve} /> <Box>
<Button onClick={() => setStatsOpen(true)}>More Stats</Button> <StatsElement sleeve={props.sleeve} />
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}> <Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: '100%' }}>
<span> <Button onClick={() => setStatsOpen(true)}>More Stats</Button>
<Button onClick={() => setTravelOpen(true)} disabled={player.money < CONSTANTS.TravelCost}> <Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
Travel <Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
</Button> <span>
</span> <Button
</Tooltip> onClick={() => setTravelOpen(true)}
<Tooltip disabled={player.money < CONSTANTS.TravelCost}
title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""} sx={{ width: '100%', height: '100%' }}
> >
<span> Travel
<Button onClick={() => setAugmentationsOpen(true)} disabled={props.sleeve.shock < 100}> </Button>
Manage Augmentations </span>
</Button> </Tooltip>
</span> <Tooltip
</Tooltip> title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
</Grid> >
<Grid item xs={5}> <span>
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} /> <Button
<Typography>{desc}</Typography> onClick={() => setAugmentationsOpen(true)}
<Typography> disabled={props.sleeve.shock < 100}
{props.sleeve.currentTask === SleeveTaskType.Crime && sx={{ width: '100%', height: '100%' }}
createProgressBarText({ >
progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime, Manage Augmentations
totalTicks: 25, </Button>
})} </span>
</Typography> </Tooltip>
<Button onClick={setTask}>Set Task</Button> </Box>
</Grid> </Box>
<Grid item xs={4}> <Box>
<StatsTable title="Earnings (Pre-Synchronization)" rows={data} /> <EarningsElement sleeve={props.sleeve} />
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button> <Box>
</Grid> <TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
</Grid> <Button onClick={setTask} sx={{ width: '100%' }}>Set Task</Button>
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} /> <Typography>{desc}</Typography>
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} /> <Typography>
<TravelModal {props.sleeve.currentTask === SleeveTaskType.Crime &&
open={travelOpen} createProgressBarText({
onClose={() => setTravelOpen(false)} progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime,
sleeve={props.sleeve} totalTicks: 25,
rerender={props.rerender} })}
/> </Typography>
<SleeveAugmentationsModal </Box>
open={augmentationsOpen} </Box>
onClose={() => setAugmentationsOpen(false)} <MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
sleeve={props.sleeve} <MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
/> <TravelModal
</> open={travelOpen}
onClose={() => setTravelOpen(false)}
sleeve={props.sleeve}
rerender={props.rerender}
/>
<SleeveAugmentationsModal
open={augmentationsOpen}
onClose={() => setAugmentationsOpen(false)}
sleeve={props.sleeve}
/>
</Box>
</Box>
</Box >
); );
} }

@ -1,12 +1,16 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import {
Box,
Typography,
Button,
Container
} from "@mui/material";
import { use } from "../../../ui/Context";
import { SleeveElem } from "./SleeveElem"; import { SleeveElem } from "./SleeveElem";
import { FAQModal } from "./FAQModal"; import { FAQModal } from "./FAQModal";
import { use } from "../../../ui/Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
export function SleeveRoot(): React.ReactElement { export function SleeveRoot(): React.ReactElement {
const player = use.Player(); const player = use.Player();
@ -23,27 +27,29 @@ export function SleeveRoot(): React.ReactElement {
return ( return (
<> <>
<Typography variant="h4">Sleeves</Typography> <Container disableGutters maxWidth="md" sx={{ mx: 0 }}>
<Typography> <Typography variant="h4">Sleeves</Typography>
Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness has been copied. In <Typography>
other words, these Synthoids contain a perfect duplicate of your mind. Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness has been copied. In
<br /> other words, these Synthoids contain a perfect duplicate of your mind.
<br /> <br />
Sleeves can be used to perform different tasks synchronously. <br />
<br /> Sleeves can be used to perform different tasks synchronously.
<br /> <br />
</Typography> <br />
</Typography>
</Container>
<Button onClick={() => setFAQOpen(true)}>FAQ</Button> <Button onClick={() => setFAQOpen(true)}>FAQ</Button>
<Link <Button href="https://bitburner.readthedocs.io/en/latest/advancedgameplay/sleeves.html#duplicate-sleeves" target="_blank">
target="_blank" Wiki Documentation
href="https://bitburner.readthedocs.io/en/latest/advancedgameplay/sleeves.html#duplicate-sleeves" </Button>
> <Box display="grid" sx={{ gridTemplateColumns: 'repeat(2, 1fr)', mt: 1 }}>
<Typography> Documentation</Typography> {player.sleeves.map((sleeve, i) => (
</Link> <SleeveElem key={i} rerender={rerender} sleeve={sleeve} />
{player.sleeves.map((sleeve, i) => ( ))}
<SleeveElem key={i} rerender={rerender} sleeve={sleeve} /> </Box>
))}
<FAQModal open={FAQOpen} onClose={() => setFAQOpen(false)} /> <FAQModal open={FAQOpen} onClose={() => setFAQOpen(false)} />
</> </>
); );

@ -1,31 +1,110 @@
import { Sleeve } from "../Sleeve";
import { numeralWrapper } from "../../../ui/numeralFormat";
import React from "react"; import React from "react";
import { StatsTable } from "../../../ui/React/StatsTable"; import {
Typography,
Table,
TableBody,
TableCell,
TableRow,
} from "@mui/material";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { Settings } from "../../../Settings/Settings";
import { StatsRow } from "../../../ui/React/StatsRow";
import { characterOverviewStyles as useStyles } from "../../../ui/React/CharacterOverview";
import { Money } from "../../../ui/React/Money";
import { MoneyRate } from "../../../ui/React/MoneyRate";
import { ReputationRate } from "../../../ui/React/ReputationRate";
import { use } from "../../../ui/Context";
import { Sleeve } from "../Sleeve";
import { SleeveTaskType } from "../SleeveTaskTypesEnum";
interface IProps { interface IProps {
sleeve: Sleeve; sleeve: Sleeve;
} }
export function StatsElement(props: IProps): React.ReactElement { export function StatsElement(props: IProps): React.ReactElement {
const rows = [ const classes = useStyles();
[
"HP: ", return (
<> <Table sx={{ display: 'table', mb: 1, width: '100%' }}>
{numeralWrapper.formatHp(props.sleeve.hp)} / {numeralWrapper.formatHp(props.sleeve.max_hp)} <TableBody>
</>, <StatsRow name="City" color={Settings.theme.primary} data={{ content: props.sleeve.city }} />
], <StatsRow name="HP" color={Settings.theme.hp}
["City: ", <>{props.sleeve.city}</>], data={{ content: `${numeralWrapper.formatHp(props.sleeve.hp)} / ${numeralWrapper.formatHp(props.sleeve.max_hp)}` }}
["Hacking: ", <>{numeralWrapper.formatSkill(props.sleeve.hacking)}</>], />
["Strength: ", <>{numeralWrapper.formatSkill(props.sleeve.strength)}</>], <StatsRow name="Hacking" color={Settings.theme.hack} data={{ level: props.sleeve.hacking, exp: props.sleeve.hacking_exp }} />
["Defense: ", <>{numeralWrapper.formatSkill(props.sleeve.defense)}</>], <StatsRow name="Strength" color={Settings.theme.combat} data={{ level: props.sleeve.strength, exp: props.sleeve.strength_exp }} />
["Dexterity: ", <>{numeralWrapper.formatSkill(props.sleeve.dexterity)}</>], <StatsRow name="Defense" color={Settings.theme.combat} data={{ level: props.sleeve.defense, exp: props.sleeve.defense_exp }} />
["Agility: ", <>{numeralWrapper.formatSkill(props.sleeve.agility)}</>], <StatsRow name="Dexterity" color={Settings.theme.combat} data={{ level: props.sleeve.dexterity, exp: props.sleeve.dexterity_exp }} />
["Charisma: ", <>{numeralWrapper.formatSkill(props.sleeve.charisma)}</>], <StatsRow name="Agility" color={Settings.theme.combat} data={{ level: props.sleeve.agility, exp: props.sleeve.agility_exp }} />
["Shock: ", <>{numeralWrapper.formatSleeveShock(100 - props.sleeve.shock)}</>], <StatsRow name="Charisma" color={Settings.theme.cha} data={{ level: props.sleeve.charisma, exp: props.sleeve.charisma_exp }} />
["Sync: ", <>{numeralWrapper.formatSleeveSynchro(props.sleeve.sync)}</>], <TableRow>
["Memory: ", <>{numeralWrapper.formatSleeveMemory(props.sleeve.memory)}</>], <TableCell classes={{ root: classes.cellNone }}>
]; <br />
return <StatsTable rows={rows} />; </TableCell>
</TableRow>
<StatsRow name="Shock" color={Settings.theme.primary} data={{ content: numeralWrapper.formatSleeveShock(100 - props.sleeve.shock) }} />
<StatsRow name="Sync" color={Settings.theme.primary} data={{ content: numeralWrapper.formatSleeveSynchro(props.sleeve.sync) }} />
<StatsRow name="Memory" color={Settings.theme.primary} data={{ content: numeralWrapper.formatSleeveMemory(props.sleeve.memory) }} />
</TableBody>
</Table>
)
}
export function EarningsElement(props: IProps): React.ReactElement {
const classes = useStyles();
const player = use.Player();
let data: any[][] = [];
if (props.sleeve.currentTask === SleeveTaskType.Crime) {
data = [
[`Money`, <><Money money={parseFloat(props.sleeve.currentTaskLocation)} /> (on success)</>],
[`Hacking Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.hack)} (2x on success)`],
[`Strength Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.str)} (2x on success)`],
[`Defense Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.def)} (2x on success)`],
[`Dexterity Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.dex)} (2x on success)`],
[`Agility Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.agi)} (2x on success)`],
[`Charisma Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.cha)} (2x on success)`],
];
} else {
data = [
[`Money:`, <MoneyRate money={5 * props.sleeve.gainRatesForTask.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.hack)} / sec`],
[`Strength Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.str)} / sec`],
[`Defense Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.def)} / sec`],
[`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.dex)} / sec`],
[`Agility Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.agi)} / sec`],
[`Charisma Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.cha)} / sec`],
];
if (props.sleeve.currentTask === SleeveTaskType.Company || props.sleeve.currentTask === SleeveTaskType.Faction) {
const repGain: number = props.sleeve.getRepGain(player);
data.push([`Reputation:`, <ReputationRate reputation={5 * repGain} />]);
}
}
return (
<Table sx={{ display: 'table', mb: 1, width: '100%', lineHeight: 0 }}>
<TableBody>
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<Typography variant='h6'>
Earnings
</Typography>
</TableCell>
</TableRow>
{data.map(([a, b]) => (
<TableRow key={a.toString() + b.toString()}>
<TableCell classes={{ root: classes.cellNone }}>
<Typography>{a}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography>{b}</Typography>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)
} }

@ -9,6 +9,7 @@ import { Factions } from "../../../Faction/Factions";
import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum"; import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum";
import Select, { SelectChangeEvent } from "@mui/material/Select"; import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
import { FactionNames } from "../../../Faction/data/FactionNames";
const universitySelectorOptions: string[] = [ const universitySelectorOptions: string[] = [
"Study Computer Science", "Study Computer Science",
@ -55,7 +56,7 @@ function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] { function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
// Array of all factions that other sleeves are working for // Array of all factions that other sleeves are working for
const forbiddenFactions = ["Bladeburners"]; const forbiddenFactions = [FactionNames.Bladeburners as string];
if (player.gang) { if (player.gang) {
forbiddenFactions.push(player.gang.facName); forbiddenFactions.push(player.gang.facName);
} }
@ -278,7 +279,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
return ( return (
<> <>
<Select onChange={onS0Change} value={s0}> <Select onChange={onS0Change} value={s0} sx={{ width: '100%' }}>
{validActions.map((task) => ( {validActions.map((task) => (
<MenuItem key={task} value={task}> <MenuItem key={task} value={task}>
{task} {task}
@ -287,8 +288,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
</Select> </Select>
{!(details.first.length === 1 && details.first[0] === "------") && ( {!(details.first.length === 1 && details.first[0] === "------") && (
<> <>
<br /> <Select onChange={onS1Change} value={s1} sx={{ width: '100%' }}>
<Select onChange={onS1Change} value={s1}>
{details.first.map((detail) => ( {details.first.map((detail) => (
<MenuItem key={detail} value={detail}> <MenuItem key={detail} value={detail}>
{detail} {detail}
@ -299,8 +299,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
)} )}
{!(details2.length === 1 && details2[0] === "------") && ( {!(details2.length === 1 && details2[0] === "------") && (
<> <>
<br /> <Select onChange={onS2Change} value={s2} sx={{ width: '100%' }}>
<Select onChange={onS2Change} value={s2}>
{details2.map((detail) => ( {details2.map((detail) => (
<MenuItem key={detail} value={detail}> <MenuItem key={detail} value={detail}>
{detail} {detail}

@ -1,3 +1,5 @@
import { FactionNames } from './Faction/data/FactionNames';
import { CityName } from './Locations/data/CityNames';
import { Augmentations } from "./Augmentation/Augmentations"; import { Augmentations } from "./Augmentation/Augmentations";
import { augmentationExists, initAugmentations } from "./Augmentation/AugmentationHelpers"; import { augmentationExists, initAugmentations } from "./Augmentation/AugmentationHelpers";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
@ -160,9 +162,7 @@ export function prestigeAugmentation(): void {
} }
if (augmentationExists(AugmentationNames.StaneksGift1) && Augmentations[AugmentationNames.StaneksGift1].owned) { if (augmentationExists(AugmentationNames.StaneksGift1) && Augmentations[AugmentationNames.StaneksGift1].owned) {
// TODO(hydroflame): refactor faction names so we don't have to hard joinFaction(Factions[FactionNames.ChurchOfTheMachineGod]);
// code strings.
joinFaction(Factions["Church of the Machine God"]);
} }
staneksGift.prestigeAugmentation(); staneksGift.prestigeAugmentation();
@ -260,7 +260,7 @@ export function prestigeSourceFile(flume: boolean): void {
homeComp.messages.push(LiteratureNames.CorporationManagementHandbook); homeComp.messages.push(LiteratureNames.CorporationManagementHandbook);
dialogBoxCreate( dialogBoxCreate(
"You received a copy of the Corporation Management Handbook on your home computer. " + "You received a copy of the Corporation Management Handbook on your home computer. " +
"Read it if you need help getting started with Corporations!", "Read it if you need help getting started with Corporations!",
); );
} }
@ -279,7 +279,7 @@ export function prestigeSourceFile(flume: boolean): void {
} }
if (Player.bitNodeN === 13) { if (Player.bitNodeN === 13) {
dialogBoxCreate("Trouble is brewing in Chongqing"); dialogBoxCreate(`Trouble is brewing in ${CityName.Chongqing}`);
} }
// Reset Stock market, gang, and corporation // Reset Stock market, gang, and corporation

@ -11,6 +11,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { BitFlumeEvent } from "../../BitNode/ui/BitFlumeModal"; import { BitFlumeEvent } from "../../BitNode/ui/BitFlumeModal";
import { calculateHackingTime, calculateGrowTime, calculateWeakenTime } from "../../Hacking"; import { calculateHackingTime, calculateGrowTime, calculateWeakenTime } from "../../Hacking";
import { FactionNames } from "../../Faction/data/FactionNames";
function requireHackingLevel(lvl: number) { function requireHackingLevel(lvl: number) {
return function (p: IPlayer) { return function (p: IPlayer) {
@ -316,7 +317,7 @@ export const programsMetadata: IProgramCreationParams[] = [
} }
terminal.print("We will contact you."); terminal.print("We will contact you.");
terminal.print("-- Daedalus --"); terminal.print(`-- ${FactionNames.Daedalus} --`);
}, },
}, },
]; ];

@ -1506,6 +1506,20 @@ export interface TIX {
* @returns True if you successfully purchased it or if you already have access, false otherwise. * @returns True if you successfully purchased it or if you already have access, false otherwise.
*/ */
purchase4SMarketDataTixApi(): boolean; purchase4SMarketDataTixApi(): boolean;
/**
* Purchase WSE Account.
* @remarks RAM cost: 2.5 GB
* @returns True if you successfully purchased it or if you already have access, false otherwise.
*/
purchaseWseAccount(): boolean;
/**
* Purchase TIX API Access
* @remarks RAM cost: 2.5 GB
* @returns True if you successfully purchased it or if you already have access, false otherwise.
*/
purchaseTixApi(): boolean;
} }
/** /**

@ -1,3 +1,4 @@
import { FactionNames } from '../../Faction/data/FactionNames';
// tslint:disable:max-file-line-count // tslint:disable:max-file-line-count
// This could actually be a JSON file as it should be constant metadata to be imported... // This could actually be a JSON file as it should be constant metadata to be imported...
@ -78,7 +79,7 @@ interface IServerMetadata {
export const serverMetadata: IServerMetadata[] = [ export const serverMetadata: IServerMetadata[] = [
{ {
hackDifficulty: 99, hackDifficulty: 99,
hostname: "ecorp", hostname: LocationName.AevumECorp.toLowerCase(),
moneyAvailable: { moneyAvailable: {
max: 70e9, max: 70e9,
min: 30e9, min: 30e9,
@ -95,7 +96,7 @@ export const serverMetadata: IServerMetadata[] = [
}, },
{ {
hackDifficulty: 99, hackDifficulty: 99,
hostname: "megacorp", hostname: LocationName.Sector12MegaCorp.toLowerCase(),
moneyAvailable: { moneyAvailable: {
max: 60e9, max: 60e9,
min: 40e9, min: 40e9,
@ -163,7 +164,7 @@ export const serverMetadata: IServerMetadata[] = [
}, },
{ {
hackDifficulty: 99, hackDifficulty: 99,
hostname: "nwo", hostname: LocationName.VolhavenNWO.toLowerCase(),
literature: [LiteratureNames.TheHiddenWorld], literature: [LiteratureNames.TheHiddenWorld],
moneyAvailable: { moneyAvailable: {
max: 40e9, max: 40e9,
@ -423,7 +424,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 90, max: 90,
min: 80, min: 80,
}, },
hostname: "vitalife", hostname: LocationName.NewTokyoVitaLife.toLowerCase(),
literature: [LiteratureNames.AGreenTomorrow], literature: [LiteratureNames.AGreenTomorrow],
maxRamExponent: { maxRamExponent: {
max: 7, max: 7,
@ -601,7 +602,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 90, max: 90,
min: 80, min: 80,
}, },
hostname: "aerocorp", hostname: LocationName.AevumAeroCorp.toLowerCase(),
literature: [LiteratureNames.ManAndMachine], literature: [LiteratureNames.ManAndMachine],
moneyAvailable: { moneyAvailable: {
max: 1200000000, max: 1200000000,
@ -726,7 +727,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 85, max: 85,
min: 75, min: 75,
}, },
hostname: "deltaone", hostname: LocationName.Sector12DeltaOne.toLowerCase(),
moneyAvailable: { moneyAvailable: {
max: 1700000000, max: 1700000000,
min: 1300000000, min: 1300000000,
@ -1120,7 +1121,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 65, max: 65,
min: 55, min: 55,
}, },
hostname: "comptek", hostname: LocationName.VolhavenCompuTek.toLowerCase(),
literature: [LiteratureNames.ManAndMachine], literature: [LiteratureNames.ManAndMachine],
moneyAvailable: { moneyAvailable: {
max: 250000000, max: 250000000,
@ -1201,7 +1202,7 @@ export const serverMetadata: IServerMetadata[] = [
}, },
{ {
hackDifficulty: 10, hackDifficulty: 10,
hostname: "foodnstuff", hostname: LocationName.Sector12FoodNStuff.toLowerCase(),
literature: [LiteratureNames.Sector12Crime], literature: [LiteratureNames.Sector12Crime],
maxRamExponent: 4, maxRamExponent: 4,
moneyAvailable: 2000000, moneyAvailable: 2000000,
@ -1381,7 +1382,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 20000000, moneyAvailable: 20000000,
networkLayer: 1, networkLayer: 1,
numOpenPortsRequired: 1, numOpenPortsRequired: 1,
organizationName: "Iron Gym Network", organizationName: `${LocationName.Sector12IronGym} Network`,
requiredHackingSkill: 100, requiredHackingSkill: 100,
serverGrowth: 20, serverGrowth: 20,
specialName: LocationName.Sector12IronGym, specialName: LocationName.Sector12IronGym,
@ -1503,7 +1504,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 0, moneyAvailable: 0,
networkLayer: 4, networkLayer: 4,
numOpenPortsRequired: 2, numOpenPortsRequired: 2,
organizationName: "NiteSec", organizationName: FactionNames.NiteSec,
requiredHackingSkill: { requiredHackingSkill: {
max: 220, max: 220,
min: 202, min: 202,
@ -1534,7 +1535,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 0, moneyAvailable: 0,
networkLayer: 2, networkLayer: 2,
numOpenPortsRequired: 1, numOpenPortsRequired: 1,
organizationName: "CyberSec", organizationName: FactionNames.CyberSec,
requiredHackingSkill: { requiredHackingSkill: {
max: 60, max: 60,
min: 51, min: 51,

@ -8,3 +8,11 @@ export function getStockMarket4SDataCost(): number {
export function getStockMarket4STixApiCost(): number { export function getStockMarket4STixApiCost(): number {
return CONSTANTS.MarketDataTixApi4SCost * BitNodeMultipliers.FourSigmaMarketDataApiCost; return CONSTANTS.MarketDataTixApi4SCost * BitNodeMultipliers.FourSigmaMarketDataApiCost;
} }
export function getStockMarketWseCost(): number {
return CONSTANTS.WSEAccountCost;
}
export function getStockMarketTixApiCost(): number {
return CONSTANTS.TIXAPICost;
}

@ -19,6 +19,7 @@ import IconButton from "@mui/material/IconButton";
import HelpIcon from "@mui/icons-material/Help"; import HelpIcon from "@mui/icons-material/Help";
import CheckIcon from "@mui/icons-material/Check"; import CheckIcon from "@mui/icons-material/Check";
import { StaticModal } from "../../ui/React/StaticModal"; import { StaticModal } from "../../ui/React/StaticModal";
import { FactionNames } from "../../Faction/data/FactionNames";
type IProps = { type IProps = {
initStockMarket: () => void; initStockMarket: () => void;
@ -190,10 +191,10 @@ export function InfoAndPurchases(props: IProps): React.ReactElement {
</Typography> </Typography>
<PurchaseTixApiAccessButton {...props} /> <PurchaseTixApiAccessButton {...props} />
<Typography variant="h5" color="primary"> <Typography variant="h5" color="primary">
Four Sigma (4S) Market Data Feed {FactionNames.FourSigma} (4S) Market Data Feed
</Typography> </Typography>
<Typography> <Typography>
Four Sigma's (4S) Market Data Feed provides information about stocks that will help your trading strategies. {FactionNames.FourSigma}'s (4S) Market Data Feed provides information about stocks that will help your trading strategies.
<IconButton onClick={() => setHelpOpen(true)}> <IconButton onClick={() => setHelpOpen(true)}>
<HelpIcon /> <HelpIcon />
</IconButton> </IconButton>

49
src/ui/React/StatsRow.tsx Normal file

@ -0,0 +1,49 @@
import React from "react";
import {
Typography,
TableCell,
TableRow,
} from "@mui/material";
import { numeralWrapper } from "../numeralFormat";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { characterOverviewStyles as useStyles } from "./CharacterOverview";
interface ITableRowData {
content?: string;
level?: number;
exp?: number;
}
interface IProps {
name: string;
color: string;
classes?: any;
data: ITableRowData;
}
export const StatsRow = ({ name, color, classes = useStyles(), data }: IProps): React.ReactElement => {
let content;
if (data.content !== undefined) {
content = data.content;
} else if (data.level !== undefined && data.exp !== undefined) {
content = `${formatNumber(data.level, 0)} (${numeralWrapper.formatExp(data.exp)} exp)`;
} else if (data.level !== undefined && data.exp === undefined) {
content = `${formatNumber(data.level, 0)}`;
}
return (
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>{name}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>
{content}
</Typography>
</TableCell>
</TableRow>
)
}

@ -1,3 +1,4 @@
import { CityName } from './../../../src/Locations/data/CityNames';
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
import { jest, describe, expect, test } from "@jest/globals"; import { jest, describe, expect, test } from "@jest/globals";
@ -37,7 +38,7 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
hackDifficulty: 1, hackDifficulty: 1,
moneyAvailable: 70000, moneyAvailable: 70000,
numOpenPortsRequired: 0, numOpenPortsRequired: 0,
organizationName: LocationName.Aevum, organizationName: CityName.Aevum,
requiredHackingSkill: 1, requiredHackingSkill: 1,
serverGrowth: 3000, serverGrowth: 3000,
}); });