diff --git a/src/Bladeburner/Actions/BlackOperation.ts b/src/Bladeburner/Actions/BlackOperation.ts index fd75cd469..ec0efd5b4 100644 --- a/src/Bladeburner/Actions/BlackOperation.ts +++ b/src/Bladeburner/Actions/BlackOperation.ts @@ -6,6 +6,8 @@ import { ActionClass, ActionParams } from "./Action"; import { operationSkillSuccessBonus, operationTeamSuccessBonus } from "./Operation"; import { getEnumHelper } from "../../utils/EnumHelper"; import type { TeamActionWithCasualties } from "./TeamCasualties"; +import { constructorsForReviver, Generic_fromJSON, type IReviverValue } from "../../utils/JSONReviver"; +import { clampInteger } from "../../utils/helpers/clampNumber"; interface BlackOpParams { name: BladeburnerBlackOpName; @@ -32,11 +34,11 @@ export class BlackOperation extends ActionClass implements TeamActionWithCasualt return getEnumHelper("BladeburnerBlackOpName").isMember(name); } - constructor(params: ActionParams & BlackOpParams) { + constructor(params: (ActionParams & BlackOpParams) | null = null) { super(params); - this.name = params.name; - this.reqdRank = params.reqdRank; - this.n = params.n; + this.name = params?.name ?? BladeburnerBlackOpName.OperationTyphoon; + this.reqdRank = params?.reqdRank ?? 0; + this.n = params?.n ?? 0; } getAvailability(bladeburner: Bladeburner): Availability { @@ -65,4 +67,23 @@ export class BlackOperation extends ActionClass implements TeamActionWithCasualt getTeamSuccessBonus = operationTeamSuccessBonus; getActionTypeSkillSuccessBonus = operationSkillSuccessBonus; + + toJSON(): IReviverValue { + return { + ctor: "BlackOperation", + data: { + teamCount: this.teamCount, + }, + }; + } + + loadData(loadedObject: BlackOperation): void { + this.teamCount = clampInteger(loadedObject.teamCount, 0); + } + + static fromJSON(value: IReviverValue): BlackOperation { + return Generic_fromJSON(BlackOperation, value.data); + } } + +constructorsForReviver.BlackOperation = BlackOperation; diff --git a/src/Bladeburner/Bladeburner.ts b/src/Bladeburner/Bladeburner.ts index c111b2ef2..b47ffbe99 100644 --- a/src/Bladeburner/Bladeburner.ts +++ b/src/Bladeburner/Bladeburner.ts @@ -47,7 +47,7 @@ import { createContracts, loadContractsData } from "./data/Contracts"; import { createOperations, loadOperationsData } from "./data/Operations"; import { clampInteger, clampNumber } from "../utils/helpers/clampNumber"; import { parseCommand } from "../Terminal/Parser"; -import { BlackOperations } from "./data/BlackOperations"; +import { createBlackOperations, loadBlackOperationsData } from "./data/BlackOperations"; import { GeneralActions } from "./data/GeneralActions"; import { PlayerObject } from "../PersonObjects/Player/PlayerObject"; import { Sleeve } from "../PersonObjects/Sleeve/Sleeve"; @@ -92,7 +92,7 @@ export class Bladeburner implements OperationTeam { } this._teamSize = newSize; // Reduce teamCount of actions if it's greater than the team size. - for (const action of [...Object.values(this.operations), ...Object.values(BlackOperations)]) { + for (const action of [...Object.values(this.operations), ...Object.values(this.blackOperations)]) { action.teamCount = Math.min(action.teamCount, this._teamSize); } } @@ -120,9 +120,13 @@ export class Bladeburner implements OperationTeam { staminaBonus = 0; maxStamina = 1; stamina = 1; - // Contracts and operations are stored on the Bladeburner object even though they are global so that they can utilize save/load of the main bladeburner object + // Contracts, operations and blackOps are stored on the Bladeburner object even though they are global so that they + // can utilize save/load of the main bladeburner object contracts: Record; operations: Record; + blackOperations: Record; + // Array for quick lookup by BlackOp number + blackOperationArray: BlackOperation[]; numBlackOpsComplete = 0; logging = { general: true, @@ -143,6 +147,11 @@ export class Bladeburner implements OperationTeam { constructor() { this.contracts = createContracts(); this.operations = createOperations(); + this.blackOperations = createBlackOperations(); + this.blackOperationArray = Object.values(this.blackOperations).sort((a, b) => (a.n < b.n ? -1 : 1)); + if (!this.blackOperationArray.every((blackOp, i) => blackOp.n === i)) { + throw new Error("blackOperationArray is not initialized with correct indices"); + } } // Initialization code that is dependent on Player is here instead of in the constructor @@ -1431,7 +1440,7 @@ export class Bladeburner implements OperationTeam { case BladeburnerActionType.Operation: return this.operations[actionId.name]; case BladeburnerActionType.BlackOp: - return BlackOperations[actionId.name]; + return this.blackOperations[actionId.name]; case BladeburnerActionType.General: return GeneralActions[actionId.name]; } @@ -1450,7 +1459,7 @@ export class Bladeburner implements OperationTeam { case BladeburnerActionType.Operation: return this.operations[name as BladeburnerOperationName]; case BladeburnerActionType.BlackOp: - return BlackOperations[name as BladeburnerBlackOpName]; + return this.blackOperations[name as BladeburnerBlackOpName]; } } @@ -1461,9 +1470,11 @@ export class Bladeburner implements OperationTeam { return id ? this.getActionObject(id) : null; } - static keysToSave = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers"] }); + static keysToSave = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers", "blackOperationArray"] }); // Don't load contracts or operations because of the special loading method they use, see fromJSON - static keysToLoad = getKeyList(Bladeburner, { removedKeys: ["skillMultipliers", "contracts", "operations"] }); + static keysToLoad = getKeyList(Bladeburner, { + removedKeys: ["skillMultipliers", "contracts", "operations", "blackOperations", "blackOperationArray"], + }); /** Serialize the current object to a JSON save state. */ toJSON(): IReviverValue { @@ -1473,9 +1484,10 @@ export class Bladeburner implements OperationTeam { /** Initializes a Bladeburner object from a JSON save state. */ static fromJSON(value: IReviverValue): Bladeburner { assertObject(value.data); - // operations and contracts are not loaded directly from the save, we load them in using a different method + // Contracts, operations, and black ops are not loaded directly from the save; they are loaded via a different method. const contractsData = value.data.contracts; const operationsData = value.data.operations; + const blackOperationsData = value.data.blackOperations; const bladeburner = Generic_fromJSON(Bladeburner, value.data, Bladeburner.keysToLoad); /** @@ -1496,10 +1508,11 @@ export class Bladeburner implements OperationTeam { bladeburner.automateActionLow = loadActionIdentifier(bladeburner.automateActionLow); } } - // Loading this way allows better typesafety and also allows faithfully reconstructing contracts/operations + // Loading this way allows better typesafety and also allows faithfully reconstructing contracts/operations/blackOps // even from save data that is missing a lot of static info about the objects. loadContractsData(contractsData, bladeburner.contracts); loadOperationsData(operationsData, bladeburner.operations); + loadBlackOperationsData(blackOperationsData, bladeburner.blackOperations); // Regenerate skill multiplier data, which is not included in savedata bladeburner.updateSkillMultipliers(); // If stamina or maxStamina is invalid, we set both of them to 1 and recalculate them. diff --git a/src/Bladeburner/data/BlackOperations.ts b/src/Bladeburner/data/BlackOperations.ts index 2026ad695..0512c5471 100644 --- a/src/Bladeburner/data/BlackOperations.ts +++ b/src/Bladeburner/data/BlackOperations.ts @@ -1,737 +1,752 @@ +import { assertLoadingType } from "../../utils/TypeAssertion"; import { BlackOperation } from "../Actions/BlackOperation"; import { BladeburnerBlackOpName, CityName, FactionName } from "@enums"; -export const BlackOperations: Record = { - [BladeburnerBlackOpName.OperationTyphoon]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationTyphoon, - n: 0, - baseDifficulty: 2000, - reqdRank: 2.5e3, - rankGain: 50, - rankLoss: 10, - hpLoss: 100, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - 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.\n\n" + - `The goal of ${BladeburnerBlackOpName.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.", - }), - [BladeburnerBlackOpName.OperationZero]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationZero, - n: 1, - baseDifficulty: 2500, - reqdRank: 5e3, - rankGain: 60, - rankLoss: 15, - hpLoss: 50, - weights: { - hacking: 0.2, - strength: 0.15, - defense: 0.15, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isStealth: true, - 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.\n\n" + - `The goal of ${BladeburnerBlackOpName.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.", - }), - [BladeburnerBlackOpName.OperationX]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationX, - n: 2, - baseDifficulty: 3000, - reqdRank: 7.5e3, - rankGain: 75, - rankLoss: 15, - hpLoss: 100, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "We have recently discovered an underground publication group called Samizdat. Even though most of their " + - "publications are nonsensical conspiracy theories, the average human is gullible enough to believe them. Many of " + - "their works discuss Synthoids and pose a threat to society. The publications are spreading rapidly in China and " + - "other Eastern countries.\n\n" + - "Samizdat has done a good job of keeping hidden and anonymous. However, we've just received intelligence that " + - `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.", - }), - [BladeburnerBlackOpName.OperationTitan]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationTitan, - n: 3, - baseDifficulty: 4000, - reqdRank: 10e3, - rankGain: 100, - rankLoss: 20, - hpLoss: 100, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "Several months ago, Titan Laboratories' Bioengineering department was infiltrated by Synthoids. As far as we " + - "know, Titan Laboratories' management has no knowledge about this. We don't know what the Synthoids are up to, " + - "but the research that they could be conducting using Titan Laboratories' vast resources is potentially very " + - "dangerous.\n\n" + - `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.", - }), - [BladeburnerBlackOpName.OperationAres]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationAres, - n: 4, - baseDifficulty: 5000, - reqdRank: 12.5e3, - rankGain: 125, - rankLoss: 20, - hpLoss: 200, - weights: { - hacking: 0, - strength: 0.25, - defense: 0.25, - dexterity: 0.25, - agility: 0.25, - charisma: 0, - intelligence: 0, - }, - decays: { - hacking: 0, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "One of our undercover agents, Agent Carter, has informed us of a massive weapons deal going down in Dubai " + - "between rogue Russian militants and a radical Synthoid community. These weapons are next-gen plasma and energy " + - "weapons. It is critical for the safety of humanity that this deal does not happen.\n\n" + - "Your task is to intercept the deal. Leave no survivors.", - }), - [BladeburnerBlackOpName.OperationArchangel]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationArchangel, - n: 5, - baseDifficulty: 7500, - reqdRank: 15e3, - rankGain: 200, - rankLoss: 20, - hpLoss: 25, - weights: { - hacking: 0, - strength: 0.2, - defense: 0.2, - dexterity: 0.3, - agility: 0.3, - charisma: 0, - intelligence: 0, - }, - decays: { - hacking: 0, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "Our analysts have discovered that the popular Red Rabbit brothel in Amsterdam is run and 'staffed' by MK-VI " + - "Synthoids. Intelligence suggests that the profit from this brothel is used to fund a large black market arms " + - "trafficking operation.\n\n" + - "The goal of this operation is to take out the leaders that are running the Red Rabbit brothel. Try to limit the " + - "number of other casualties, but do what you must to complete the mission.", - }), - [BladeburnerBlackOpName.OperationJuggernaut]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationJuggernaut, - n: 6, - baseDifficulty: 10e3, - reqdRank: 20e3, - rankGain: 300, - rankLoss: 40, - hpLoss: 300, - weights: { - hacking: 0, - strength: 0.25, - defense: 0.25, - dexterity: 0.25, - agility: 0.25, - charisma: 0, - intelligence: 0, - }, - decays: { - hacking: 0, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "The CIA has just encountered a new security threat. A new criminal group, led by a shadowy operative who calls " + - "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 has thus enlisted our help.\n\n" + - "Your mission is to eradicate Juggernaut and his followers.", - }), - [BladeburnerBlackOpName.OperationRedDragon]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationRedDragon, - n: 7, - baseDifficulty: 12.5e3, - reqdRank: 25e3, - rankGain: 500, - rankLoss: 50, - hpLoss: 500, - weights: { - hacking: 0.05, - strength: 0.2, - defense: 0.2, - dexterity: 0.25, - agility: 0.25, - charisma: 0, - intelligence: 0.05, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - `The ${FactionName.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.\n\n" + - `Your task is to infiltrate and destroy the ${FactionName.Tetrads}' base of operations in Los Angeles. ` + - "Intelligence tells us that their base houses one of their Synthoid manufacturing units.", - }), - [BladeburnerBlackOpName.OperationK]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationK, - n: 8, - baseDifficulty: 15e3, - reqdRank: 30e3, - rankGain: 750, - rankLoss: 60, - hpLoss: 1000, - weights: { - hacking: 0.05, - strength: 0.2, - defense: 0.2, - dexterity: 0.25, - agility: 0.25, - charisma: 0, - intelligence: 0.05, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "CODE RED SITUATION. Our intelligence tells us that VitaLife has discovered a new android cloning technology. " + - "This technology is supposedly capable of cloning Synthoids, not only physically but also their advanced AI " + - "modules. We do not believe that VitaLife is trying to use this technology illegally or maliciously, but if any " + - "Synthoids were able to infiltrate the corporation and take advantage of this technology, then the results would " + - "be catastrophic.\n\n" + - "We do not have the power or jurisdiction to shut this down through legal or political means, so we must resort " + - "to a covert operation. Your goal is to destroy this technology and eliminate anyone who was involved in its " + - "creation.", - }), - [BladeburnerBlackOpName.OperationDeckard]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationDeckard, - n: 9, - baseDifficulty: 20e3, - reqdRank: 40e3, - rankGain: 1e3, - rankLoss: 75, - hpLoss: 200, - weights: { - hacking: 0, - strength: 0.24, - defense: 0.24, - dexterity: 0.24, - agility: 0.24, - charisma: 0, - intelligence: 0.04, - }, - decays: { - hacking: 0, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "Despite your success in eliminating VitaLife's new android-replicating technology in " + - `${BladeburnerBlackOpName.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.\n\n" + - `The goal of ${BladeburnerBlackOpName.OperationDeckard} is to hunt down these Synthoids and retire them. I don't need to ` + - "tell you how critical this mission is.", - }), - [BladeburnerBlackOpName.OperationTyrell]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationTyrell, - n: 10, - baseDifficulty: 25e3, - reqdRank: 50e3, - rankGain: 1.5e3, - rankLoss: 100, - hpLoss: 500, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - `A week ago, ${FactionName.BladeIndustries} reported a small break-in at one of their ${CityName.Aevum} ` + - `Augmentation storage facilities. We figured out that ${FactionName.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.\n\n" + - "We cannot have Synthoids upgrading their already-enhanced abilities with augmentations. Your task is to hunt " + - `down associated members of ${FactionName.TheDarkArmy} and eliminate them.`, - }), - [BladeburnerBlackOpName.OperationWallace]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationWallace, - n: 11, - baseDifficulty: 30e3, - reqdRank: 75e3, - rankGain: 2e3, - rankLoss: 150, - hpLoss: 1500, - weights: { - hacking: 0, - strength: 0.24, - defense: 0.24, - dexterity: 0.24, - agility: 0.24, - charisma: 0, - intelligence: 0.04, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - `Based on information gathered from ${BladeburnerBlackOpName.OperationTyrell}, we've discovered that ` + - `${FactionName.TheDarkArmy} was well aware that there were Synthoids amongst their ranks. Even worse, we believe ` + - `that ${FactionName.TheDarkArmy} is working together with other criminal organizations such as ` + - `${FactionName.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.\n\n" + - "The best way to deal with this is to prevent it before it even happens. The goal of " + - `${BladeburnerBlackOpName.OperationWallace} is to destroy ${FactionName.TheDarkArmy} and ${FactionName.TheSyndicate} factions in ` + - `${CityName.Aevum} immediately. Leave no survivors.`, - }), - [BladeburnerBlackOpName.OperationShoulderOfOrion]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationShoulderOfOrion, - n: 12, - baseDifficulty: 35e3, - reqdRank: 100e3, - rankGain: 2.5e3, - rankLoss: 500, - hpLoss: 1500, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isStealth: true, - desc: - "China's Solaris Space Systems is secretly launching the first manned spacecraft in over a decade using " + - "Synthoids. We believe China is trying to establish the first off-world colonies.\n\n" + - "The mission is to prevent this launch without instigating an international conflict. When you accept this " + - "mission, you will be officially disavowed by the NSA and the national government until after you successfully " + - "return. In the event of failure, all of the operation's team members must not let themselves be captured alive.", - }), - [BladeburnerBlackOpName.OperationHyron]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationHyron, - n: 13, - baseDifficulty: 40e3, - reqdRank: 125e3, - rankGain: 3e3, - rankLoss: 1e3, - hpLoss: 500, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - `Our intelligence tells us that ${FactionName.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.\n\n" + - "I do not need to remind you why sentient-level AIs pose a serious threat to all of mankind.\n\n" + - `The research for this project is being conducted at one of ${FactionName.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.", - }), - [BladeburnerBlackOpName.OperationMorpheus]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationMorpheus, - n: 14, - baseDifficulty: 45e3, - reqdRank: 150e3, - rankGain: 4e3, - rankLoss: 1e3, - hpLoss: 100, - weights: { - hacking: 0.05, - strength: 0.15, - defense: 0.15, - dexterity: 0.3, - agility: 0.3, - charisma: 0, - intelligence: 0.05, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isStealth: true, - desc: - "DreamSense Technologies is an advertising company that uses special technology to transmit their ads into the " + - "people's dreams and subconscious. They do this using broadcast transmitter towers. Based on information from our " + - `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.\n\n" + - "The mission is to destroy this broadcast tower. Speed and stealth are of the utmost importance for this.", - }), - [BladeburnerBlackOpName.OperationIonStorm]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationIonStorm, - n: 15, - baseDifficulty: 50e3, - reqdRank: 175e3, - rankGain: 5e3, - rankLoss: 1e3, - hpLoss: 5000, - weights: { - hacking: 0, - strength: 0.24, - defense: 0.24, - dexterity: 0.24, - agility: 0.24, - charisma: 0, - intelligence: 0.04, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "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.\n\n" + - `This is a full-scale assault operation to find and retire all of these Synthoids in the ${CityName.Sector12} ` + - "Slums.", - }), - [BladeburnerBlackOpName.OperationAnnihilus]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationAnnihilus, - n: 16, - baseDifficulty: 55e3, - reqdRank: 200e3, - rankGain: 7.5e3, - rankLoss: 1e3, - hpLoss: 10e3, - weights: { - hacking: 0, - strength: 0.24, - defense: 0.24, - dexterity: 0.24, - agility: 0.24, - charisma: 0, - intelligence: 0.04, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - "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 '${FactionName.TheCovenant}'. We have no prior intelligence about this organization, so you ` + - "are going in blind.", - }), - [BladeburnerBlackOpName.OperationUltron]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationUltron, - n: 17, - baseDifficulty: 60e3, - reqdRank: 250e3, - rankGain: 10e3, - rankLoss: 2e3, - hpLoss: 10e3, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - isKill: true, - desc: - `${FactionName.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.\n\n" + - `${FactionName.OmniTekIncorporated} has also told us they believe someone has triggered this malfunction in a ` + - "large group of MK-VI Synthoids, and these newly radicalized Synthoids are now amassing in " + - `${CityName.Volhaven} to form a terrorist group called Ultron.\n\n` + - "Intelligence suggests Ultron is heavily armed and that their members are augmented. We believe Ultron is making " + - "moves to take control of and weaponize DeltaOne's Tactical High-Energy Satellite Laser Array (THESLA).\n\n" + - "Your task is to find and destroy Ultron.", - }), - [BladeburnerBlackOpName.OperationCenturion]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationCenturion, - n: 18, - baseDifficulty: 70e3, - reqdRank: 300e3, - rankGain: 15e3, - rankLoss: 5e3, - hpLoss: 10e3, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - desc: - "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)\n\n" + - "Throughout all of humanity's history, we have relied on technology to survive, conquer, and progress. Its " + - "advancement became our primary goal. And at the peak of human civilization, technology turned into power. Global, " + - "absolute power.\n\n" + - "It seems that the universe is not without a sense of irony.\n\n" + - "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)", - }), - [BladeburnerBlackOpName.OperationVindictus]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationVindictus, - n: 19, - baseDifficulty: 75e3, - reqdRank: 350e3, - rankGain: 20e3, - rankLoss: 20e3, - hpLoss: 20e3, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - desc: - "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)\n\n" + - "The bits are all around us. The daemons that hold the Node together can manifest themselves in many different " + - "ways.\n\n" + - "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)", - }), - [BladeburnerBlackOpName.OperationDaedalus]: new BlackOperation({ - name: BladeburnerBlackOpName.OperationDaedalus, - n: 20, - baseDifficulty: 80e3, - reqdRank: 400e3, - rankGain: 40e3, - rankLoss: 10e3, - hpLoss: 100e3, - weights: { - hacking: 0.1, - strength: 0.2, - defense: 0.2, - dexterity: 0.2, - agility: 0.2, - charisma: 0, - intelligence: 0.1, - }, - decays: { - hacking: 0.6, - strength: 0.8, - defense: 0.8, - dexterity: 0.8, - agility: 0.8, - charisma: 0, - intelligence: 0.75, - }, - desc: "Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.", - }), -}; - -/** Array for quick lookup by blackop number */ -export const blackOpsArray = Object.values(BlackOperations).sort((a, b) => (a.n < b.n ? -1 : 1)); -// Verify that all "n" properties match the index in the array -if (!blackOpsArray.every((blackOp, i) => blackOp.n === i)) { - throw new Error("blackOpsArray did not initialize with correct indices"); +export function createBlackOperations(): Record { + return { + [BladeburnerBlackOpName.OperationTyphoon]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationTyphoon, + n: 0, + baseDifficulty: 2000, + reqdRank: 2.5e3, + rankGain: 50, + rankLoss: 10, + hpLoss: 100, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + 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.\n\n" + + `The goal of ${BladeburnerBlackOpName.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.", + }), + [BladeburnerBlackOpName.OperationZero]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationZero, + n: 1, + baseDifficulty: 2500, + reqdRank: 5e3, + rankGain: 60, + rankLoss: 15, + hpLoss: 50, + weights: { + hacking: 0.2, + strength: 0.15, + defense: 0.15, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isStealth: true, + 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.\n\n" + + `The goal of ${BladeburnerBlackOpName.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.", + }), + [BladeburnerBlackOpName.OperationX]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationX, + n: 2, + baseDifficulty: 3000, + reqdRank: 7.5e3, + rankGain: 75, + rankLoss: 15, + hpLoss: 100, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "We have recently discovered an underground publication group called Samizdat. Even though most of their " + + "publications are nonsensical conspiracy theories, the average human is gullible enough to believe them. Many of " + + "their works discuss Synthoids and pose a threat to society. The publications are spreading rapidly in China and " + + "other Eastern countries.\n\n" + + "Samizdat has done a good job of keeping hidden and anonymous. However, we've just received intelligence that " + + `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.", + }), + [BladeburnerBlackOpName.OperationTitan]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationTitan, + n: 3, + baseDifficulty: 4000, + reqdRank: 10e3, + rankGain: 100, + rankLoss: 20, + hpLoss: 100, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "Several months ago, Titan Laboratories' Bioengineering department was infiltrated by Synthoids. As far as we " + + "know, Titan Laboratories' management has no knowledge about this. We don't know what the Synthoids are up to, " + + "but the research that they could be conducting using Titan Laboratories' vast resources is potentially very " + + "dangerous.\n\n" + + `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.", + }), + [BladeburnerBlackOpName.OperationAres]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationAres, + n: 4, + baseDifficulty: 5000, + reqdRank: 12.5e3, + rankGain: 125, + rankLoss: 20, + hpLoss: 200, + weights: { + hacking: 0, + strength: 0.25, + defense: 0.25, + dexterity: 0.25, + agility: 0.25, + charisma: 0, + intelligence: 0, + }, + decays: { + hacking: 0, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "One of our undercover agents, Agent Carter, has informed us of a massive weapons deal going down in Dubai " + + "between rogue Russian militants and a radical Synthoid community. These weapons are next-gen plasma and energy " + + "weapons. It is critical for the safety of humanity that this deal does not happen.\n\n" + + "Your task is to intercept the deal. Leave no survivors.", + }), + [BladeburnerBlackOpName.OperationArchangel]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationArchangel, + n: 5, + baseDifficulty: 7500, + reqdRank: 15e3, + rankGain: 200, + rankLoss: 20, + hpLoss: 25, + weights: { + hacking: 0, + strength: 0.2, + defense: 0.2, + dexterity: 0.3, + agility: 0.3, + charisma: 0, + intelligence: 0, + }, + decays: { + hacking: 0, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "Our analysts have discovered that the popular Red Rabbit brothel in Amsterdam is run and 'staffed' by MK-VI " + + "Synthoids. Intelligence suggests that the profit from this brothel is used to fund a large black market arms " + + "trafficking operation.\n\n" + + "The goal of this operation is to take out the leaders that are running the Red Rabbit brothel. Try to limit the " + + "number of other casualties, but do what you must to complete the mission.", + }), + [BladeburnerBlackOpName.OperationJuggernaut]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationJuggernaut, + n: 6, + baseDifficulty: 10e3, + reqdRank: 20e3, + rankGain: 300, + rankLoss: 40, + hpLoss: 300, + weights: { + hacking: 0, + strength: 0.25, + defense: 0.25, + dexterity: 0.25, + agility: 0.25, + charisma: 0, + intelligence: 0, + }, + decays: { + hacking: 0, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "The CIA has just encountered a new security threat. A new criminal group, led by a shadowy operative who calls " + + "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 has thus enlisted our help.\n\n" + + "Your mission is to eradicate Juggernaut and his followers.", + }), + [BladeburnerBlackOpName.OperationRedDragon]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationRedDragon, + n: 7, + baseDifficulty: 12.5e3, + reqdRank: 25e3, + rankGain: 500, + rankLoss: 50, + hpLoss: 500, + weights: { + hacking: 0.05, + strength: 0.2, + defense: 0.2, + dexterity: 0.25, + agility: 0.25, + charisma: 0, + intelligence: 0.05, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + `The ${FactionName.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.\n\n" + + `Your task is to infiltrate and destroy the ${FactionName.Tetrads}' base of operations in Los Angeles. ` + + "Intelligence tells us that their base houses one of their Synthoid manufacturing units.", + }), + [BladeburnerBlackOpName.OperationK]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationK, + n: 8, + baseDifficulty: 15e3, + reqdRank: 30e3, + rankGain: 750, + rankLoss: 60, + hpLoss: 1000, + weights: { + hacking: 0.05, + strength: 0.2, + defense: 0.2, + dexterity: 0.25, + agility: 0.25, + charisma: 0, + intelligence: 0.05, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "CODE RED SITUATION. Our intelligence tells us that VitaLife has discovered a new android cloning technology. " + + "This technology is supposedly capable of cloning Synthoids, not only physically but also their advanced AI " + + "modules. We do not believe that VitaLife is trying to use this technology illegally or maliciously, but if any " + + "Synthoids were able to infiltrate the corporation and take advantage of this technology, then the results would " + + "be catastrophic.\n\n" + + "We do not have the power or jurisdiction to shut this down through legal or political means, so we must resort " + + "to a covert operation. Your goal is to destroy this technology and eliminate anyone who was involved in its " + + "creation.", + }), + [BladeburnerBlackOpName.OperationDeckard]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationDeckard, + n: 9, + baseDifficulty: 20e3, + reqdRank: 40e3, + rankGain: 1e3, + rankLoss: 75, + hpLoss: 200, + weights: { + hacking: 0, + strength: 0.24, + defense: 0.24, + dexterity: 0.24, + agility: 0.24, + charisma: 0, + intelligence: 0.04, + }, + decays: { + hacking: 0, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "Despite your success in eliminating VitaLife's new android-replicating technology in " + + `${BladeburnerBlackOpName.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.\n\n" + + `The goal of ${BladeburnerBlackOpName.OperationDeckard} is to hunt down these Synthoids and retire them. I don't need to ` + + "tell you how critical this mission is.", + }), + [BladeburnerBlackOpName.OperationTyrell]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationTyrell, + n: 10, + baseDifficulty: 25e3, + reqdRank: 50e3, + rankGain: 1.5e3, + rankLoss: 100, + hpLoss: 500, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + `A week ago, ${FactionName.BladeIndustries} reported a small break-in at one of their ${CityName.Aevum} ` + + `Augmentation storage facilities. We figured out that ${FactionName.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.\n\n" + + "We cannot have Synthoids upgrading their already-enhanced abilities with augmentations. Your task is to hunt " + + `down associated members of ${FactionName.TheDarkArmy} and eliminate them.`, + }), + [BladeburnerBlackOpName.OperationWallace]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationWallace, + n: 11, + baseDifficulty: 30e3, + reqdRank: 75e3, + rankGain: 2e3, + rankLoss: 150, + hpLoss: 1500, + weights: { + hacking: 0, + strength: 0.24, + defense: 0.24, + dexterity: 0.24, + agility: 0.24, + charisma: 0, + intelligence: 0.04, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + `Based on information gathered from ${BladeburnerBlackOpName.OperationTyrell}, we've discovered that ` + + `${FactionName.TheDarkArmy} was well aware that there were Synthoids amongst their ranks. Even worse, we believe ` + + `that ${FactionName.TheDarkArmy} is working together with other criminal organizations such as ` + + `${FactionName.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.\n\n" + + "The best way to deal with this is to prevent it before it even happens. The goal of " + + `${BladeburnerBlackOpName.OperationWallace} is to destroy ${FactionName.TheDarkArmy} and ${FactionName.TheSyndicate} factions in ` + + `${CityName.Aevum} immediately. Leave no survivors.`, + }), + [BladeburnerBlackOpName.OperationShoulderOfOrion]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationShoulderOfOrion, + n: 12, + baseDifficulty: 35e3, + reqdRank: 100e3, + rankGain: 2.5e3, + rankLoss: 500, + hpLoss: 1500, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isStealth: true, + desc: + "China's Solaris Space Systems is secretly launching the first manned spacecraft in over a decade using " + + "Synthoids. We believe China is trying to establish the first off-world colonies.\n\n" + + "The mission is to prevent this launch without instigating an international conflict. When you accept this " + + "mission, you will be officially disavowed by the NSA and the national government until after you successfully " + + "return. In the event of failure, all of the operation's team members must not let themselves be captured alive.", + }), + [BladeburnerBlackOpName.OperationHyron]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationHyron, + n: 13, + baseDifficulty: 40e3, + reqdRank: 125e3, + rankGain: 3e3, + rankLoss: 1e3, + hpLoss: 500, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + `Our intelligence tells us that ${FactionName.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.\n\n" + + "I do not need to remind you why sentient-level AIs pose a serious threat to all of mankind.\n\n" + + `The research for this project is being conducted at one of ${FactionName.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.", + }), + [BladeburnerBlackOpName.OperationMorpheus]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationMorpheus, + n: 14, + baseDifficulty: 45e3, + reqdRank: 150e3, + rankGain: 4e3, + rankLoss: 1e3, + hpLoss: 100, + weights: { + hacking: 0.05, + strength: 0.15, + defense: 0.15, + dexterity: 0.3, + agility: 0.3, + charisma: 0, + intelligence: 0.05, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isStealth: true, + desc: + "DreamSense Technologies is an advertising company that uses special technology to transmit their ads into the " + + "people's dreams and subconscious. They do this using broadcast transmitter towers. Based on information from our " + + `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.\n\n" + + "The mission is to destroy this broadcast tower. Speed and stealth are of the utmost importance for this.", + }), + [BladeburnerBlackOpName.OperationIonStorm]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationIonStorm, + n: 15, + baseDifficulty: 50e3, + reqdRank: 175e3, + rankGain: 5e3, + rankLoss: 1e3, + hpLoss: 5000, + weights: { + hacking: 0, + strength: 0.24, + defense: 0.24, + dexterity: 0.24, + agility: 0.24, + charisma: 0, + intelligence: 0.04, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "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.\n\n" + + `This is a full-scale assault operation to find and retire all of these Synthoids in the ${CityName.Sector12} ` + + "Slums.", + }), + [BladeburnerBlackOpName.OperationAnnihilus]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationAnnihilus, + n: 16, + baseDifficulty: 55e3, + reqdRank: 200e3, + rankGain: 7.5e3, + rankLoss: 1e3, + hpLoss: 10e3, + weights: { + hacking: 0, + strength: 0.24, + defense: 0.24, + dexterity: 0.24, + agility: 0.24, + charisma: 0, + intelligence: 0.04, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + "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 '${FactionName.TheCovenant}'. We have no prior intelligence about this organization, so you ` + + "are going in blind.", + }), + [BladeburnerBlackOpName.OperationUltron]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationUltron, + n: 17, + baseDifficulty: 60e3, + reqdRank: 250e3, + rankGain: 10e3, + rankLoss: 2e3, + hpLoss: 10e3, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + isKill: true, + desc: + `${FactionName.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.\n\n" + + `${FactionName.OmniTekIncorporated} has also told us they believe someone has triggered this malfunction in a ` + + "large group of MK-VI Synthoids, and these newly radicalized Synthoids are now amassing in " + + `${CityName.Volhaven} to form a terrorist group called Ultron.\n\n` + + "Intelligence suggests Ultron is heavily armed and that their members are augmented. We believe Ultron is making " + + "moves to take control of and weaponize DeltaOne's Tactical High-Energy Satellite Laser Array (THESLA).\n\n" + + "Your task is to find and destroy Ultron.", + }), + [BladeburnerBlackOpName.OperationCenturion]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationCenturion, + n: 18, + baseDifficulty: 70e3, + reqdRank: 300e3, + rankGain: 15e3, + rankLoss: 5e3, + hpLoss: 10e3, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + desc: + "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)\n\n" + + "Throughout all of humanity's history, we have relied on technology to survive, conquer, and progress. Its " + + "advancement became our primary goal. And at the peak of human civilization, technology turned into power. Global, " + + "absolute power.\n\n" + + "It seems that the universe is not without a sense of irony.\n\n" + + "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)", + }), + [BladeburnerBlackOpName.OperationVindictus]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationVindictus, + n: 19, + baseDifficulty: 75e3, + reqdRank: 350e3, + rankGain: 20e3, + rankLoss: 20e3, + hpLoss: 20e3, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + desc: + "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)\n\n" + + "The bits are all around us. The daemons that hold the Node together can manifest themselves in many different " + + "ways.\n\n" + + "D)@#)($M)C0293c40($*)@#D0JUMP3Rm0C<*@#)*$)#02c94830c(#$*D)", + }), + [BladeburnerBlackOpName.OperationDaedalus]: new BlackOperation({ + name: BladeburnerBlackOpName.OperationDaedalus, + n: 20, + baseDifficulty: 80e3, + reqdRank: 400e3, + rankGain: 40e3, + rankLoss: 10e3, + hpLoss: 100e3, + weights: { + hacking: 0.1, + strength: 0.2, + defense: 0.2, + dexterity: 0.2, + agility: 0.2, + charisma: 0, + intelligence: 0.1, + }, + decays: { + hacking: 0.6, + strength: 0.8, + defense: 0.8, + dexterity: 0.8, + agility: 0.8, + charisma: 0, + intelligence: 0.75, + }, + desc: "Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.", + }), + }; +} + +export const numberOfBlackOperations = Object.keys(BladeburnerBlackOpName).length; + +export function loadBlackOperationsData( + data: unknown, + blackOperations: Record, +) { + if (data == null || typeof data !== "object" || Array.isArray(data)) { + return; + } + assertLoadingType>(data); + for (const blackOpName of Object.values(BladeburnerBlackOpName)) { + const loadedBlackOp = data[blackOpName]; + if (!(loadedBlackOp instanceof BlackOperation)) { + continue; + } + blackOperations[blackOpName].loadData(loadedBlackOp); + } } diff --git a/src/Bladeburner/data/Contracts.ts b/src/Bladeburner/data/Contracts.ts index dcc1d0520..78643c333 100644 --- a/src/Bladeburner/data/Contracts.ts +++ b/src/Bladeburner/data/Contracts.ts @@ -113,7 +113,9 @@ export function createContracts(): Record { export function loadContractsData(data: unknown, contracts: Record) { // loading data as "unknown" and typechecking it down is probably not necessary // but this will prevent crashes even with malformed savedata - if (!data || typeof data !== "object") return; + if (data == null || typeof data !== "object" || Array.isArray(data)) { + return; + } assertLoadingType>(data); for (const contractName of Object.values(BladeburnerContractName)) { const loadedContract = data[contractName]; diff --git a/src/Bladeburner/data/Operations.ts b/src/Bladeburner/data/Operations.ts index 065a98d00..78f3de20d 100644 --- a/src/Bladeburner/data/Operations.ts +++ b/src/Bladeburner/data/Operations.ts @@ -230,7 +230,9 @@ export function createOperations(): Record export function loadOperationsData(data: unknown, operations: Record) { // loading data as "unknown" and typechecking it down is probably not necessary // but this will prevent crashes even with malformed savedata - if (!data || typeof data !== "object") return; + if (data == null || typeof data !== "object" || Array.isArray(data)) { + return; + } assertLoadingType>(data); for (const operationName of Object.values(BladeburnerOperationName)) { const loadedOperation = data[operationName]; diff --git a/src/Bladeburner/ui/BlackOpPage.tsx b/src/Bladeburner/ui/BlackOpPage.tsx index eb27f0c96..fac912da5 100644 --- a/src/Bladeburner/ui/BlackOpPage.tsx +++ b/src/Bladeburner/ui/BlackOpPage.tsx @@ -7,7 +7,7 @@ import { BlackOpElem } from "./BlackOpElem"; import { Router } from "../../ui/GameRoot"; import { Page } from "../../ui/Router"; import { CorruptibleText } from "../../ui/React/CorruptibleText"; -import { blackOpsArray } from "../data/BlackOperations"; +import { numberOfBlackOperations } from "../data/BlackOperations"; import { finishBitNode } from "../../BitNode/BitNodeUtils"; import { Player } from "@player"; @@ -16,7 +16,7 @@ interface BlackOpPageProps { } export function BlackOpPage({ bladeburner }: BlackOpPageProps): React.ReactElement { - const blackOperations = blackOpsArray.slice(0, bladeburner.numBlackOpsComplete + 1).reverse(); + const blackOperations = bladeburner.blackOperationArray.slice(0, bladeburner.numBlackOpsComplete + 1).reverse(); return ( <> @@ -36,11 +36,11 @@ export function BlackOpPage({ bladeburner }: BlackOpPageProps): React.ReactEleme Unaffected by Charisma. - {bladeburner.numBlackOpsComplete >= blackOpsArray.length && ( + {bladeburner.numBlackOpsComplete >= numberOfBlackOperations && (