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 { IMap } from "../types";
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...
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
@ -56,7 +58,7 @@ function bitNodeFinishedState(): boolean {
const wd = GetServer(SpecialServers.WorldDaemon);
if (!(wd instanceof Server)) return false;
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 {
@ -82,40 +84,40 @@ function sfAchievement(): Achievement[] {
}
export const achievements: IMap<Achievement> = {
CYBERSEC: {
...achievementData["CYBERSEC"],
[FactionNames.CyberSec.toUpperCase()]: {
...achievementData[FactionNames.CyberSec.toUpperCase()],
Icon: "CSEC",
Condition: () => Player.factions.includes("CyberSec"),
Condition: () => Player.factions.includes(FactionNames.CyberSec),
},
NITESEC: {
...achievementData["NITESEC"],
Icon: "NiteSec",
Condition: () => Player.factions.includes("NiteSec"),
[FactionNames.NiteSec.toUpperCase()]: {
...achievementData[FactionNames.NiteSec.toUpperCase()],
Icon: FactionNames.NiteSec,
Condition: () => Player.factions.includes(FactionNames.NiteSec),
},
THE_BLACK_HAND: {
...achievementData["THE_BLACK_HAND"],
Icon: "TBH",
Condition: () => Player.factions.includes("The Black Hand"),
Condition: () => Player.factions.includes(FactionNames.TheBlackHand),
},
BITRUNNERS: {
...achievementData["BITRUNNERS"],
Icon: "bitrunners",
Condition: () => Player.factions.includes("BitRunners"),
[FactionNames.BitRunners.toUpperCase()]: {
...achievementData[FactionNames.BitRunners.toUpperCase()],
Icon: FactionNames.BitRunners.toLowerCase(),
Condition: () => Player.factions.includes(FactionNames.BitRunners),
},
DAEDALUS: {
...achievementData["DAEDALUS"],
Icon: "daedalus",
Condition: () => Player.factions.includes("Daedalus"),
[FactionNames.Daedalus.toUpperCase()]: {
...achievementData[FactionNames.Daedalus.toUpperCase()],
Icon: FactionNames.Daedalus.toLowerCase(),
Condition: () => Player.factions.includes(FactionNames.Daedalus),
},
THE_COVENANT: {
...achievementData["THE_COVENANT"],
Icon: "thecovenant",
Condition: () => Player.factions.includes("The Covenant"),
Icon: FactionNames.TheCovenant.toLowerCase(),
Condition: () => Player.factions.includes(FactionNames.TheCovenant),
},
ILLUMINATI: {
...achievementData["ILLUMINATI"],
Icon: "illuminati",
Condition: () => Player.factions.includes("Illuminati"),
[FactionNames.Illuminati.toUpperCase()]: {
...achievementData[FactionNames.Illuminati.toUpperCase()],
Icon: FactionNames.Illuminati.toLowerCase(),
Condition: () => Player.factions.includes(FactionNames.Illuminati),
},
"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.
// { ID: "ECORP", Condition: () => Player.factions.includes("ECorp") },
// { ID: "MEGACORP", Condition: () => Player.factions.includes("MegaCorp") },
// { ID: "BACHMAN_&_ASSOCIATES", Condition: () => Player.factions.includes("Bachman & Associates") },
// { ID: "BLADE_INDUSTRIES", Condition: () => Player.factions.includes("Blade Industries") },
// { ID: "NWO", Condition: () => Player.factions.includes("NWO") },
// { ID: "CLARKE_INCORPORATED", Condition: () => Player.factions.includes("Clarke Incorporated") },
// { ID: "OMNITEK_INCORPORATED", Condition: () => Player.factions.includes("OmniTek Incorporated") },
// { ID: "FOUR_SIGMA", Condition: () => Player.factions.includes("Four Sigma") },
// { ID: "KUAIGONG_INTERNATIONAL", Condition: () => Player.factions.includes("KuaiGong International") },
// { ID: "FULCRUM_SECRET_TECHNOLOGIES", Condition: () => Player.factions.includes("Fulcrum Secret Technologies") },
// { ID: "AEVUM", Condition: () => Player.factions.includes("Aevum") },
// { ID: "CHONGQING", Condition: () => Player.factions.includes("Chongqing") },
// { ID: "ISHIMA", Condition: () => Player.factions.includes("Ishima") },
// { ID: "NEW_TOKYO", Condition: () => Player.factions.includes("New Tokyo") },
// { ID: "SECTOR-12", Condition: () => Player.factions.includes("Sector-12") },
// { ID: "VOLHAVEN", Condition: () => Player.factions.includes("Volhaven") },
// { ID: "SPEAKERS_FOR_THE_DEAD", Condition: () => Player.factions.includes("Speakers for the Dead") },
// { ID: "THE_DARK_ARMY", Condition: () => Player.factions.includes("The Dark Army") },
// { ID: "THE_SYNDICATE", Condition: () => Player.factions.includes("The Syndicate") },
// { ID: "SILHOUETTE", Condition: () => Player.factions.includes("Silhouette") },
// { ID: "TETRADS", Condition: () => Player.factions.includes("Tetrads") },
// { ID: "SLUM_SNAKES", Condition: () => Player.factions.includes("Slum Snakes") },
// { ID: "NETBURNERS", Condition: () => Player.factions.includes("Netburners") },
// { ID: "TIAN_DI_HUI", Condition: () => Player.factions.includes("Tian Di Hui") },
// { ID: "BLADEBURNERS", Condition: () => Player.factions.includes("Bladeburners") },
// { ID: FactionNames.ECorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.ECorp) },
// { ID: FactionNames.MegaCorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.MegaCorp) },
// { ID: "BACHMAN_&_ASSOCIATES", Condition: () => Player.factions.includes(FactionNames.BachmanAssociates) },
// { ID: "BLADE_INDUSTRIES", Condition: () => Player.factions.includes(FactionNames.BladeIndustries) },
// { ID: FactionNames.NWO.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.NWO) },
// { ID: "CLARKE_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.ClarkeIncorporated) },
// { ID: "OMNITEK_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.OmniTekIncorporated) },
// { ID: "FOUR_SIGMA", Condition: () => Player.factions.includes(FactionNames.FourSigma) },
// { ID: "KUAIGONG_INTERNATIONAL", Condition: () => Player.factions.includes(FactionNames.KuaiGongInternational) },
// { ID: "FULCRUM_SECRET_TECHNOLOGIES", Condition: () => Player.factions.includes(FactionNames.FulcrumSecretTechnologies) },
// { ID: FactionNames.Aevum.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Aevum) },
// { ID: FactionNames.Chongqing.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Chongqing) },
// { ID: FactionNames.Ishima.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Ishima) },
// { ID: "NEW_TOKYO", Condition: () => Player.factions.includes(FactionNames.NewTokyo) },
// { ID: "SECTOR-12", Condition: () => Player.factions.includes(FactionNames.Sector12) },
// { ID: FactionNames.Volhaven.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Volhaven) },
// { ID: "SPEAKERS_FOR_THE_DEAD", Condition: () => Player.factions.includes(FactionNames.SpeakersForTheDead) },
// { ID: "THE_DARK_ARMY", Condition: () => Player.factions.includes(FactionNames.TheDarkArmy) },
// { ID: "THE_SYNDICATE", Condition: () => Player.factions.includes(FactionNames.TheSyndicate) },
// { ID: FactionNames.Silhouette.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Silhouette) },
// { ID: FactionNames.Tetrads.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Tetrads) },
// { ID: "SLUM_SNAKES", Condition: () => Player.factions.includes(FactionNames.SlumSnakes) },
// { ID: FactionNames.Netburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Netburners) },
// { ID: "TIAN_DI_HUI", Condition: () => Player.factions.includes(FactionNames.TianDiHui) },
// { ID: FactionNames.Bladeburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Bladeburners) },
// { ID: "DEEPSCANV1.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV1.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 { IPlayer } from "../PersonObjects/IPlayer";
import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames";
import { CityName } from "../Locations/data/CityNames";
class BitNode {
// A short description, or tagline, about the BitNode
@ -80,8 +82,7 @@ BitNodes["BitNode2"] = new BitNode(
<br />
The amount of money gained from crimes and Infiltration is tripled
<br />
Certain Factions (Slum Snakes, Tetrads, The Syndicate, The Dark Army, Speakers for the Dead, NiteSec, The Black
Hand) give the player the ability to form and manage their own gangs. These gangs will earn the player money and
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
reputation with the corresponding Faction
<br />
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(
6,
1,
"Bladeburners",
FactionNames.Bladeburners,
"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
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
the humans that had created them.
<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:
<br />
<br />
@ -249,7 +250,7 @@ BitNodes["BitNode6"] = new BitNode(
<br />
<br />
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
stats by:
<br />
@ -265,23 +266,23 @@ BitNodes["BitNode6"] = new BitNode(
BitNodes["BitNode7"] = new BitNode(
7,
2,
"Bladeburners 2079",
`${FactionNames.Bladeburners} 2079`,
"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
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
that were stronger, faster, and more intelligent than the humans that had created them.
<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 />
<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 />
Bladeburner skills cost twice as many skill points
{FactionNames.Bladeburners} skills cost twice as many skill points
<br />
Augmentations are 3x more expensive
<br />
@ -299,8 +300,8 @@ BitNodes["BitNode7"] = new BitNode(
<br />
<br />
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.
In addition, this Source-File will increase all of your Bladeburner multipliers by:
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 {FactionNames.Bladeburners} multipliers by:
<br />
<br />
Level 1: 8%
@ -363,9 +364,9 @@ BitNodes["BitNode9"] = new BitNode(
"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,
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.
<br />
<br />
@ -537,12 +538,12 @@ BitNodes["BitNode13"] = new BitNode(
"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.
<br />
<br />
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 />
In this BitNode:
@ -554,7 +555,7 @@ BitNodes["BitNode13"] = new BitNode(
<br />
<br />
Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File lets the Church of the Machine God appear in other BitNodes.
level up to a maximum of 3. This Source-File lets the {FactionNames.ChurchOfTheMachineGod} appear in other BitNodes.
<br />
<br />
Each level of this Source-File increases the size of Stanek's Gift.

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

@ -33,6 +33,8 @@ import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
import { getTimestamp } from "../utils/helpers/getTimestamp";
import { joinFaction } from "../Faction/FactionHelpers";
import { WorkerScript } from "../Netscript/WorkerScript";
import { FactionNames } from "../Faction/data/FactionNames";
import { BlackOperationNames } from "./data/BlackOperationNames";
interface BlackOpsAttempt {
error?: string;
@ -229,7 +231,6 @@ export class Bladeburner implements IBladeburner {
break;
default:
throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
break;
}
}
@ -291,7 +292,7 @@ export class Bladeburner implements IBladeburner {
prestige(): void {
this.resetAction();
const bladeburnerFac = Factions["Bladeburners"];
const bladeburnerFac = Factions[FactionNames.Bladeburners];
if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac);
}
@ -320,7 +321,6 @@ export class Bladeburner implements IBladeburner {
} else {
return null;
}
break;
case "operation":
case "operations":
case "op":
@ -332,7 +332,6 @@ export class Bladeburner implements IBladeburner {
} else {
return null;
}
break;
case "blackoperation":
case "black operation":
case "black operations":
@ -347,7 +346,6 @@ export class Bladeburner implements IBladeburner {
} else {
return null;
}
break;
case "general":
case "general action":
case "gen":
@ -1375,7 +1373,7 @@ export class Bladeburner implements IBladeburner {
teamLossMax = Math.ceil(teamCount / 2);
// Operation Daedalus
if (action.name === "Operation Daedalus") {
if (action.name === BlackOperationNames.OperationDaedalus) {
this.resetAction();
return router.toBitVerse(false, false);
}
@ -1531,8 +1529,7 @@ export class Bladeburner implements IBladeburner {
this.startAction(player, this.action);
if (this.logging.general) {
this.log(
`Rested in Hyperbolic Regeneration Chamber. Restored ${
BladeburnerConstants.HrcHpGain
`Rested in Hyperbolic Regeneration Chamber. Restored ${BladeburnerConstants.HrcHpGain
} HP and gained ${numeralWrapper.formatStamina(staminaGain)} stamina`,
);
}
@ -1577,11 +1574,11 @@ export class Bladeburner implements IBladeburner {
}
this.maxRank = Math.max(this.rank, this.maxRank);
const bladeburnersFactionName = "Bladeburners";
const bladeburnersFactionName = FactionNames.Bladeburners;
if (factionExists(bladeburnersFactionName)) {
const bladeburnerFac = Factions[bladeburnersFactionName];
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) {
const favorBonus = 1 + bladeburnerFac.favor / 100;
@ -1918,7 +1915,7 @@ export class Bladeburner implements IBladeburner {
if (!router.isInitialized) return;
// 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);
}
@ -2340,12 +2337,12 @@ export class Bladeburner implements IBladeburner {
}
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean {
const bladeburnerFac = Factions["Bladeburners"];
const bladeburnerFac = Factions[FactionNames.Bladeburners];
if (bladeburnerFac.isMember) {
return true;
} else if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac);
workerScript.log("bladeburner.joinBladeburnerFaction", () => "Joined Bladeburners faction.");
workerScript.log("bladeburner.joinBladeburnerFaction", () => `Joined ${FactionNames.Bladeburners} faction.`);
return true;
} else {
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 { FactionNames } from "../../Faction/data/FactionNames";
import { CityName } from "../../Locations/data/CityNames";
import { BlackOperationNames } from "./BlackOperationNames";
interface IBlackOp {
desc: JSX.Element;
@ -7,34 +10,34 @@ interface IBlackOp {
export const BlackOperations: {
[key: string]: IBlackOp | undefined;
} = {
"Operation Typhoon": {
[BlackOperationNames.OperationTyphoon]: {
desc: (
<>
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.
<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.
</>
),
},
"Operation Zero": {
[BlackOperationNames.OperationZero]: {
desc: (
<>
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.
<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
evidence can be fabricated as a last resort. Be warned that AeroCorp has some of the most advanced security
measures in the world.
</>
),
},
"Operation X": {
[BlackOperationNames.OperationX]: {
desc: (
<>
We have recently discovered an underground publication group called Samizdat. Even though most of their
@ -44,12 +47,12 @@ export const BlackOperations: {
<br />
<br />
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.
</>
),
},
"Operation Titan": {
[BlackOperationNames.OperationTitan]: {
desc: (
<>
Several months ago Titan Laboratories' Bioengineering department was infiltrated by Synthoids. As far as we
@ -58,13 +61,13 @@ export const BlackOperations: {
dangerous.
<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
the Synthoids and their goals.
</>
),
},
"Operation Ares": {
[BlackOperationNames.OperationAres]: {
desc: (
<>
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: (
<>
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: (
<>
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
city-wide blackout. The CIA suspects that Juggernaut is a heavily-augmented Synthoid, and have thus enlisted our
help.
@ -103,20 +106,20 @@ export const BlackOperations: {
</>
),
},
"Operation Red Dragon": {
[BlackOperationNames.OperationRedDragon]: {
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
their criminal activities.
<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.
</>
),
},
"Operation K": {
[BlackOperationNames.OperationK]: {
desc: (
<>
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: (
<>
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
technology before the Operation. It is almost a certainty that these Synthoids are some of the rogue MK-VI ones
from the Synthoid Uprising.
<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.
</>
),
},
"Operation Tyrell": {
[BlackOperationNames.OperationTyrell]: {
desc: (
<>
A week ago Blade Industries reported a small break-in at one of their 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
A week ago {FactionNames.BladeIndustries} reported a small break-in at one of their {CityName.Aevum} Augmentation storage facilities. We
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.
<br />
<br />
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: (
<>
Based on information gathered from Operation Tyrell, we've discovered that The Dark Army was well aware that
there were Synthoids amongst their ranks. Even worse, we believe that The Dark Army is working together with
other criminal organizations such as The Syndicate 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
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 {FactionNames.TheDarkArmy} is working together with
other criminal organizations such as {FactionNames.TheSyndicate} and that they are planning some sort of large-scale takeover
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.
<br />
<br />
The best way to deal with this is to prevent it before it even happens. The goal of Operation Wallace is to
destroy the Dark Army and Syndicate factions in Aevum immediately. Leave no survivors.
The best way to deal with this is to prevent it before it even happens. The goal of {BlackOperationNames.OperationWallace} is to
destroy {FactionNames.TheDarkArmy} and Syndicate factions in {CityName.Aevum} immediately. Leave no survivors.
</>
),
},
"Operation Shoulder of Orion": {
[BlackOperationNames.OperationShoulderOfOrion]: {
desc: (
<>
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: (
<>
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
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.
@ -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.
<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
project lead.
</>
),
},
"Operation Morpheus": {
[BlackOperationNames.OperationMorpheus]: {
desc: (
<>
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
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.
<br />
<br />
@ -218,38 +221,38 @@ export const BlackOperations: {
</>
),
},
"Operation Ion Storm": {
[BlackOperationNames.OperationIonStorm]: {
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
weapons, money, and other resources. This makes them dangerous.
<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: (
<>
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
'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: (
<>
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
destruction of humanity. They say that this bug affects all MK-VI Synthoids, not just the rogue ones from the
Uprising.
<br />
<br />
OmniTek 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
{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 {CityName.Volhaven} to form a terrorist group
called Ultron.
<br />
<br />
@ -261,7 +264,7 @@ export const BlackOperations: {
</>
),
},
"Operation Centurion": {
[BlackOperationNames.OperationCenturion]: {
desc: (
<>
{"D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)"}
@ -279,7 +282,7 @@ export const BlackOperations: {
</>
),
},
"Operation Vindictus": {
[BlackOperationNames.OperationVindictus]: {
desc: (
<>
{"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.</>,
},
};

@ -1,3 +1,4 @@
import { CityName } from './../../Locations/data/CityNames';
export const BladeburnerConstants: {
CityNames: string[];
CyclesPerSecond: number;
@ -27,7 +28,7 @@ export const BladeburnerConstants: {
HrcHpGain: 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
StaminaGainPerSecond: 0.0085,

@ -3,6 +3,7 @@ import { BlackOpList } from "./BlackOpList";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps {
bladeburner: IBladeburner;
@ -17,7 +18,7 @@ export function BlackOpPage(props: IProps): React.ReactElement {
successively by completing the one before it.
<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 />
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 { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context";
import { CinematicText } from "../../ui/React/CinematicText";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
@ -8,14 +9,14 @@ export function BladeburnerCinematic(): React.ReactElement {
return (
<CinematicText
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.",
"------",
"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 ",
"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.",
"------",
"The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating ",
@ -27,13 +28,13 @@ export function BladeburnerCinematic(): React.ReactElement {
"------",
"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. ",
"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.",
]}
onDone={() => {
router.toTerminal();
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.",
);
}}

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

@ -1,3 +1,4 @@
import { CityName } from './../../Locations/data/CityNames';
const CyclesPerMarketCycle = 50;
const AllCorporationStates = ["START", "PURCHASE", "PRODUCTION", "SALE", "EXPORT"];
export const CorporationConstants: {
@ -37,7 +38,7 @@ export const CorporationConstants: {
CyclesPerIndustryStateCycle: CyclesPerMarketCycle / AllCorporationStates.length,
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
WarehouseInitialSize: 100,

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

@ -1,3 +1,4 @@
import { FactionNames } from '../Faction/data/FactionNames';
import { Fragment } from "./Fragment";
import { ActiveFragment } from "./ActiveFragment";
import { FragmentType } from "./FragmentType";
@ -32,7 +33,7 @@ export class StaneksGift implements IStaneksGift {
af.avgCharge = (af.numCharge * af.avgCharge + threads) / (af.numCharge + 1);
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;
}

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

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

@ -18,42 +18,7 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { InvitationEvent } from "./ui/InvitationModal";
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",
]
import { FactionNames } from "./data/FactionNames";
export function inviteToFaction(faction: Faction): void {
Player.receiveInvite(faction.name);
@ -67,8 +32,9 @@ export function joinFaction(faction: Faction): void {
if (faction.isMember) return;
faction.isMember = true;
Player.factions.push(faction.name);
const allFactions = Object.values(FactionNames).map(faction => faction as string)
Player.factions.sort((a, b) =>
factionOrder.indexOf(a) - factionOrder.indexOf(b));
allFactions.indexOf(a) - allFactions.indexOf(b));
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction

@ -1,5 +1,6 @@
import React from "react";
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
@ -84,13 +85,15 @@ export class FactionInfo {
}
}
/**
* A map of all factions and associated info to them.
*/
// tslint:disable-next-line:variable-name
export const FactionInfos: IMap<FactionInfo> = {
// 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
@ -106,7 +109,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
),
Daedalus: new FactionInfo(
[FactionNames.Daedalus]: new FactionInfo(
<>Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.</>,
[],
true,
@ -117,7 +120,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
),
"The Covenant": new FactionInfo(
[FactionNames.TheCovenant]: new FactionInfo(
(
<>
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
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
Internet-related software and commercial hardware, ECorp makes the world's information universally accessible.
{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, {FactionNames.ECorp} makes the world's information universally accessible.
</>
),
[],
@ -153,15 +156,15 @@ export const FactionInfos: IMap<FactionInfo> = {
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
scale, in ways that no other company can.
<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,
),
"Bachman & Associates": new FactionInfo(
[FactionNames.BachmanAssociates]: new FactionInfo(
(
<>
Where Law and Business meet - thats where we are.
@ -191,9 +194,9 @@ export const FactionInfos: IMap<FactionInfo> = {
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
@ -210,7 +213,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true,
),
"Clarke Incorporated": new FactionInfo(
[FactionNames.ClarkeIncorporated]: new FactionInfo(
<>The Power of the Genome - Unlocked.</>,
[],
true,
@ -221,7 +224,7 @@ export const FactionInfos: IMap<FactionInfo> = {
true,
),
"OmniTek Incorporated": new FactionInfo(
[FactionNames.OmniTekIncorporated]: new FactionInfo(
<>Simply put, our mission is to design and build robots that make a difference.</>,
[],
true,
@ -232,11 +235,11 @@ export const FactionInfos: IMap<FactionInfo> = {
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
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,
),
"KuaiGong International": new FactionInfo(
[FactionNames.KuaiGongInternational]: new FactionInfo(
<>Dream big. Work hard. Make history.</>,
[],
true,
@ -260,7 +263,7 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// 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
@ -277,7 +280,7 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// 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
@ -299,7 +302,7 @@ export const FactionInfos: IMap<FactionInfo> = {
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.
@ -320,42 +323,42 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// prettier-ignore
NiteSec: new FactionInfo(<>
{" __..__ "}<br />
{" _.nITESECNIt. "}<br />
{" .-'NITESECNITESEc. "}<br />
{" .' NITESECNITESECn "}<br />
{" / NITESECNITESEC; "}<br />
{" : :NITESECNITESEC; "}<br />
{" ; $ NITESECNITESECN "}<br />
{" : _, ,N'ITESECNITESEC "}<br />
{" : .+^^`, : `NITESECNIT "}<br />
{" ) /), `-,-=,NITESECNI "}<br />
{" / ^ ,-;|NITESECN; "}<br />
{" / _.' '-';NITESECN "}<br />
{" ( , ,-''`^NITE' "}<br />
{" )` :`. .' "}<br />
{" )-- ; `- / "}<br />
{" ' _.-' : "}<br />
{" ( _.-' . "}<br />
{" ------. "}<br />
{" . "}<br />
{" _.nIt "}<br />
{" _.nITESECNi "}<br />
{" nITESECNIT^' "}<br />
{" NITE^' ___ "}<br />
{" / .gP''''Tp. "}<br />
{" : d' . `b "}<br />
{" ; d' o `b ; "}<br />
{" / d; `b| "}<br />
{" /, $; @ `: "}<br />
{" /' $/ ; "}<br />
{" .' $/b o | "}<br />
{" .' d$/$; : "}<br />
{" / .d/$/$; , ; "}<br />
{" d .dNITESEC $ | "}<br />
{" :bp.__.gNITESEC/$ :$ ; "}<br />
{" NITESECNITESECNIT /$b : "}<br /></>,
[FactionNames.NiteSec]: new FactionInfo(<>
{" __..__ "}<br />
{" _.nITESECNIt. "}<br />
{" .-'NITESECNITESEc. "}<br />
{" .' NITESECNITESECn "}<br />
{" / NITESECNITESEC; "}<br />
{" : :NITESECNITESEC; "}<br />
{" ; $ NITESECNITESECN "}<br />
{" : _, ,N'ITESECNITESEC "}<br />
{" : .+^^`, : `NITESECNIT "}<br />
{" ) /), `-,-=,NITESECNI "}<br />
{" / ^ ,-;|NITESECN; "}<br />
{" / _.' '-';NITESECN "}<br />
{" ( , ,-''`^NITE' "}<br />
{" )` :`. .' "}<br />
{" )-- ; `- / "}<br />
{" ' _.-' : "}<br />
{" ( _.-' . "}<br />
{" ------. "}<br />
{" . "}<br />
{" _.nIt "}<br />
{" _.nITESECNi "}<br />
{" nITESECNIT^' "}<br />
{" NITE^' ___ "}<br />
{" / .gP''''Tp. "}<br />
{" : d' . `b "}<br />
{" ; d' o `b ; "}<br />
{" / d; `b| "}<br />
{" /, $; @ `: "}<br />
{" /' $/ ; "}<br />
{" .' $/b o | "}<br />
{" .' d$/$; : "}<br />
{" / .d/$/$; , ; "}<br />
{" d .dNITESEC $ | "}<br />
{" :bp.__.gNITESEC/$ :$ ; "}<br />
{" NITESECNITESECNIT /$b : "}<br /></>,
[],
true,
true,
@ -366,9 +369,9 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// City factions, essentially governments
Aevum: new FactionInfo(
[FactionNames.Aevum]: new FactionInfo(
<>The Silicon City.</>,
["Chongqing", "New Tokyo", "Ishima", "Volhaven"],
[FactionNames.Chongqing, FactionNames.NewTokyo, FactionNames.Ishima, FactionNames.Volhaven],
true,
true,
true,
@ -376,9 +379,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
false,
),
Chongqing: new FactionInfo(
[FactionNames.Chongqing]: new FactionInfo(
<>Serve the People.</>,
["Sector-12", "Aevum", "Volhaven"],
[FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true,
true,
true,
@ -386,9 +389,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
false,
),
Ishima: new FactionInfo(
[FactionNames.Ishima]: new FactionInfo(
<>The East Asian Order of the Future.</>,
["Sector-12", "Aevum", "Volhaven"],
[FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true,
true,
true,
@ -396,9 +399,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
false,
),
"New Tokyo": new FactionInfo(
[FactionNames.NewTokyo]: new FactionInfo(
<>Asia's World City.</>,
["Sector-12", "Aevum", "Volhaven"],
[FactionNames.Sector12, FactionNames.Aevum, FactionNames.Volhaven],
true,
true,
true,
@ -406,9 +409,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
false,
),
"Sector-12": new FactionInfo(
[FactionNames.Sector12]: new FactionInfo(
<>The City of the Future.</>,
["Chongqing", "New Tokyo", "Ishima", "Volhaven"],
[FactionNames.Chongqing, FactionNames.NewTokyo, FactionNames.Ishima, FactionNames.Volhaven],
true,
true,
true,
@ -416,9 +419,9 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
false,
),
Volhaven: new FactionInfo(
[FactionNames.Volhaven]: new FactionInfo(
<>Benefit, Honor, and Glory.</>,
["Chongqing", "Sector-12", "New Tokyo", "Aevum", "Ishima"],
[FactionNames.Chongqing, FactionNames.Sector12, FactionNames.NewTokyo, FactionNames.Aevum, FactionNames.Ishima],
true,
true,
true,
@ -428,7 +431,7 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// 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.</>,
[],
true,
@ -439,7 +442,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
),
"The Dark Army": new FactionInfo(
[FactionNames.TheDarkArmy]: new FactionInfo(
<>The World doesn't care about right or wrong. It only cares about power.</>,
[],
true,
@ -450,9 +453,9 @@ export const FactionInfos: IMap<FactionInfo> = {
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
@ -472,7 +475,7 @@ export const FactionInfos: IMap<FactionInfo> = {
false,
),
Tetrads: new FactionInfo(
[FactionNames.Tetrads]: new FactionInfo(
<>Following the mandate of Heaven and carrying out the way.</>,
[],
false,
@ -483,14 +486,14 @@ export const FactionInfos: IMap<FactionInfo> = {
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.
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
@ -508,13 +511,13 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// Special Factions
Bladeburners: new FactionInfo(
[FactionNames.Bladeburners]: new FactionInfo(
(
<>
It's too bad they won't live. But then again, who does?
<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.
</>
),
@ -528,7 +531,7 @@ export const FactionInfos: IMap<FactionInfo> = {
),
// prettier-ignore
"Church of the Machine God": new FactionInfo(<>
[FactionNames.ChurchOfTheMachineGod]: new FactionInfo(<>
{" `` "}<br />
{" -odmmNmds: "}<br />
{" `hNmo:..-omNh. "}<br />

@ -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 Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { FactionNames } from "../data/FactionNames";
interface IProps {
open: boolean;
@ -27,7 +28,7 @@ export function CreateGangModal(props: IProps): React.ReactElement {
"is not as important.";
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 {

@ -21,6 +21,8 @@ import { CreateGangModal } from "./CreateGangModal";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot";
import { FactionNames } from "../data/FactionNames";
import { GangConstants } from "../../Gang/data/Constants";
type IProps = {
faction: Faction;
@ -50,16 +52,6 @@ const augmentationsInfo =
"your abilities.";
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 {
faction: Faction;
rerender: () => void;
@ -111,9 +103,9 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
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.getGangName() !== faction.name) {
canAccessGang = false;

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

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

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

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

@ -17,36 +17,14 @@ import {
import { numeralWrapper } from "../../ui/numeralFormat";
import { GangMember } from "../GangMember";
import { Settings } from "../../Settings/Settings";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { MoneyRate } from "../../ui/React/MoneyRate";
import { StatsRow } from "../../ui/React/StatsRow";
import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview";
interface IProps {
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 {
const classes = useStyles();
@ -102,12 +80,12 @@ export function GangMemberStats(props: IProps): React.ReactElement {
>
<Table sx={{ display: 'table', mb: 1, width: '100%' }}>
<TableBody>
{generateTableRow("Hacking", props.member.hack, props.member.hack_exp, Settings.theme.hack, classes)}
{generateTableRow("Strength", props.member.str, props.member.str_exp, Settings.theme.combat, classes)}
{generateTableRow("Defense", props.member.def, props.member.def_exp, Settings.theme.combat, classes)}
{generateTableRow("Dexterity", props.member.dex, props.member.dex_exp, Settings.theme.combat, classes)}
{generateTableRow("Agility", props.member.agi, props.member.agi_exp, Settings.theme.combat, classes)}
{generateTableRow("Charisma", props.member.cha, props.member.cha_exp, Settings.theme.cha, classes)}
<StatsRow name="Hacking" color={Settings.theme.hack} data={{ level: props.member.hack, exp: props.member.hack_exp }} />
<StatsRow name="Strength" color={Settings.theme.combat} data={{ level: props.member.str, exp: props.member.str_exp }} />
<StatsRow name="Defense" color={Settings.theme.combat} data={{ level: props.member.def, exp: props.member.def_exp }} />
<StatsRow name="Dexterity" color={Settings.theme.combat} data={{ level: props.member.dex, exp: props.member.dex_exp }} />
<StatsRow name="Agility" color={Settings.theme.combat} data={{ level: props.member.agi, exp: props.member.agi_exp }} />
<StatsRow name="Charisma" color={Settings.theme.cha} data={{ level: props.member.cha, exp: props.member.cha_exp }} />
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<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.
*/
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 { formatNumber } from "../../utils/StringHelperFunctions";
import { AllGangs } from "../AllGangs";
import { useGang } from "./Context";
import Typography from "@mui/material/Typography";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import Tooltip from "@mui/material/Tooltip";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import { AllGangs } from "../AllGangs";
import { useGang } from "./Context";
import { TerritoryInfoModal } from "./TerritoryInfoModal";
export function TerritorySubpage(): React.ReactElement {
const gang = useGang();
const gangNames = Object.keys(AllGangs).filter((g) => g != gang.facName);
const [infoOpen, setInfoOpen] = useState(false);
return (
<>
<Container disableGutters maxWidth="md" sx={{ mx: 0 }}>
<Typography>
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.
<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>
<Button onClick={() => setInfoOpen(true)} sx={{ my: 1 }}>
<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
control={<Switch
checked={gang.territoryWarfareEngaged}
onChange={(event) => (gang.territoryWarfareEngaged = event.target.checked)}
/>
}
label={
<Tooltip
title={
<Typography>
/>}
label={<Tooltip
title={<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>}>
<Typography>Engage in Territory Warfare</Typography>
</Tooltip>
}
/>
<br />
<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>
</Tooltip>} />
<br />
<FormControlLabel
control={
<Switch
control={<Switch
checked={gang.notifyMemberDeath}
onChange={(event) => (gang.notifyMemberDeath = event.target.checked)}
/>
}
label={
<Tooltip
title={
<Typography>
/>}
label={<Tooltip
title={<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>}>
<Typography>Notify about Gang Member Deaths</Typography>
</Tooltip>
}
/>
<br />
<Paper>
</Tooltip>} />
<Typography>
<b>
<u>{gang.facName}</u>
</b>
<br />
Power: {formatNumber(AllGangs[gang.facName].power, 6)}
<br />
Territory: {formatTerritory(AllGangs[gang.facName].territory)}%
<br />
<br />
<b>Territory Clash Chance:</b> {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)} <br />
<b>Power:</b> {formatNumber(AllGangs[gang.facName].power, 3)} <br />
<b>Territory:</b> {formatTerritory(AllGangs[gang.facName].territory)}% <br />
</Typography>
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
{gangNames.map((name) => (
<OtherGangTerritory key={name} name={name} />
))}
</Paper>
</>
</Box>
<TerritoryInfoModal open={infoOpen} onClose={() => setInfoOpen(false)} />
</Container >
);
}
function formatTerritory(n: number): string {
const v = n * 100;
const precision = 3;
if (v <= 0) {
return formatNumber(0, 2);
return formatNumber(0, precision);
} else if (v >= 100) {
return formatNumber(100, 2);
return formatNumber(100, precision);
} 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 clashVictoryChance = playerPower / (power + playerPower);
return (
<Typography>
<u>{props.name}</u>
<br />
Power: {formatNumber(power, 6)}
<br />
Territory: {formatTerritory(AllGangs[props.name].territory)}%<br />
Chance to win clash with this gang: {numeralWrapper.formatPercentage(clashVictoryChance, 3)}
<br />
<br />
<Box component={Paper} sx={{ p: 1 }}>
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
{props.name}
</Typography>
<Typography>
<b>Power:</b> {formatNumber(power, 3)} <br />
<b>Territory:</b> {formatTerritory(AllGangs[props.name].territory)}% <br />
<b>Clash Win Chance:</b> {numeralWrapper.formatPercentage(clashVictoryChance, 3)}
</Typography>
</Box>
);
}

@ -16,6 +16,7 @@ import Typography from "@mui/material/Typography";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import { SelectChangeEvent } from "@mui/material/Select";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps {
player: IPlayer;
@ -28,7 +29,7 @@ const serversMap: { [key: string]: string } = {};
export function HacknetUpgradeElem(props: IProps): React.ReactElement {
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 {
setSelectedServer(event.target.value);

@ -1,6 +1,8 @@
import { CityName } from './../Locations/data/CityNames';
import { Literature } from "./Literature";
import { LiteratureNames } from "./data/LiteratureNames";
import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames";
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, " +
"are composed entirely of organic substances. For this reason, Synthoids are virtually identical to " +
"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 " +
"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 " +
"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 " +
"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>" +
"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. " +
"This hack went undetected and for months OmniTek unknowingly churned out legions of Synthoids embedded with this " +
`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 ${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 " +
"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, " +
"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, " +
"outsmarting them at every turn.<br><br>" +
"It wasn't until the sacrifice of an elite international military taskforce, called the Bladeburners, that humanity " +
"was finally able to defeat the Synthoids. The Bladeburners' final act was a suicide bombing mission that " +
`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 ${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 " +
"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>" +
"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 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 " +
@ -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>" +
"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 " +
"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>" +
"Nobody knows what happened to the terrorist group Ascendis Totalis.";
Literatures[fn] = new Literature(title, fn, txt);
@ -199,9 +201,9 @@ export const Literatures: IMap<Literature> = {};
title = "Brighter than the Sun";
fn = LiteratureNames.BrighterThanTheSun;
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 " +
"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>" +
"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 " +
@ -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 " +
"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 " +
"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 " +
"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 " +
@ -234,11 +236,11 @@ export const Literatures: IMap<Literature> = {};
"And now democracy is dead, in the USA.";
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;
txt =
"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 " +
"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>" +
@ -246,7 +248,7 @@ export const Literatures: IMap<Literature> = {};
"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 " +
"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);
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 " +
"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 " +
"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 " +
"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>" +
"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 " +
"help the oppressed by attacking the elite and powerful. Others, such as NiteSec, are hacktivist groups " +
`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 ${FactionNames.NiteSec}, are hacktivist groups ` +
"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);
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 " +
"improved our daily lives. However, the question still remains of whether AI will ever be advanced enough to re-create " +
"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 " +
"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>" +
@ -340,9 +342,9 @@ export const Literatures: IMap<Literature> = {};
fn = LiteratureNames.TensionsInTechRace;
txt =
"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. " +
"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. " +
"Defense contractors such as " +
"DeltaOne and AeroCorp have been working with the CIA and NSA to prepare " +
@ -381,13 +383,13 @@ export const Literatures: IMap<Literature> = {};
txt =
"WAKE UP SHEEPLE<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>" +
"Yes, the Illuminati of legends. The ancient secret society that controls the entire " +
`THE ${FactionNames.Illuminati.toUpperCase()} ARE THE SECRET RULERS OF THE WORLD!<br><br>` +
`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 " +
"that have penetrated every major government, financial agency, and corporation in the last " +
"three hundred years.<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>" +
"THEY ARE ALL AROUND YOU<br><br>" +
"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. " +
"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. " +
"The most notable of these is the Tetrads.<br><br>" +
"It is widely believed that the 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 " +
"Triads were losing their purpose and direction. The Tetrads started off as a small group that mainly engaged " +
`The most notable of these is the ${FactionNames.Tetrads}.<br><br>` +
`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 ${FactionNames.Tetrads}, all of whom were ex-Triad members, believed that the ` +
`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 " +
"drug trade in all of the major Asian cities. They quickly became the most powerful crime syndicate in the " +
"continent.<br><br>" +
"Not much else is known about the 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 " +
`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 ${FactionNames.Tetrads} have infiltrated the governments ` +
"and powerful corporations in Asia, which has helped faciliate their recent rapid rise.";
Literatures[fn] = new Literature(title, fn, txt);

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

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

@ -8,6 +8,7 @@ import { GetServer } from "../Server/AllServers";
import { Settings } from "../Settings/Settings";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver } from "../utils/JSONReviver";
import { FactionNames } from "../Faction/data/FactionNames";
//Sends message to player, including a pop up
function sendMessage(msg: Message, forced = false): void {
@ -139,7 +140,7 @@ function initMessages(): void {
AddToAllMessages(
new Message(
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>" +
"You should join them, garner their favor, and " +
"exploit them for their Augmentations. But do not trust them. " +
@ -152,7 +153,7 @@ function initMessages(): void {
MessageFilenames.Jumper2,
"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 " +
"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",
),
);
@ -160,7 +161,7 @@ function initMessages(): void {
new Message(
MessageFilenames.Jumper3,
"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",
),
);
@ -181,7 +182,7 @@ function initMessages(): void {
"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>" +
"But first, you must pass our test. Find and install the backdoor on our server. <br><br>" +
"-CyberSec",
`-${FactionNames.CyberSec}`,
),
);
AddToAllMessages(
@ -193,7 +194,7 @@ function initMessages(): void {
"and ideas with bullets. <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." +
"<br><br>-NiteSec",
`<br><br>-${FactionNames.NiteSec}`,
),
);
AddToAllMessages(

@ -3,6 +3,7 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { Factions } from "../Faction/Factions";
import { Faction } from "../Faction/Faction";
import { GetServer } from "../Server/AllServers";
import { FactionNames } from "../Faction/data/FactionNames";
function allFactionAugs(p: IPlayer, f: Faction): boolean {
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",
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 => {
return allFactionAugs(p, Factions["CyberSec"]);
return allFactionAugs(p, Factions[FactionNames.CyberSec]);
},
},
{
title: "Join the faction hinted at in nitesec-test.msg",
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 => {
return allFactionAugs(p, Factions["NiteSec"]);
return allFactionAugs(p, Factions[FactionNames.NiteSec]);
},
},
{
title: "Join the faction hinted at in j3.msg",
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 => {
return allFactionAugs(p, Factions["The Black Hand"]);
return allFactionAugs(p, Factions[FactionNames.TheBlackHand]);
},
},
{
title: "Join the faction hinted at in 19dfj3l1nd.msg",
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 => {
return allFactionAugs(p, Factions["BitRunners"]);
return allFactionAugs(p, Factions[FactionNames.BitRunners]);
},
},
{
title: "Complete fl1ght.exe",
fulfilled: (p: IPlayer): boolean => {
// 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 => {
return p.augmentations.some((aug) => aug.name == "The Red Pill");
},

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

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

@ -42,6 +42,7 @@ import { Terminal } from "../Terminal";
import { calculateHackingTime } from "../Hacking";
import { Server } from "../Server/Server";
import { netscriptCanHack } from "../Hacking/netscriptCanHack";
import { FactionNames } from "../Faction/data/FactionNames";
export function NetscriptSingularity(
player: IPlayer,
@ -282,7 +283,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) {
workerScript.log(
"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;
}
@ -294,7 +295,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) {
workerScript.log(
"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;
}
@ -306,7 +307,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) {
workerScript.log(
"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;
}
@ -369,7 +370,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) {
workerScript.log(
"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;
}
@ -381,7 +382,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) {
workerScript.log(
"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;
}
@ -393,7 +394,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) {
workerScript.log(
"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;
}
@ -405,7 +406,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) {
workerScript.log(
"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;
}
@ -417,7 +418,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) {
workerScript.log(
"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;
}
@ -1033,85 +1034,85 @@ export function NetscriptSingularity(
const fac = Factions[name];
// Arrays listing factions that allow each time of work
const hackAvailable = [
"Illuminati",
"Daedalus",
"The Covenant",
"ECorp",
"MegaCorp",
"Bachman & Associates",
"Blade Industries",
"NWO",
"Clarke Incorporated",
"OmniTek Incorporated",
"Four Sigma",
"KuaiGong International",
"Fulcrum Secret Technologies",
"BitRunners",
"The Black Hand",
"NiteSec",
"Chongqing",
"Sector-12",
"New Tokyo",
"Aevum",
"Ishima",
"Volhaven",
"Speakers for the Dead",
"The Dark Army",
"The Syndicate",
"Silhouette",
"Netburners",
"Tian Di Hui",
"CyberSec",
FactionNames.Illuminati as string,
FactionNames.Daedalus as string,
FactionNames.TheCovenant as string,
FactionNames.ECorp as string,
FactionNames.MegaCorp as string,
FactionNames.BachmanAssociates as string,
FactionNames.Bladeburners as string,
FactionNames.NWO as string,
FactionNames.ClarkeIncorporated as string,
FactionNames.OmniTekIncorporated as string,
FactionNames.FourSigma as string,
FactionNames.KuaiGongInternational as string,
FactionNames.FulcrumSecretTechnologies as string,
FactionNames.BitRunners as string,
FactionNames.TheBlackHand as string,
FactionNames.NiteSec as string,
FactionNames.Chongqing as string,
FactionNames.Sector12 as string,
FactionNames.NewTokyo as string,
FactionNames.Aevum as string,
FactionNames.Ishima as string,
FactionNames.Volhaven as string,
FactionNames.SpeakersForTheDead as string,
FactionNames.TheDarkArmy as string,
FactionNames.TheSyndicate as string,
FactionNames.Silhouette as string,
FactionNames.Netburners as string,
FactionNames.TianDiHui as string,
FactionNames.CyberSec as string,
];
const fdWkAvailable = [
"Illuminati",
"Daedalus",
"The Covenant",
"ECorp",
"MegaCorp",
"Bachman & Associates",
"Blade Industries",
"NWO",
"Clarke Incorporated",
"OmniTek Incorporated",
"Four Sigma",
"KuaiGong International",
"The Black Hand",
"Chongqing",
"Sector-12",
"New Tokyo",
"Aevum",
"Ishima",
"Volhaven",
"Speakers for the Dead",
"The Dark Army",
"The Syndicate",
"Silhouette",
"Tetrads",
"Slum Snakes",
FactionNames.Illuminati as string,
FactionNames.Daedalus as string,
FactionNames.TheCovenant as string,
FactionNames.ECorp as string,
FactionNames.MegaCorp as string,
FactionNames.BachmanAssociates as string,
FactionNames.Bladeburners as string,
FactionNames.NWO as string,
FactionNames.ClarkeIncorporated as string,
FactionNames.OmniTekIncorporated as string,
FactionNames.FourSigma as string,
FactionNames.KuaiGongInternational as string,
FactionNames.TheBlackHand as string,
FactionNames.Chongqing as string,
FactionNames.Sector12 as string,
FactionNames.NewTokyo as string,
FactionNames.Aevum as string,
FactionNames.Ishima as string,
FactionNames.Volhaven as string,
FactionNames.SpeakersForTheDead as string,
FactionNames.TheDarkArmy as string,
FactionNames.TheSyndicate as string,
FactionNames.Silhouette as string,
FactionNames.Tetrads as string,
FactionNames.SlumSnakes as string,
];
const scWkAvailable = [
"ECorp",
"MegaCorp",
"Bachman & Associates",
"Blade Industries",
"NWO",
"Clarke Incorporated",
"OmniTek Incorporated",
"Four Sigma",
"KuaiGong International",
"Fulcrum Secret Technologies",
"Chongqing",
"Sector-12",
"New Tokyo",
"Aevum",
"Ishima",
"Volhaven",
"Speakers for the Dead",
"The Syndicate",
"Tetrads",
"Slum Snakes",
"Tian Di Hui",
FactionNames.ECorp as string,
FactionNames.MegaCorp as string,
FactionNames.BachmanAssociates as string,
FactionNames.Bladeburners as string,
FactionNames.NWO as string,
FactionNames.ClarkeIncorporated as string,
FactionNames.OmniTekIncorporated as string,
FactionNames.FourSigma as string,
FactionNames.KuaiGongInternational as string,
FactionNames.FulcrumSecretTechnologies as string,
FactionNames.Chongqing as string,
FactionNames.Sector12 as string,
FactionNames.NewTokyo as string,
FactionNames.Aevum as string,
FactionNames.Ishima as string,
FactionNames.Volhaven as string,
FactionNames.SpeakersForTheDead as string,
FactionNames.TheSyndicate as string,
FactionNames.Tetrads as string,
FactionNames.SlumSnakes as string,
FactionNames.TianDiHui as string,
];
switch (type.toLowerCase()) {

@ -8,7 +8,7 @@ import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/St
import { OrderTypes } from "../StockMarket/data/OrderTypes";
import { PositionTypes } from "../StockMarket/data/PositionTypes";
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 { 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");
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 { calculateClassEarnings } from "../formulas/work";
import { achievements } from "../../Achievements/Achievements";
import { FactionNames } from "../../Faction/data/FactionNames";
export function init(this: IPlayer): void {
/* Initialize Player's home computer */
@ -1811,7 +1812,6 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
}
return false;
}
return false; //Same job, do nothing
}
}
@ -2144,7 +2144,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Illuminati
const illuminatiFac = Factions["Illuminati"];
const illuminatiFac = Factions[FactionNames.Illuminati];
if (
!illuminatiFac.isBanned &&
!illuminatiFac.isMember &&
@ -2161,7 +2161,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Daedalus
const daedalusFac = Factions["Daedalus"];
const daedalusFac = Factions[FactionNames.Daedalus];
if (
!daedalusFac.isBanned &&
!daedalusFac.isMember &&
@ -2175,7 +2175,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//The Covenant
const covenantFac = Factions["The Covenant"];
const covenantFac = Factions[FactionNames.TheCovenant];
if (
!covenantFac.isBanned &&
!covenantFac.isMember &&
@ -2192,7 +2192,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//ECorp
const ecorpFac = Factions["ECorp"];
const ecorpFac = Factions[FactionNames.ECorp];
if (
!ecorpFac.isBanned &&
!ecorpFac.isMember &&
@ -2203,7 +2203,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//MegaCorp
const megacorpFac = Factions["MegaCorp"];
const megacorpFac = Factions[FactionNames.MegaCorp];
if (
!megacorpFac.isBanned &&
!megacorpFac.isMember &&
@ -2214,7 +2214,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Bachman & Associates
const bachmanandassociatesFac = Factions["Bachman & Associates"];
const bachmanandassociatesFac = Factions[FactionNames.BachmanAssociates];
if (
!bachmanandassociatesFac.isBanned &&
!bachmanandassociatesFac.isMember &&
@ -2225,7 +2225,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Blade Industries
const bladeindustriesFac = Factions["Blade Industries"];
const bladeindustriesFac = Factions[FactionNames.BladeIndustries];
if (
!bladeindustriesFac.isBanned &&
!bladeindustriesFac.isMember &&
@ -2236,7 +2236,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//NWO
const nwoFac = Factions["NWO"];
const nwoFac = Factions[FactionNames.NWO];
if (
!nwoFac.isBanned &&
!nwoFac.isMember &&
@ -2247,7 +2247,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Clarke Incorporated
const clarkeincorporatedFac = Factions["Clarke Incorporated"];
const clarkeincorporatedFac = Factions[FactionNames.ClarkeIncorporated];
if (
!clarkeincorporatedFac.isBanned &&
!clarkeincorporatedFac.isMember &&
@ -2258,7 +2258,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//OmniTek Incorporated
const omnitekincorporatedFac = Factions["OmniTek Incorporated"];
const omnitekincorporatedFac = Factions[FactionNames.OmniTekIncorporated];
if (
!omnitekincorporatedFac.isBanned &&
!omnitekincorporatedFac.isMember &&
@ -2269,7 +2269,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Four Sigma
const foursigmaFac = Factions["Four Sigma"];
const foursigmaFac = Factions[FactionNames.FourSigma];
if (
!foursigmaFac.isBanned &&
!foursigmaFac.isMember &&
@ -2280,7 +2280,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//KuaiGong International
const kuaigonginternationalFac = Factions["KuaiGong International"];
const kuaigonginternationalFac = Factions[FactionNames.KuaiGongInternational];
if (
!kuaigonginternationalFac.isBanned &&
!kuaigonginternationalFac.isMember &&
@ -2291,11 +2291,11 @@ 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
const fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"];
const fulcrumsecrettechonologiesFac = Factions[FactionNames.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) {
console.error("Could not find Fulcrum Secret Technologies Server");
console.error(`Could not find ${FactionNames.FulcrumSecretTechnologies} Server`);
} else if (
!fulcrumsecrettechonologiesFac.isBanned &&
!fulcrumsecrettechonologiesFac.isMember &&
@ -2307,11 +2307,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//BitRunners
const bitrunnersFac = Factions["BitRunners"];
const bitrunnersFac = Factions[FactionNames.BitRunners];
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) {
console.error("Could not find BitRunners Server");
console.error(`Could not find ${FactionNames.BitRunners} Server`);
} else if (
!bitrunnersFac.isBanned &&
!bitrunnersFac.isMember &&
@ -2323,11 +2323,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
//The Black Hand
const theblackhandFac = Factions["The Black Hand"];
const theblackhandFac = Factions[FactionNames.TheBlackHand];
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) {
console.error("Could not find The Black Hand Server");
console.error(`Could not find ${FactionNames.TheBlackHand} Server`);
} else if (
!theblackhandFac.isBanned &&
!theblackhandFac.isMember &&
@ -2338,11 +2338,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//NiteSec
const nitesecFac = Factions["NiteSec"];
const nitesecFac = Factions[FactionNames.NiteSec];
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) {
console.error("Could not find NiteSec Server");
console.error(`Could not find ${FactionNames.NiteSec} Server`);
} else if (
!nitesecFac.isBanned &&
!nitesecFac.isMember &&
@ -2353,7 +2353,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Chongqing
const chongqingFac = Factions["Chongqing"];
const chongqingFac = Factions[FactionNames.Chongqing];
if (
!chongqingFac.isBanned &&
!chongqingFac.isMember &&
@ -2365,7 +2365,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Sector-12
const sector12Fac = Factions["Sector-12"];
const sector12Fac = Factions[FactionNames.Sector12];
if (
!sector12Fac.isBanned &&
!sector12Fac.isMember &&
@ -2377,7 +2377,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//New Tokyo
const newtokyoFac = Factions["New Tokyo"];
const newtokyoFac = Factions[FactionNames.NewTokyo];
if (
!newtokyoFac.isBanned &&
!newtokyoFac.isMember &&
@ -2389,7 +2389,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Aevum
const aevumFac = Factions["Aevum"];
const aevumFac = Factions[FactionNames.Aevum];
if (
!aevumFac.isBanned &&
!aevumFac.isMember &&
@ -2401,7 +2401,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Ishima
const ishimaFac = Factions["Ishima"];
const ishimaFac = Factions[FactionNames.Ishima];
if (
!ishimaFac.isBanned &&
!ishimaFac.isMember &&
@ -2413,7 +2413,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Volhaven
const volhavenFac = Factions["Volhaven"];
const volhavenFac = Factions[FactionNames.Volhaven];
if (
!volhavenFac.isBanned &&
!volhavenFac.isMember &&
@ -2425,7 +2425,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Speakers for the Dead
const speakersforthedeadFac = Factions["Speakers for the Dead"];
const speakersforthedeadFac = Factions[FactionNames.SpeakersForTheDead];
if (
!speakersforthedeadFac.isBanned &&
!speakersforthedeadFac.isMember &&
@ -2444,7 +2444,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//The Dark Army
const thedarkarmyFac = Factions["The Dark Army"];
const thedarkarmyFac = Factions[FactionNames.TheDarkArmy];
if (
!thedarkarmyFac.isBanned &&
!thedarkarmyFac.isMember &&
@ -2464,7 +2464,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//The Syndicate
const thesyndicateFac = Factions["The Syndicate"];
const thesyndicateFac = Factions[FactionNames.TheSyndicate];
if (
!thesyndicateFac.isBanned &&
!thesyndicateFac.isMember &&
@ -2484,7 +2484,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Silhouette
const silhouetteFac = Factions["Silhouette"];
const silhouetteFac = Factions[FactionNames.Silhouette];
if (
!silhouetteFac.isBanned &&
!silhouetteFac.isMember &&
@ -2499,7 +2499,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Tetrads
const tetradsFac = Factions["Tetrads"];
const tetradsFac = Factions[FactionNames.Tetrads];
if (
!tetradsFac.isBanned &&
!tetradsFac.isMember &&
@ -2515,7 +2515,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//SlumSnakes
const slumsnakesFac = Factions["Slum Snakes"];
const slumsnakesFac = Factions[FactionNames.SlumSnakes];
if (
!slumsnakesFac.isBanned &&
!slumsnakesFac.isMember &&
@ -2531,7 +2531,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Netburners
const netburnersFac = Factions["Netburners"];
const netburnersFac = Factions[FactionNames.Netburners];
let totalHacknetRam = 0;
let totalHacknetCores = 0;
let totalHacknetLevels = 0;
@ -2563,7 +2563,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//Tian Di Hui
const tiandihuiFac = Factions["Tian Di Hui"];
const tiandihuiFac = Factions[FactionNames.TianDiHui];
if (
!tiandihuiFac.isBanned &&
!tiandihuiFac.isMember &&
@ -2576,11 +2576,11 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
}
//CyberSec
const cybersecFac = Factions["CyberSec"];
const cybersecFac = Factions[FactionNames.CyberSec];
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) {
console.error("Could not find CyberSec Server");
console.error(`Could not find ${FactionNames.CyberSec} Server`);
} else if (
!cybersecFac.isBanned &&
!cybersecFac.isMember &&
@ -2637,7 +2637,7 @@ export function gainCodingContractReward(this: IPlayer, reward: ICodingContractR
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty;
// 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) => {
return !specialFactions.includes(f);
});
@ -2656,7 +2656,6 @@ export function gainCodingContractReward(this: IPlayer, reward: ICodingContractR
Factions[facName].playerReputation += gainPerFaction;
}
return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`;
break;
case CodingContractRewardType.CompanyReputation: {
if (reward.name == null || !(Companies[reward.name] instanceof Company)) {
//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 { IPlayer } from "../IPlayer";
@ -80,10 +81,10 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
}
for (const facName of p.factions) {
if (facName === "Bladeburners") {
if (facName === FactionNames.Bladeburners) {
continue;
}
if (facName === "Netburners") {
if (facName === FactionNames.Netburners) {
continue;
}
const fac: Faction | null = Factions[facName];

@ -16,6 +16,7 @@ import { use } from "../../../ui/Context";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { FactionNames } from "../../../Faction/data/FactionNames";
interface IProps {
open: boolean;
@ -76,7 +77,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
<>
<Typography>
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>
<Button disabled={purchaseDisabled} onClick={purchaseOnClick}>
Purchase -&nbsp;

@ -2,6 +2,7 @@ import React from "react";
import { Modal } from "../../../ui/React/Modal";
import Typography from "@mui/material/Typography";
import { FactionNames } from "../../../Faction/data/FactionNames";
interface IProps {
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>
<br />
<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>
<br />
<br />
@ -109,7 +110,7 @@ export function FAQModal({ open, onClose }: IProps): React.ReactElement {
<br />
<br />
<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.
</Typography>
</>

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

@ -1,34 +1,29 @@
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 { 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 { TravelModal } from "./TravelModal";
import { Money } from "../../../ui/React/Money";
import { MoneyRate } from "../../../ui/React/MoneyRate";
import { use } from "../../../ui/Context";
import { ReputationRate } from "../../../ui/React/ReputationRate";
import { StatsElement } from "./StatsElement";
import { StatsElement, EarningsElement } from "./StatsElement";
import { MoreStatsModal } from "./MoreStatsModal";
import { MoreEarningsModal } from "./MoreEarningsModal";
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 {
sleeve: Sleeve;
@ -141,42 +136,22 @@ export function SleeveElem(props: IProps): React.ReactElement {
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 (
<>
<Grid container component={Paper}>
<Grid item xs={3}>
<Box component={Paper} sx={{ width: 'auto' }}>
<Box sx={{ m: 1 }}>
<Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: '100%', gap: 1 }}>
<Box>
<StatsElement sleeve={props.sleeve} />
<Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: '100%' }}>
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
<span>
<Button onClick={() => setTravelOpen(true)} disabled={player.money < CONSTANTS.TravelCost}>
<Button
onClick={() => setTravelOpen(true)}
disabled={player.money < CONSTANTS.TravelCost}
sx={{ width: '100%', height: '100%' }}
>
Travel
</Button>
</span>
@ -185,14 +160,22 @@ export function SleeveElem(props: IProps): React.ReactElement {
title={props.sleeve.shock < 100 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
>
<span>
<Button onClick={() => setAugmentationsOpen(true)} disabled={props.sleeve.shock < 100}>
<Button
onClick={() => setAugmentationsOpen(true)}
disabled={props.sleeve.shock < 100}
sx={{ width: '100%', height: '100%' }}
>
Manage Augmentations
</Button>
</span>
</Tooltip>
</Grid>
<Grid item xs={5}>
</Box>
</Box>
<Box>
<EarningsElement sleeve={props.sleeve} />
<Box>
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
<Button onClick={setTask} sx={{ width: '100%' }}>Set Task</Button>
<Typography>{desc}</Typography>
<Typography>
{props.sleeve.currentTask === SleeveTaskType.Crime &&
@ -201,13 +184,8 @@ export function SleeveElem(props: IProps): React.ReactElement {
totalTicks: 25,
})}
</Typography>
<Button onClick={setTask}>Set Task</Button>
</Grid>
<Grid item xs={4}>
<StatsTable title="Earnings (Pre-Synchronization)" rows={data} />
<Button onClick={() => setEarningsOpen(true)}>More Earnings Info</Button>
</Grid>
</Grid>
</Box>
</Box>
<MoreStatsModal open={statsOpen} onClose={() => setStatsOpen(false)} sleeve={props.sleeve} />
<MoreEarningsModal open={earningsOpen} onClose={() => setEarningsOpen(false)} sleeve={props.sleeve} />
<TravelModal
@ -221,6 +199,8 @@ export function SleeveElem(props: IProps): React.ReactElement {
onClose={() => setAugmentationsOpen(false)}
sleeve={props.sleeve}
/>
</>
</Box>
</Box>
</Box >
);
}

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

@ -1,31 +1,110 @@
import { Sleeve } from "../Sleeve";
import { numeralWrapper } from "../../../ui/numeralFormat";
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 {
sleeve: Sleeve;
}
export function StatsElement(props: IProps): React.ReactElement {
const rows = [
[
"HP: ",
<>
{numeralWrapper.formatHp(props.sleeve.hp)} / {numeralWrapper.formatHp(props.sleeve.max_hp)}
</>,
],
["City: ", <>{props.sleeve.city}</>],
["Hacking: ", <>{numeralWrapper.formatSkill(props.sleeve.hacking)}</>],
["Strength: ", <>{numeralWrapper.formatSkill(props.sleeve.strength)}</>],
["Defense: ", <>{numeralWrapper.formatSkill(props.sleeve.defense)}</>],
["Dexterity: ", <>{numeralWrapper.formatSkill(props.sleeve.dexterity)}</>],
["Agility: ", <>{numeralWrapper.formatSkill(props.sleeve.agility)}</>],
["Charisma: ", <>{numeralWrapper.formatSkill(props.sleeve.charisma)}</>],
["Shock: ", <>{numeralWrapper.formatSleeveShock(100 - props.sleeve.shock)}</>],
["Sync: ", <>{numeralWrapper.formatSleeveSynchro(props.sleeve.sync)}</>],
["Memory: ", <>{numeralWrapper.formatSleeveMemory(props.sleeve.memory)}</>],
];
return <StatsTable rows={rows} />;
const classes = useStyles();
return (
<Table sx={{ display: 'table', mb: 1, width: '100%' }}>
<TableBody>
<StatsRow name="City" color={Settings.theme.primary} data={{ content: props.sleeve.city }} />
<StatsRow name="HP" color={Settings.theme.hp}
data={{ content: `${numeralWrapper.formatHp(props.sleeve.hp)} / ${numeralWrapper.formatHp(props.sleeve.max_hp)}` }}
/>
<StatsRow name="Hacking" color={Settings.theme.hack} data={{ level: props.sleeve.hacking, exp: props.sleeve.hacking_exp }} />
<StatsRow name="Strength" color={Settings.theme.combat} data={{ level: props.sleeve.strength, exp: props.sleeve.strength_exp }} />
<StatsRow name="Defense" color={Settings.theme.combat} data={{ level: props.sleeve.defense, exp: props.sleeve.defense_exp }} />
<StatsRow name="Dexterity" color={Settings.theme.combat} data={{ level: props.sleeve.dexterity, exp: props.sleeve.dexterity_exp }} />
<StatsRow name="Agility" color={Settings.theme.combat} data={{ level: props.sleeve.agility, exp: props.sleeve.agility_exp }} />
<StatsRow name="Charisma" color={Settings.theme.cha} data={{ level: props.sleeve.charisma, exp: props.sleeve.charisma_exp }} />
<TableRow>
<TableCell classes={{ root: classes.cellNone }}>
<br />
</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 Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import { FactionNames } from "../../../Faction/data/FactionNames";
const universitySelectorOptions: string[] = [
"Study Computer Science",
@ -55,7 +56,7 @@ function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
// Array of all factions that other sleeves are working for
const forbiddenFactions = ["Bladeburners"];
const forbiddenFactions = [FactionNames.Bladeburners as string];
if (player.gang) {
forbiddenFactions.push(player.gang.facName);
}
@ -278,7 +279,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
return (
<>
<Select onChange={onS0Change} value={s0}>
<Select onChange={onS0Change} value={s0} sx={{ width: '100%' }}>
{validActions.map((task) => (
<MenuItem key={task} value={task}>
{task}
@ -287,8 +288,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
</Select>
{!(details.first.length === 1 && details.first[0] === "------") && (
<>
<br />
<Select onChange={onS1Change} value={s1}>
<Select onChange={onS1Change} value={s1} sx={{ width: '100%' }}>
{details.first.map((detail) => (
<MenuItem key={detail} value={detail}>
{detail}
@ -299,8 +299,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
)}
{!(details2.length === 1 && details2[0] === "------") && (
<>
<br />
<Select onChange={onS2Change} value={s2}>
<Select onChange={onS2Change} value={s2} sx={{ width: '100%' }}>
{details2.map((detail) => (
<MenuItem key={detail} value={detail}>
{detail}

@ -1,3 +1,5 @@
import { FactionNames } from './Faction/data/FactionNames';
import { CityName } from './Locations/data/CityNames';
import { Augmentations } from "./Augmentation/Augmentations";
import { augmentationExists, initAugmentations } from "./Augmentation/AugmentationHelpers";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
@ -160,9 +162,7 @@ export function prestigeAugmentation(): void {
}
if (augmentationExists(AugmentationNames.StaneksGift1) && Augmentations[AugmentationNames.StaneksGift1].owned) {
// TODO(hydroflame): refactor faction names so we don't have to hard
// code strings.
joinFaction(Factions["Church of the Machine God"]);
joinFaction(Factions[FactionNames.ChurchOfTheMachineGod]);
}
staneksGift.prestigeAugmentation();
@ -279,7 +279,7 @@ export function prestigeSourceFile(flume: boolean): void {
}
if (Player.bitNodeN === 13) {
dialogBoxCreate("Trouble is brewing in Chongqing");
dialogBoxCreate(`Trouble is brewing in ${CityName.Chongqing}`);
}
// Reset Stock market, gang, and corporation

@ -11,6 +11,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { BitFlumeEvent } from "../../BitNode/ui/BitFlumeModal";
import { calculateHackingTime, calculateGrowTime, calculateWeakenTime } from "../../Hacking";
import { FactionNames } from "../../Faction/data/FactionNames";
function requireHackingLevel(lvl: number) {
return function (p: IPlayer) {
@ -316,7 +317,7 @@ export const programsMetadata: IProgramCreationParams[] = [
}
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.
*/
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
// 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[] = [
{
hackDifficulty: 99,
hostname: "ecorp",
hostname: LocationName.AevumECorp.toLowerCase(),
moneyAvailable: {
max: 70e9,
min: 30e9,
@ -95,7 +96,7 @@ export const serverMetadata: IServerMetadata[] = [
},
{
hackDifficulty: 99,
hostname: "megacorp",
hostname: LocationName.Sector12MegaCorp.toLowerCase(),
moneyAvailable: {
max: 60e9,
min: 40e9,
@ -163,7 +164,7 @@ export const serverMetadata: IServerMetadata[] = [
},
{
hackDifficulty: 99,
hostname: "nwo",
hostname: LocationName.VolhavenNWO.toLowerCase(),
literature: [LiteratureNames.TheHiddenWorld],
moneyAvailable: {
max: 40e9,
@ -423,7 +424,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 90,
min: 80,
},
hostname: "vitalife",
hostname: LocationName.NewTokyoVitaLife.toLowerCase(),
literature: [LiteratureNames.AGreenTomorrow],
maxRamExponent: {
max: 7,
@ -601,7 +602,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 90,
min: 80,
},
hostname: "aerocorp",
hostname: LocationName.AevumAeroCorp.toLowerCase(),
literature: [LiteratureNames.ManAndMachine],
moneyAvailable: {
max: 1200000000,
@ -726,7 +727,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 85,
min: 75,
},
hostname: "deltaone",
hostname: LocationName.Sector12DeltaOne.toLowerCase(),
moneyAvailable: {
max: 1700000000,
min: 1300000000,
@ -1120,7 +1121,7 @@ export const serverMetadata: IServerMetadata[] = [
max: 65,
min: 55,
},
hostname: "comptek",
hostname: LocationName.VolhavenCompuTek.toLowerCase(),
literature: [LiteratureNames.ManAndMachine],
moneyAvailable: {
max: 250000000,
@ -1201,7 +1202,7 @@ export const serverMetadata: IServerMetadata[] = [
},
{
hackDifficulty: 10,
hostname: "foodnstuff",
hostname: LocationName.Sector12FoodNStuff.toLowerCase(),
literature: [LiteratureNames.Sector12Crime],
maxRamExponent: 4,
moneyAvailable: 2000000,
@ -1381,7 +1382,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 20000000,
networkLayer: 1,
numOpenPortsRequired: 1,
organizationName: "Iron Gym Network",
organizationName: `${LocationName.Sector12IronGym} Network`,
requiredHackingSkill: 100,
serverGrowth: 20,
specialName: LocationName.Sector12IronGym,
@ -1503,7 +1504,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 0,
networkLayer: 4,
numOpenPortsRequired: 2,
organizationName: "NiteSec",
organizationName: FactionNames.NiteSec,
requiredHackingSkill: {
max: 220,
min: 202,
@ -1534,7 +1535,7 @@ export const serverMetadata: IServerMetadata[] = [
moneyAvailable: 0,
networkLayer: 2,
numOpenPortsRequired: 1,
organizationName: "CyberSec",
organizationName: FactionNames.CyberSec,
requiredHackingSkill: {
max: 60,
min: 51,

@ -8,3 +8,11 @@ export function getStockMarket4SDataCost(): number {
export function getStockMarket4STixApiCost(): number {
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 CheckIcon from "@mui/icons-material/Check";
import { StaticModal } from "../../ui/React/StaticModal";
import { FactionNames } from "../../Faction/data/FactionNames";
type IProps = {
initStockMarket: () => void;
@ -190,10 +191,10 @@ export function InfoAndPurchases(props: IProps): React.ReactElement {
</Typography>
<PurchaseTixApiAccessButton {...props} />
<Typography variant="h5" color="primary">
Four Sigma (4S) Market Data Feed
{FactionNames.FourSigma} (4S) Market Data Feed
</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)}>
<HelpIcon />
</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-next-line @typescript-eslint/no-unused-vars
import { jest, describe, expect, test } from "@jest/globals";
@ -37,7 +38,7 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
hackDifficulty: 1,
moneyAvailable: 70000,
numOpenPortsRequired: 0,
organizationName: LocationName.Aevum,
organizationName: CityName.Aevum,
requiredHackingSkill: 1,
serverGrowth: 3000,
});