diff --git a/src/Constants.ts b/src/Constants.ts
index 0dce70c0e..b02e14809 100644
--- a/src/Constants.ts
+++ b/src/Constants.ts
@@ -47,14 +47,6 @@ export const CONSTANTS: {
IntelligenceTerminalHackBaseExpGain: number;
IntelligenceSingFnBaseExpGain: number;
IntelligenceClassBaseExpGain: number;
- IntelligenceHackingMissionBaseExpGain: number;
- HackingMissionRepToDiffConversion: number;
- HackingMissionRepToRewardConversion: number;
- HackingMissionSpamTimeIncrease: number;
- HackingMissionTransferAttackIncrease: number;
- HackingMissionMiscDefenseIncrease: number;
- HackingMissionDifficultyToHacking: number;
- HackingMissionHowToPlay: string;
MillisecondsPer20Hours: number;
GameCyclesPer20Hours: number;
MillisecondsPer10Hours: number;
@@ -199,63 +191,6 @@ export const CONSTANTS: {
IntelligenceTerminalHackBaseExpGain: 200, // Hacking exp divided by this to determine int exp gain
IntelligenceSingFnBaseExpGain: 1.5,
IntelligenceClassBaseExpGain: 0.01,
- IntelligenceHackingMissionBaseExpGain: 3, // Hacking Mission difficulty multiplied by this to get exp gain
-
- // Hacking Missions
- // TODO Move this into Hacking Mission implementation
- HackingMissionRepToDiffConversion: 10000, // Faction rep is divided by this to get mission difficulty
- HackingMissionRepToRewardConversion: 7, // Faction rep divided byt his to get mission rep reward
- HackingMissionSpamTimeIncrease: 25000, // How much time limit increase is gained when conquering a Spam Node (ms)
- HackingMissionTransferAttackIncrease: 1.05, // Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
- HackingMissionMiscDefenseIncrease: 1.05, // The amount by which every misc node's defense is multiplied when one is conquered
- HackingMissionDifficultyToHacking: 135, // Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc)
- HackingMissionHowToPlay:
- "Hacking missions are a minigame that, if won, will reward you with faction reputation. " +
- "In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " +
- "are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " +
- "that initially belong to neither you nor the enemy. The goal of the game is " +
- "to capture all of the enemy's Database nodes within the time limit. " +
- "If you fail to do this, you will lose. " +
- "Each Node has three stats: Attack, Defense, and HP. There are five different actions that " +
- "a Node can take: " +
- "Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the owner's Attack, the Player's " +
- "hacking level, and the enemy's defense. " +
- "Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the " +
- "enemy's defense. " +
- "Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the enemy's " +
- "defense. " +
- "Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level. " +
- "Overflow - Raises the Node's Attack but lowers its Defense. The effectiveness is determined by your hacking level. " +
- "Note that when determining the effectiveness of the above actions, the TOTAL Attack or Defense of the team is used, not just the " +
- "Attack/Defense of the individual Node that is performing the action. " +
- "To capture a Node, you must lower its HP down to 0. " +
- "There are six different types of Nodes: " +
- "CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action " +
- "Firewall - Nodes with high defense. These Nodes can 'Fortify' " +
- "Database - A special type of Node. The player's objective is to conquer all of the enemy's Database Nodes within " +
- "the time limit. These Nodes cannot perform any actions " +
- "Spam - Conquering one of these Nodes will slow the enemy's trace, giving the player additional time to complete " +
- "the mission. These Nodes cannot perform any actions " +
- "Transfer - Conquering one of these nodes will increase the Attack of all of your CPU Cores by a small fixed percentage. " +
- "These Nodes are capable of performing every action except the 'Attack' action " +
- "Shield - Nodes with high defense. These Nodes can 'Fortify' " +
- "To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Double-clicking " +
- "a node will select all of your Nodes of the same type (e.g. select all CPU Core Nodes or all Transfer Nodes). Note that only Nodes " +
- "that can perform actions (CPU Core, Transfer, Shield, Firewall) can be selected. Selected Nodes will be denoted with a white highlight. After selecting a Node or multiple Nodes, " +
- "select its action using the Action Buttons near the top of the screen. Every action also has a corresponding keyboard " +
- "shortcut. " +
- "For certain actions such as attacking, scanning, and weakening, the Node performing the action must have a target. To target " +
- "another node, simply click-and-drag from the 'source' Node to a target. A Node can only have one target, and you can target " +
- "any Node that is adjacent to one of your Nodes (immediately above, below, or to the side. NOT diagonal). Furthermore, only CPU Cores and Transfer Nodes " +
- "can target, since they are the only ones that can perform the related actions. To remove a target, you can simply click on the line that represents " +
- "the connection between one of your Nodes and its target. Alternatively, you can select the 'source' Node and click the 'Drop Connection' button, " +
- "or press 'd'. " +
- "Other Notes: " +
- "-Whenever a miscellenaous Node (not owned by the player or enemy) is conquered, the defense of all remaining miscellaneous Nodes that " +
- "are not actively being targeted will increase by a fixed percentage. " +
- "-Whenever a Node is conquered, its stats are significantly reduced " +
- "-Miscellaneous Nodes slowly raise their defense over time " +
- "-Nodes slowly regenerate health over time.",
// Time-related constants
MillisecondsPer20Hours: 72000000,
diff --git a/src/Faction/FactionHelpers.tsx b/src/Faction/FactionHelpers.tsx
index 7d4440a7a..876d81e9d 100644
--- a/src/Faction/FactionHelpers.tsx
+++ b/src/Faction/FactionHelpers.tsx
@@ -7,7 +7,6 @@ import { CONSTANTS } from "../Constants";
import { Faction } from "./Faction";
import { Factions } from "./Factions";
-import { HackingMission, setInMission } from "../Missions";
import { Player } from "../Player";
import { Settings } from "../Settings/Settings";
import {
@@ -49,12 +48,6 @@ export function joinFaction(faction: Faction): void {
}
}
-export function startHackingMission(faction: Faction): void {
- const mission = new HackingMission(faction.playerReputation, faction);
- setInMission(true, mission); //Sets inMission flag to true
- mission.init();
-}
-
//Returns a boolean indicating whether the player has the prerequisites for the
//specified Augmentation
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
diff --git a/src/Faction/ui/FactionRoot.tsx b/src/Faction/ui/FactionRoot.tsx
index cc6d656f2..1fb5d7287 100644
--- a/src/Faction/ui/FactionRoot.tsx
+++ b/src/Faction/ui/FactionRoot.tsx
@@ -30,10 +30,6 @@ type IProps = {
// Info text for all options on the UI
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " + "faction reputation";
-const hackingMissionInfo =
- "Attempt a hacking mission for your faction. " +
- "A mission is a mini game that, if won, earns you " +
- "significant reputation with this faction. (Recommended hacking level: 200+)";
const hackingContractsInfo =
"Complete hacking contracts for your faction. " +
"Your effectiveness, which determines how much " +
@@ -96,11 +92,6 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
player.startFactionHackWork(router, faction);
}
- function startHackingMission(faction: Faction): void {
- player.singularityStopWork();
- router.toHackingMission(faction);
- }
-
function startSecurityWork(faction: Faction): void {
player.startFactionSecurityWork(router, faction);
}
@@ -138,13 +129,6 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
setGangOpen(false)} />
>
)}
- {!isPlayersGang && factionInfo.offerHackingMission && (
- startHackingMission(faction)}
- />
- )}
{!isPlayersGang && factionInfo.offerHackingWork && (
startHackingMission(props.faction));
- return
;
-}
diff --git a/src/Message/MessageHelpers.ts b/src/Message/MessageHelpers.ts
index 32da4fb94..6b6fbaf0a 100644
--- a/src/Message/MessageHelpers.ts
+++ b/src/Message/MessageHelpers.ts
@@ -2,7 +2,6 @@ import { Message } from "./Message";
import { Augmentations } from "../Augmentation/Augmentations";
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
import { Programs } from "../Programs/Programs";
-import { inMission } from "../Missions";
import { Player } from "../Player";
import { redPillFlag } from "../RedPill";
import { GetServerByHostname } from "../Server/ServerHelpers";
@@ -66,11 +65,11 @@ function checkForMessagesToSend(): void {
redpillOwned = true;
}
- if (redpill && redpillOwned && Player.sourceFiles.length === 0 && !redPillFlag && !inMission) {
+ if (redpill && redpillOwned && Player.sourceFiles.length === 0 && !redPillFlag) {
sendMessage(redpill, true);
} else if (redpill && redpillOwned) {
//If player has already destroyed a BitNode, message is not forced
- if (!redPillFlag && !inMission) {
+ if (!redPillFlag) {
sendMessage(redpill);
}
} else if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) {
diff --git a/src/Missions.d.ts b/src/Missions.d.ts
deleted file mode 100644
index 8a1e7d522..000000000
--- a/src/Missions.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export declare let inMission: boolean;
-export declare class HackingMission {
- constructor(reputation: number, faction: Faction);
- init(): void;
- process(numCycles: number): void;
-}
-export declare function setInMission(inMission: boolean, mission: HackingMission): void;
-export declare let currMission: HackingMission;
diff --git a/src/Missions.jsx b/src/Missions.jsx
deleted file mode 100644
index 73dac72c1..000000000
--- a/src/Missions.jsx
+++ /dev/null
@@ -1,1600 +0,0 @@
-import { CONSTANTS } from "./Constants";
-import { Player } from "./Player";
-
-import { dialogBoxCreate } from "./ui/React/DialogBox";
-import { formatNumber } from "./utils/StringHelperFunctions";
-import { Reputation } from "./ui/React/Reputation";
-
-import { addOffset } from "./utils/helpers/addOffset";
-import { getRandomInt } from "./utils/helpers/getRandomInt";
-import { isString } from "./utils/helpers/isString";
-
-import { clearEventListeners } from "./ui/uiHelpers/clearEventListeners";
-import { Router } from "./ui/GameRoot";
-
-// For some reason `jsplumb` needs to be imported exactly like this,
-// lowercase p, and later in the code used as `jsPlumb` uppercase P. wtf.
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import jsplumb from "jsplumb";
-
-import React from "react";
-import ReactDOM from "react-dom";
-
-let inMission = false; // Flag to denote whether a mission is running
-let currMission = null;
-function setInMission(bool, mission) {
- inMission = bool;
- if (bool) {
- currMission = mission;
- } else {
- currMission = null;
- }
-}
-
-// Keyboard shortcuts
-$(document).keydown(function (e) {
- if (inMission && currMission && currMission.selectedNode.length != 0) {
- switch (e.keyCode) {
- case 65: // a for Attack
- currMission.actionButtons[0].click();
- break;
- case 83: // s for Scan
- currMission.actionButtons[1].click();
- break;
- case 87: // w for Weaken
- currMission.actionButtons[2].click();
- break;
- case 70: // f for Fortify
- currMission.actionButtons[3].click();
- break;
- case 82: // r for Overflow
- currMission.actionButtons[4].click();
- break;
- case 68: // d for Detach connection
- currMission.actionButtons[5].click();
- break;
- default:
- break;
- }
- }
-});
-
-let NodeTypes = {
- Core: "CPU Core Node", // All actions available
- Firewall: "Firewall Node", // No actions available
- Database: "Database Node", // No actions available
- Spam: "Spam Node", // No actions Available
- Transfer: "Transfer Node", // Can Weaken, Scan, Fortify and Overflow
- Shield: "Shield Node", // Can Fortify
-};
-
-let NodeActions = {
- Attack: "Attacking", // Damaged based on attack stat + hacking level + opp def
- Scan: "Scanning", // -Def for target, affected by attack and hacking level
- Weaken: "Weakening", // -Attack for target, affected by attack and hacking level
- Fortify: "Fortifying", // +Defense for Node, affected by hacking level
- Overflow: "Overflowing", // +Attack but -Defense for Node, affected by hacking level
-};
-
-function Node(type, stats) {
- this.type = type;
- this.atk = stats.atk ? stats.atk : 0;
- this.def = stats.def ? stats.def : 0;
- this.hp = stats.hp ? stats.hp : 0;
- this.maxhp = this.hp;
- this.plyrCtrl = false;
- this.enmyCtrl = false;
- this.pos = [0, 0]; // x, y
- this.el = null; // Holds the Node's DOM element
- this.action = null;
- this.targetedCount = 0; // Count of how many connections this node is the target of
-
- /**
- * Holds the JsPlumb Connection object for this Node, where this Node is the Source (since each Node
- * can only have 1 outgoing Connection)
- */
- this.conn = null;
-}
-
-Node.prototype.setPosition = function (x, y) {
- this.pos = [x, y];
-};
-
-Node.prototype.setControlledByPlayer = function () {
- this.plyrCtrl = true;
- this.enmyCtrl = false;
- if (this.el) {
- this.el.classList.remove("hack-mission-enemy-node");
- this.el.classList.add("hack-mission-player-node");
- }
-};
-
-Node.prototype.setControlledByEnemy = function () {
- this.plyrCtrl = false;
- this.enmyCtrl = true;
- if (this.el) {
- this.el.classList.remove("hack-mission-player-node");
- this.el.classList.add("hack-mission-enemy-node");
- }
-};
-
-// Sets this node to be the active node
-Node.prototype.select = function (actionButtons) {
- if (this.enmyCtrl) {
- return;
- }
- this.el.classList.add("hack-mission-player-node-active");
-
- // Make all buttons inactive
- for (var i = 0; i < actionButtons.length; ++i) {
- actionButtons[i].classList.remove("a-link-button");
- actionButtons[i].classList.add("a-link-button-inactive");
- }
-
- switch (this.type) {
- case NodeTypes.Core:
- // All buttons active
- for (var i = 0; i < actionButtons.length; ++i) {
- actionButtons[i].classList.remove("a-link-button-inactive");
- actionButtons[i].classList.add("a-link-button");
- }
- break;
- case NodeTypes.Transfer:
- actionButtons[1].classList.remove("a-link-button-inactive");
- actionButtons[1].classList.add("a-link-button");
- actionButtons[2].classList.remove("a-link-button-inactive");
- actionButtons[2].classList.add("a-link-button");
- actionButtons[3].classList.remove("a-link-button-inactive");
- actionButtons[3].classList.add("a-link-button");
- actionButtons[4].classList.remove("a-link-button-inactive");
- actionButtons[4].classList.add("a-link-button");
- actionButtons[5].classList.remove("a-link-button-inactive");
- actionButtons[5].classList.add("a-link-button");
- break;
- case NodeTypes.Shield:
- case NodeTypes.Firewall:
- actionButtons[3].classList.remove("a-link-button-inactive");
- actionButtons[3].classList.add("a-link-button");
- break;
- default:
- break;
- }
-};
-
-Node.prototype.deselect = function (actionButtons) {
- this.el.classList.remove("hack-mission-player-node-active");
- for (var i = 0; i < actionButtons.length; ++i) {
- actionButtons[i].classList.remove("a-link-button");
- actionButtons[i].classList.add("a-link-button-inactive");
- }
-};
-
-Node.prototype.untarget = function () {
- if (this.targetedCount === 0) {
- console.warn(`Node ${this.el.id} is being 'untargeted' when it has no target count`);
- return;
- }
- --this.targetedCount;
-};
-
-/**
- * Hacking mission instance
- * @param rep {number} How much reputation the player has for the faction
- * @param fac {Faction} Faction for which this mission is being conducted
- */
-function HackingMission(rep, fac) {
- this.faction = fac;
-
- this.started = false;
- this.time = 180000; // 5 minutes to start, milliseconds
-
- this.playerCores = [];
- this.playerNodes = []; // Non-core nodes
- this.playerAtk = 0;
- this.playerDef = 0;
-
- this.enemyCores = [];
- this.enemyDatabases = [];
- this.enemyNodes = []; // Non-core nodes
- this.enemyAtk = 0;
- this.enemyDef = 0;
-
- this.miscNodes = [];
-
- this.selectedNode = []; // Which of the player's nodes are currently selected
-
- this.actionButtons = []; // DOM buttons for actions
-
- this.availablePositions = [];
- for (var r = 0; r < 8; ++r) {
- for (var c = 0; c < 8; ++c) {
- this.availablePositions.push([r, c]);
- }
- }
-
- this.map = [];
- for (var i = 0; i < 8; ++i) {
- this.map.push([null, null, null, null, null, null, null, null]);
- }
-
- this.jsplumbinstance = null;
-
- this.difficulty = rep / CONSTANTS.HackingMissionRepToDiffConversion + 1;
- this.reward = 250 + rep / CONSTANTS.HackingMissionRepToRewardConversion;
-}
-
-HackingMission.prototype.init = function () {
- // Create Header DOM
- this.createPageDom();
-
- // Create player starting nodes
- var home = Player.getHomeComputer();
- for (var i = 0; i < home.cpuCores; ++i) {
- var stats = {
- atk: Player.hacking_skill / 7.5 + 30,
- def: Player.hacking_skill / 20,
- hp: Player.hacking_skill / 4,
- };
- this.playerCores.push(new Node(NodeTypes.Core, stats));
- this.playerCores[i].setControlledByPlayer();
- this.setNodePosition(this.playerCores[i], i, 0);
- this.removeAvailablePosition(i, 0);
- }
-
- // Randomly generate enemy nodes (CPU and Firewall) based on difficulty
- var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4)));
- var numFirewalls = Math.min(20, getRandomInt(Math.round(this.difficulty / 3), Math.round(this.difficulty / 3) + 1));
- var numDatabases = Math.min(10, getRandomInt(1, Math.round(this.difficulty / 3) + 1));
- var totalNodes = numNodes + numFirewalls + numDatabases;
- var xlimit = 7 - Math.floor(totalNodes / 8);
- var randMult = addOffset(0.8 + this.difficulty / 5, 10);
- for (var i = 0; i < numNodes; ++i) {
- var stats = {
- atk: randMult * getRandomInt(80, 86),
- def: randMult * getRandomInt(5, 10),
- hp: randMult * getRandomInt(210, 230),
- };
- this.enemyCores.push(new Node(NodeTypes.Core, stats));
- this.enemyCores[i].setControlledByEnemy();
- this.setNodeRandomPosition(this.enemyCores[i], xlimit);
- }
- for (var i = 0; i < numFirewalls; ++i) {
- var stats = {
- atk: 0,
- def: randMult * getRandomInt(10, 20),
- hp: randMult * getRandomInt(275, 300),
- };
- this.enemyNodes.push(new Node(NodeTypes.Firewall, stats));
- this.enemyNodes[i].setControlledByEnemy();
- this.setNodeRandomPosition(this.enemyNodes[i], xlimit);
- }
- for (var i = 0; i < numDatabases; ++i) {
- var stats = {
- atk: 0,
- def: randMult * getRandomInt(30, 55),
- hp: randMult * getRandomInt(210, 275),
- };
- var node = new Node(NodeTypes.Database, stats);
- node.setControlledByEnemy();
- this.setNodeRandomPosition(node, xlimit);
- this.enemyDatabases.push(node);
- }
- this.calculateDefenses();
- this.calculateAttacks();
- this.createMap();
-};
-
-HackingMission.prototype.createPageDom = function () {
- var container = document.getElementById("mission-container");
-
- var favorMult = 1 + this.faction.favor / 100;
- var gain = this.reward * Player.faction_rep_mult * favorMult;
- var headerText = document.createElement("p");
- ReactDOM.render(
- <>
- You are about to start a hacking mission! You will gain {Reputation(gain)} faction reputation with{" "}
- {this.faction.name} if you win. Click the 'Start' button to begin.
- >,
- headerText,
- );
- headerText.style.display = "block";
- headerText.classList.add("hack-mission-header-element");
- headerText.style.width = "80%";
-
- var inGameGuideBtn = document.createElement("a");
- inGameGuideBtn.innerText = "How to Play";
- inGameGuideBtn.classList.add("a-link-button");
- inGameGuideBtn.style.display = "inline-block";
- inGameGuideBtn.classList.add("hack-mission-header-element");
- inGameGuideBtn.addEventListener("click", function () {
- dialogBoxCreate(CONSTANTS.HackingMissionHowToPlay);
- return false;
- });
-
- // Start button will get replaced with forfeit when game is started
- var startBtn = document.createElement("a");
- startBtn.innerHTML = "Start";
- startBtn.setAttribute("id", "hack-mission-start-btn");
- startBtn.classList.add("a-link-button");
- startBtn.classList.add("hack-mission-header-element");
- startBtn.style.display = "inline-block";
- startBtn.addEventListener("click", () => {
- this.start();
- return false;
- });
-
- var forfeitMission = document.createElement("a");
- forfeitMission.innerHTML = "Forfeit Mission (Exit)";
- forfeitMission.classList.add("a-link-button");
- forfeitMission.classList.add("hack-mission-header-element");
- forfeitMission.style.display = "inline-block";
- forfeitMission.addEventListener("click", () => {
- this.finishMission(false);
- return false;
- });
-
- var timer = document.createElement("p");
- timer.setAttribute("id", "hacking-mission-timer");
- timer.style.display = "inline-block";
- timer.style.margin = "6px";
-
- // Create Action Buttons (Attack/Scan/Weaken/ etc...)
- var actionsContainer = document.createElement("span");
- actionsContainer.style.display = "block";
- actionsContainer.classList.add("hack-mission-action-buttons-container");
- for (var i = 0; i < 6; ++i) {
- this.actionButtons.push(document.createElement("a"));
- this.actionButtons[i].style.display = "inline-block";
- this.actionButtons[i].classList.add("a-link-button-inactive"); // Disabled at start
- this.actionButtons[i].classList.add("tooltip"); // Disabled at start
- this.actionButtons[i].classList.add("hack-mission-header-element");
- actionsContainer.appendChild(this.actionButtons[i]);
- }
- this.actionButtons[0].innerText = "Attack(a)";
- var atkTooltip = document.createElement("span");
- atkTooltip.classList.add("tooltiptexthigh");
- atkTooltip.innerText =
- "Lowers the targeted node's HP. The effectiveness of this depends on " +
- "this node's Attack level, your hacking level, and the opponent's defense level.";
- this.actionButtons[0].appendChild(atkTooltip);
- this.actionButtons[1].innerText = "Scan(s)";
- var scanTooltip = document.createElement("span");
- scanTooltip.classList.add("tooltiptexthigh");
- scanTooltip.innerText =
- "Lowers the targeted node's defense. The effectiveness of this depends on " +
- "this node's Attack level, your hacking level, and the opponent's defense level.";
- this.actionButtons[1].appendChild(scanTooltip);
- this.actionButtons[2].innerText = "Weaken(w)";
- var WeakenTooltip = document.createElement("span");
- WeakenTooltip.classList.add("tooltiptexthigh");
- WeakenTooltip.innerText =
- "Lowers the targeted node's attack. The effectiveness of this depends on " +
- "this node's Attack level, your hacking level, and the opponent's defense level.";
- this.actionButtons[2].appendChild(WeakenTooltip);
- this.actionButtons[3].innerText = "Fortify(f)";
- var fortifyTooltip = document.createElement("span");
- fortifyTooltip.classList.add("tooltiptexthigh");
- fortifyTooltip.innerText =
- "Raises this node's Defense level. The effectiveness of this depends on " + "your hacking level";
- this.actionButtons[3].appendChild(fortifyTooltip);
- this.actionButtons[4].innerText = "Overflow(r)";
- var overflowTooltip = document.createElement("span");
- overflowTooltip.classList.add("tooltiptexthigh");
- overflowTooltip.innerText =
- "Raises this node's Attack level but lowers its Defense level. The effectiveness " +
- "of this depends on your hacking level.";
- this.actionButtons[4].appendChild(overflowTooltip);
- this.actionButtons[5].innerText = "Drop Connection(d)";
- var dropconnTooltip = document.createElement("span");
- dropconnTooltip.classList.add("tooltiptexthigh");
- dropconnTooltip.innerText =
- "Removes this Node's current connection to some target Node, if it has one. This can " +
- "also be done by simply clicking the white connection line.";
- this.actionButtons[5].appendChild(dropconnTooltip);
-
- // Player/enemy defense displays will be in action container
- var playerStats = document.createElement("p");
- var enemyStats = document.createElement("p");
- playerStats.style.display = "inline-block";
- enemyStats.style.display = "inline-block";
- playerStats.style.color = "#00ccff";
- enemyStats.style.color = "red";
- playerStats.style.margin = "4px";
- enemyStats.style.margin = "4px";
- playerStats.setAttribute("id", "hacking-mission-player-stats");
- enemyStats.setAttribute("id", "hacking-mission-enemy-stats");
- actionsContainer.appendChild(playerStats);
- actionsContainer.appendChild(enemyStats);
-
- // Set Action Button event listeners
- this.actionButtons[0].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- if (this.selectedNode[0].type !== NodeTypes.Core) {
- return;
- }
- this.setActionButtonsActive(this.selectedNode[0].type);
- this.setActionButton(NodeActions.Attack, false); // Set attack button inactive
- this.selectedNode.forEach(function (node) {
- node.action = NodeActions.Attack;
- });
- });
-
- this.actionButtons[1].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
- if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {
- return;
- }
- this.setActionButtonsActive(nodeType);
- this.setActionButton(NodeActions.Scan, false); // Set scan button inactive
- this.selectedNode.forEach(function (node) {
- node.action = NodeActions.Scan;
- });
- });
-
- this.actionButtons[2].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- var nodeType = this.selectedNode[0].type; // In a multiselect, every Node will have the same type
- if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {
- return;
- }
- this.setActionButtonsActive(nodeType);
- this.setActionButton(NodeActions.Weaken, false); // Set Weaken button inactive
- this.selectedNode.forEach(function (node) {
- node.action = NodeActions.Weaken;
- });
- });
-
- this.actionButtons[3].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- this.setActionButtonsActive(this.selectedNode[0].type);
- this.setActionButton(NodeActions.Fortify, false); // Set Fortify button inactive
- this.selectedNode.forEach(function (node) {
- node.action = NodeActions.Fortify;
- });
- });
-
- this.actionButtons[4].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- var nodeType = this.selectedNode[0].type;
- if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {
- return;
- }
- this.setActionButtonsActive(nodeType);
- this.setActionButton(NodeActions.Overflow, false); // Set Overflow button inactive
- this.selectedNode.forEach(function (node) {
- node.action = NodeActions.Overflow;
- });
- });
-
- this.actionButtons[5].addEventListener("click", () => {
- if (!(this.selectedNode.length > 0)) {
- console.error("Pressing Action button without selected node");
- return;
- }
- this.selectedNode.forEach(function (node) {
- if (node.conn) {
- var endpoints = node.conn.endpoints;
- endpoints[0].detachFrom(endpoints[1]);
- }
- node.action = NodeActions.Fortify;
- });
- });
-
- var timeDisplay = document.createElement("p");
-
- container.appendChild(headerText);
- container.appendChild(inGameGuideBtn);
- container.appendChild(startBtn);
- container.appendChild(forfeitMission);
- container.appendChild(timer);
- container.appendChild(actionsContainer);
- container.appendChild(timeDisplay);
-};
-
-HackingMission.prototype.setActionButtonsInactive = function () {
- for (var i = 0; i < this.actionButtons.length; ++i) {
- this.actionButtons[i].classList.remove("a-link-button");
- this.actionButtons[i].classList.add("a-link-button-inactive");
- }
-};
-
-HackingMission.prototype.setActionButtonsActive = function (nodeType = null) {
- for (var i = 0; i < this.actionButtons.length; ++i) {
- this.actionButtons[i].classList.add("a-link-button");
- this.actionButtons[i].classList.remove("a-link-button-inactive");
- }
-
- /**
- * For Transfer, FireWall and Shield Nodes, certain buttons should always be disabled
- * 0 = Attack, 1 = Scan, 2 = Weaken, 3 = Fortify, 4 = overflow, 5 = Drop conn
- */
- if (nodeType) {
- switch (nodeType) {
- case NodeTypes.Firewall:
- case NodeTypes.Shield:
- this.actionButtons[0].classList.remove("a-link-button");
- this.actionButtons[0].classList.add("a-link-button-inactive");
- this.actionButtons[1].classList.remove("a-link-button");
- this.actionButtons[1].classList.add("a-link-button-inactive");
- this.actionButtons[2].classList.remove("a-link-button");
- this.actionButtons[2].classList.add("a-link-button-inactive");
- this.actionButtons[4].classList.remove("a-link-button");
- this.actionButtons[4].classList.add("a-link-button-inactive");
- this.actionButtons[5].classList.remove("a-link-button");
- this.actionButtons[5].classList.add("a-link-button-inactive");
- break;
- case NodeTypes.Transfer:
- this.actionButtons[0].classList.remove("a-link-button");
- this.actionButtons[0].classList.add("a-link-button-inactive");
- break;
- default:
- break;
- }
- }
-};
-
-// True for active, false for inactive
-HackingMission.prototype.setActionButton = function (i, active = true) {
- if (isString(i)) {
- switch (i) {
- case NodeActions.Attack:
- i = 0;
- break;
- case NodeActions.Scan:
- i = 1;
- break;
- case NodeActions.Weaken:
- i = 2;
- break;
- case NodeActions.Fortify:
- i = 3;
- break;
- case NodeActions.Overflow:
- default:
- i = 4;
- break;
- }
- }
- if (active) {
- this.actionButtons[i].classList.remove("a-link-button-inactive");
- this.actionButtons[i].classList.add("a-link-button");
- } else {
- this.actionButtons[i].classList.remove("a-link-button");
- this.actionButtons[i].classList.add("a-link-button-inactive");
- }
-};
-
-HackingMission.prototype.calculateAttacks = function () {
- var total = 0;
- for (var i = 0; i < this.playerCores.length; ++i) {
- total += this.playerCores[i].atk;
- }
- for (var i = 0; i < this.playerNodes.length; ++i) {
- total += this.playerNodes[i].atk;
- }
- this.playerAtk = total;
- document.getElementById("hacking-mission-player-stats").innerHTML =
- "Player Attack: " + formatNumber(this.playerAtk, 1) + " " + "Player Defense: " + formatNumber(this.playerDef, 1);
- total = 0;
- for (var i = 0; i < this.enemyCores.length; ++i) {
- total += this.enemyCores[i].atk;
- }
- for (var i = 0; i < this.enemyDatabases.length; ++i) {
- total += this.enemyDatabases[i].atk;
- }
- for (var i = 0; i < this.enemyNodes.length; ++i) {
- total += this.enemyNodes[i].atk;
- }
- this.enemyAtk = total;
- document.getElementById("hacking-mission-enemy-stats").innerHTML =
- "Enemy Attack: " + formatNumber(this.enemyAtk, 1) + " " + "Enemy Defense: " + formatNumber(this.enemyDef, 1);
-};
-
-HackingMission.prototype.calculateDefenses = function () {
- var total = 0;
- for (var i = 0; i < this.playerCores.length; ++i) {
- total += this.playerCores[i].def;
- }
- for (var i = 0; i < this.playerNodes.length; ++i) {
- total += this.playerNodes[i].def;
- }
- this.playerDef = total;
- document.getElementById("hacking-mission-player-stats").innerHTML =
- "Player Attack: " + formatNumber(this.playerAtk, 1) + " " + "Player Defense: " + formatNumber(this.playerDef, 1);
- total = 0;
- for (var i = 0; i < this.enemyCores.length; ++i) {
- total += this.enemyCores[i].def;
- }
- for (var i = 0; i < this.enemyDatabases.length; ++i) {
- total += this.enemyDatabases[i].def;
- }
- for (var i = 0; i < this.enemyNodes.length; ++i) {
- total += this.enemyNodes[i].def;
- }
- this.enemyDef = total;
- document.getElementById("hacking-mission-enemy-stats").innerHTML =
- "Enemy Attack: " + formatNumber(this.enemyAtk, 1) + " " + "Enemy Defense: " + formatNumber(this.enemyDef, 1);
-};
-
-HackingMission.prototype.removeAvailablePosition = function (x, y) {
- for (var i = 0; i < this.availablePositions.length; ++i) {
- if (this.availablePositions[i][0] === x && this.availablePositions[i][1] === y) {
- this.availablePositions.splice(i, 1);
- return;
- }
- }
- console.warn(`removeAvailablePosition() did not remove ${x}, ${y}`);
-};
-
-HackingMission.prototype.setNodePosition = function (nodeObj, x, y) {
- if (!(nodeObj instanceof Node)) {
- console.warn("Non-Node object passed into setNodePOsition");
- return;
- }
- if (isNaN(x) || isNaN(y)) {
- console.error(`Invalid values (${x}, ${y}) passed as (x, y) for setNodePosition`);
- return;
- }
- nodeObj.pos = [x, y];
- this.map[x][y] = nodeObj;
-};
-
-HackingMission.prototype.setNodeRandomPosition = function (nodeObj, xlimit = 0) {
- var i = getRandomInt(0, this.availablePositions.length - 1);
- if (this.availablePositions[i][1] < xlimit) {
- // Recurse if not within limit
- return this.setNodeRandomPosition(nodeObj, xlimit);
- }
- var pos = this.availablePositions.splice(i, 1);
- pos = pos[0];
- this.setNodePosition(nodeObj, pos[0], pos[1]);
-};
-
-HackingMission.prototype.createMap = function () {
- // Use a grid
- var map = document.createElement("div");
- map.classList.add("hack-mission-grid");
- map.setAttribute("id", "hacking-mission-map");
- document.getElementById("mission-container").appendChild(map);
-
- // Create random Nodes for every space in the map that
- // hasn't been filled yet. The stats of each Node will be based on
- // the player/enemy attack
- var averageAttack = (this.playerAtk + this.enemyAtk) / 2;
- for (var x = 0; x < 8; ++x) {
- for (var y = 0; y < 8; ++y) {
- if (!(this.map[x][y] instanceof Node)) {
- var node,
- type = getRandomInt(0, 2);
- var randMult = addOffset(0.85 + this.difficulty / 2, 15);
- switch (type) {
- case 0: // Spam
- var stats = {
- atk: 0,
- def: averageAttack * 1.1 + getRandomInt(15, 45),
- hp: randMult * getRandomInt(200, 225),
- };
- node = new Node(NodeTypes.Spam, stats);
- break;
- case 1: // Transfer
- var stats = {
- atk: 0,
- def: averageAttack * 1.1 + getRandomInt(15, 45),
- hp: randMult * getRandomInt(250, 275),
- };
- node = new Node(NodeTypes.Transfer, stats);
- break;
- case 2: // Shield
- default:
- var stats = {
- atk: 0,
- def: averageAttack * 1.1 + getRandomInt(30, 70),
- hp: randMult * getRandomInt(300, 320),
- };
- node = new Node(NodeTypes.Shield, stats);
- break;
- }
- this.setNodePosition(node, x, y);
- this.removeAvailablePosition(x, y);
- this.miscNodes.push(node);
- }
- }
- }
-
- // Create DOM elements in order
- for (var r = 0; r < 8; ++r) {
- for (var c = 0; c < 8; ++c) {
- this.createNodeDomElement(this.map[r][c]);
- }
- }
-
- // Configure all Player CPUS
- for (var i = 0; i < this.playerCores.length; ++i) {
- this.configurePlayerNodeElement(this.playerCores[i].el);
- }
-};
-
-HackingMission.prototype.createNodeDomElement = function (nodeObj) {
- var nodeDiv = document.createElement("a"),
- txtEl = document.createElement("p");
- nodeObj.el = nodeDiv;
-
- // Set the node element's id based on its coordinates
- var id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1];
- nodeDiv.setAttribute("id", id);
- txtEl.setAttribute("id", id + "-txt");
-
- // Set node classes for owner
- nodeDiv.classList.add("hack-mission-node");
- if (nodeObj.plyrCtrl) {
- nodeDiv.classList.add("hack-mission-player-node");
- } else if (nodeObj.enmyCtrl) {
- nodeDiv.classList.add("hack-mission-enemy-node");
- }
-
- // Set node classes based on type
- var txt;
- switch (nodeObj.type) {
- case NodeTypes.Core:
- txt = "CPU Core " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-cpu-node");
- break;
- case NodeTypes.Firewall:
- txt = "Firewall " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-firewall-node");
- break;
- case NodeTypes.Database:
- txt = "Database " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-database-node");
- break;
- case NodeTypes.Spam:
- txt = "Spam " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-spam-node");
- break;
- case NodeTypes.Transfer:
- txt = "Transfer " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-transfer-node");
- break;
- case NodeTypes.Shield:
- default:
- txt = "Shield " + "HP: " + formatNumber(nodeObj.hp, 1);
- nodeDiv.classList.add("hack-mission-shield-node");
- break;
- }
-
- txt += " Atk: " + formatNumber(nodeObj.atk, 1) + " Def: " + formatNumber(nodeObj.def, 1);
- txtEl.innerHTML = txt;
-
- nodeDiv.appendChild(txtEl);
- document.getElementById("hacking-mission-map").appendChild(nodeDiv);
-};
-
-HackingMission.prototype.updateNodeDomElement = function (nodeObj) {
- if (nodeObj.el == null) {
- console.error("Calling updateNodeDomElement on a Node without an element");
- return;
- }
-
- let id = "hacking-mission-node-" + nodeObj.pos[0] + "-" + nodeObj.pos[1];
- let txtEl = document.getElementById(id + "-txt");
-
- // Set node classes based on type
- let txt;
- switch (nodeObj.type) {
- case NodeTypes.Core:
- txt = "CPU Core " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- case NodeTypes.Firewall:
- txt = "Firewall " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- case NodeTypes.Database:
- txt = "Database " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- case NodeTypes.Spam:
- txt = "Spam " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- case NodeTypes.Transfer:
- txt = "Transfer " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- case NodeTypes.Shield:
- default:
- txt = "Shield " + "HP: " + formatNumber(nodeObj.hp, 1);
- break;
- }
-
- txt += " Atk: " + formatNumber(nodeObj.atk, 1) + " Def: " + formatNumber(nodeObj.def, 1);
- if (nodeObj.action) {
- txt += " " + nodeObj.action;
- }
- txtEl.innerHTML = txt;
-};
-
-/**
- * Gets a Node DOM elements corresponding Node object using its
- * element id. Function accepts either the DOM element object or the ID as
- * an argument
- */
-HackingMission.prototype.getNodeFromElement = function (el) {
- var id;
- if (isString(el)) {
- id = el;
- } else {
- id = el.id;
- }
- id = id.replace("hacking-mission-node-", "");
- var res = id.split("-");
- if (res.length != 2) {
- console.error("Parsing hacking mission node id. could not find coordinates");
- return null;
- }
- var x = res[0],
- y = res[1];
- if (isNaN(x) || isNaN(y) || x >= 8 || y >= 8 || x < 0 || y < 0) {
- console.error(`Unexpected values (${x}, ${y}) for (x, y)`);
- return null;
- }
- return this.map[x][y];
-};
-
-function selectNode(hackMissionInst, el) {
- var nodeObj = hackMissionInst.getNodeFromElement(el);
- if (nodeObj == null) {
- console.error("Failed getting Node object");
- }
- if (!nodeObj.plyrCtrl) {
- return;
- }
-
- clearAllSelectedNodes(hackMissionInst);
- nodeObj.select(hackMissionInst.actionButtons);
- hackMissionInst.selectedNode.push(nodeObj);
-}
-
-function multiselectNode(hackMissionInst, el) {
- var nodeObj = hackMissionInst.getNodeFromElement(el);
- if (nodeObj == null) {
- console.error("Failed getting Node Object in multiselectNode()");
- }
- if (!nodeObj.plyrCtrl) {
- return;
- }
-
- clearAllSelectedNodes(hackMissionInst);
- var type = nodeObj.type;
- if (type === NodeTypes.Core) {
- hackMissionInst.playerCores.forEach(function (node) {
- node.select(hackMissionInst.actionButtons);
- hackMissionInst.selectedNode.push(node);
- });
- } else {
- hackMissionInst.playerNodes.forEach(function (node) {
- if (node.type === type) {
- node.select(hackMissionInst.actionButtons);
- hackMissionInst.selectedNode.push(node);
- }
- });
- }
-}
-
-function clearAllSelectedNodes(hackMissionInst) {
- if (hackMissionInst.selectedNode.length > 0) {
- hackMissionInst.selectedNode.forEach(function (node) {
- node.deselect(hackMissionInst.actionButtons);
- });
- hackMissionInst.selectedNode.length = 0;
- }
-}
-
-/**
- * Configures a DOM element representing a player-owned node to
- * be selectable and actionable.
- * Note: Does NOT change its css class. This is handled by Node.setControlledBy...
- */
-HackingMission.prototype.configurePlayerNodeElement = function (el) {
- var nodeObj = this.getNodeFromElement(el);
- if (nodeObj == null) {
- console.error("Failed getting Node object");
- }
-
- // Add event listener
- const selectNodeWrapper = () => {
- selectNode(this, el);
- };
- el.addEventListener("click", selectNodeWrapper);
-
- const multiselectNodeWrapper = () => {
- multiselectNode(this, el);
- };
- el.addEventListener("dblclick", multiselectNodeWrapper);
-
- if (el.firstChild) {
- el.firstChild.addEventListener("click", selectNodeWrapper);
- }
-};
-
-/**
- * Configures a DOM element representing an enemy-node by removing
- * any event listeners
- */
-HackingMission.prototype.configureEnemyNodeElement = function (el) {
- // Deselect node if it was the selected node
- var nodeObj = this.getNodeFromElement(el);
- for (var i = 0; i < this.selectedNode.length; ++i) {
- if (this.selectedNode[i] == nodeObj) {
- nodeObj.deselect(this.actionButtons);
- this.selectedNode.splice(i, 1);
- break;
- }
- }
-};
-
-/**
- * Returns bool indicating whether a node is reachable by player
- * by checking if any of the adjacent nodes are owned by the player
- */
-HackingMission.prototype.nodeReachable = function (node) {
- var x = node.pos[0],
- y = node.pos[1];
- if (x > 0 && this.map[x - 1][y].plyrCtrl) {
- return true;
- }
- if (x < 7 && this.map[x + 1][y].plyrCtrl) {
- return true;
- }
- if (y > 0 && this.map[x][y - 1].plyrCtrl) {
- return true;
- }
- if (y < 7 && this.map[x][y + 1].plyrCtrl) {
- return true;
- }
- return false;
-};
-
-HackingMission.prototype.nodeReachableByEnemy = function (node) {
- if (node == null) {
- return false;
- }
- var x = node.pos[0],
- y = node.pos[1];
- if (x > 0 && this.map[x - 1][y].enmyCtrl) {
- return true;
- }
- if (x < 7 && this.map[x + 1][y].enmyCtrl) {
- return true;
- }
- if (y > 0 && this.map[x][y - 1].enmyCtrl) {
- return true;
- }
- if (y < 7 && this.map[x][y + 1].enmyCtrl) {
- return true;
- }
- return false;
-};
-
-HackingMission.prototype.start = function () {
- this.started = true;
- this.initJsPlumb();
- var startBtn = clearEventListeners("hack-mission-start-btn");
- startBtn.classList.remove("a-link-button");
- startBtn.classList.add("a-link-button-inactive");
-};
-
-HackingMission.prototype.initJsPlumb = function () {
- var instance = jsPlumb.getInstance({
- DragOptions: { cursor: "pointer", zIndex: 2000 },
- PaintStyle: {
- gradient: {
- stops: [
- [0, "#FFFFFF"],
- [1, "#FFFFFF"],
- ],
- },
- stroke: "#FFFFFF",
- strokeWidth: 8,
- },
- });
-
- this.jsplumbinstance = instance;
-
- // All player cores are sources
- for (var i = 0; i < this.playerCores.length; ++i) {
- instance.makeSource(this.playerCores[i].el, {
- deleteEndpointsOnEmpty: true,
- maxConnections: 1,
- anchor: "Continuous",
- connector: "Flowchart",
- });
- }
-
- // Everything else is a target
- for (var i = 0; i < this.enemyCores.length; ++i) {
- instance.makeTarget(this.enemyCores[i].el, {
- maxConnections: -1,
- anchor: "Continuous",
- connector: "Flowchart",
- });
- }
- for (var i = 0; i < this.enemyDatabases.length; ++i) {
- instance.makeTarget(this.enemyDatabases[i].el, {
- maxConnections: -1,
- anchor: "Continuous",
- connector: ["Flowchart"],
- });
- }
- for (var i = 0; i < this.enemyNodes.length; ++i) {
- instance.makeTarget(this.enemyNodes[i].el, {
- maxConnections: -1,
- anchor: "Continuous",
- connector: "Flowchart",
- });
- }
- for (var i = 0; i < this.miscNodes.length; ++i) {
- instance.makeTarget(this.miscNodes[i].el, {
- maxConnections: -1,
- anchor: "Continuous",
- connector: "Flowchart",
- });
- }
-
- // Clicking a connection drops it
- instance.bind("click", (conn) => {
- // Cannot drop enemy's connections
- const sourceNode = this.getNodeFromElement(conn.source);
- if (sourceNode.enmyCtrl) {
- return;
- }
-
- var endpoints = conn.endpoints;
- endpoints[0].detachFrom(endpoints[1]);
- });
-
- // Connection events
- instance.bind("connection", (info) => {
- var targetNode = this.getNodeFromElement(info.target);
-
- // Do not detach for enemy nodes
- var thisNode = this.getNodeFromElement(info.source);
- if (thisNode.enmyCtrl) {
- return;
- }
-
- // If the node is not reachable, drop the connection
- if (!this.nodeReachable(targetNode)) {
- info.sourceEndpoint.detachFrom(info.targetEndpoint);
- return;
- }
-
- var sourceNode = this.getNodeFromElement(info.source);
- sourceNode.conn = info.connection;
- var targetNode = this.getNodeFromElement(info.target);
- ++targetNode.targetedCount;
- });
-
- // Detach Connection events
- instance.bind("connectionDetached", (info) => {
- var sourceNode = this.getNodeFromElement(info.source);
- sourceNode.conn = null;
- var targetNode = this.getNodeFromElement(info.target);
- targetNode.untarget();
- });
-};
-
-// Drops all connections where the specified node is the source
-HackingMission.prototype.dropAllConnectionsFromNode = function (node) {
- var allConns = this.jsplumbinstance.getAllConnections();
- for (var i = allConns.length - 1; i >= 0; --i) {
- if (allConns[i].source == node.el) {
- allConns[i].endpoints[0].detachFrom(allConns[i].endpoints[1]);
- }
- }
-};
-
-// Drops all connections where the specified node is the target
-HackingMission.prototype.dropAllConnectionsToNode = function (node) {
- var allConns = this.jsplumbinstance.getAllConnections();
- for (var i = allConns.length - 1; i >= 0; --i) {
- if (allConns[i].target == node.el) {
- allConns[i].endpoints[0].detachFrom(allConns[i].endpoints[1]);
- }
- }
- node.beingTargeted = false;
-};
-
-var storedCycles = 0;
-HackingMission.prototype.process = function (numCycles = 1) {
- if (!this.started) {
- return;
- }
- storedCycles += numCycles;
- if (storedCycles < 2) {
- return;
- } // Only process every 3 cycles minimum
-
- var res = false;
- // Process actions of all player nodes
- this.playerCores.forEach((node) => {
- res |= this.processNode(node, storedCycles);
- });
-
- this.playerNodes.forEach((node) => {
- if (node.type === NodeTypes.Transfer || node.type === NodeTypes.Shield || node.type === NodeTypes.Firewall) {
- res |= this.processNode(node, storedCycles);
- }
- });
-
- // Process actions of all enemy nodes
- this.enemyCores.forEach((node) => {
- this.enemyAISelectAction(node);
- res |= this.processNode(node, storedCycles);
- });
-
- this.enemyNodes.forEach((node) => {
- if (node.type === NodeTypes.Transfer || node.type === NodeTypes.Shield || node.type === NodeTypes.Firewall) {
- this.enemyAISelectAction(node);
- res |= this.processNode(node, storedCycles);
- }
- });
-
- // The hp of enemy databases increases slowly
- this.enemyDatabases.forEach((node) => {
- node.maxhp += 0.1 * storedCycles;
- node.hp += 0.1 * storedCycles;
- });
-
- if (res) {
- this.calculateAttacks();
- this.calculateDefenses();
- }
-
- // Win if all enemy databases are conquered
- if (this.enemyDatabases.length === 0) {
- this.finishMission(true);
- return;
- }
-
- // Lose if all your cores are gone
- if (this.playerCores.length === 0) {
- this.finishMission(false);
- return;
- }
-
- // Defense/hp of misc nodes increases slowly over time
- this.miscNodes.forEach((node) => {
- node.def += 0.1 * storedCycles;
- node.maxhp += 0.05 * storedCycles;
- node.hp += 0.1 * storedCycles;
- if (node.hp > node.maxhp) {
- node.hp = node.maxhp;
- }
- this.updateNodeDomElement(node);
- });
-
- // Update timer and check if player lost
- this.time -= storedCycles * CONSTANTS._idleSpeed;
- if (this.time <= 0) {
- this.finishMission(false);
- return;
- }
- this.updateTimer();
-
- storedCycles = 0;
-};
-
-// Returns a bool representing whether defenses need to be re-calculated
-HackingMission.prototype.processNode = function (nodeObj, numCycles = 1) {
- if (nodeObj.action == null) {
- return;
- }
-
- var targetNode = null,
- def,
- atk;
- if (nodeObj.conn) {
- if (nodeObj.conn.target != null) {
- targetNode = this.getNodeFromElement(nodeObj.conn.target);
- } else {
- targetNode = this.getNodeFromElement(nodeObj.conn.targetId);
- }
-
- if (targetNode == null) {
- // Player is in the middle of dragging the connection,
- // so the target node is null. Do nothing here
- } else if (targetNode.plyrCtrl) {
- def = this.playerDef;
- atk = this.enemyAtk;
- } else if (targetNode.enmyCtrl) {
- def = this.enemyDef;
- atk = this.playerAtk;
- } else {
- // Misc Node
- def = targetNode.def;
- nodeObj.plyrCtrl ? (atk = this.playerAtk) : (atk = this.enemyAtk);
- }
- }
-
- // Calculations are per second, so divide everything by 5
- var calcStats = false,
- plyr = nodeObj.plyrCtrl;
- var enmyHacking = this.difficulty * CONSTANTS.HackingMissionDifficultyToHacking;
- switch (nodeObj.action) {
- case NodeActions.Attack:
- if (targetNode == null) {
- break;
- }
- if (nodeObj.conn == null) {
- break;
- }
- var dmg = this.calculateAttackDamage(atk, def, plyr ? Player.hacking_skill : enmyHacking);
- targetNode.hp -= (dmg / 5) * numCycles;
- break;
- case NodeActions.Scan:
- if (targetNode == null) {
- break;
- }
- if (nodeObj.conn == null) {
- break;
- }
- var eff = this.calculateScanEffect(atk, def, plyr ? Player.hacking_skill : enmyHacking);
- targetNode.def -= (eff / 5) * numCycles;
- calcStats = true;
- break;
- case NodeActions.Weaken:
- if (targetNode == null) {
- break;
- }
- if (nodeObj.conn == null) {
- break;
- }
- var eff = this.calculateWeakenEffect(atk, def, plyr ? Player.hacking_skill : enmyHacking);
- targetNode.atk -= (eff / 5) * numCycles;
- calcStats = true;
- break;
- case NodeActions.Fortify:
- var eff = this.calculateFortifyEffect(Player.hacking_skill);
- nodeObj.def += (eff / 5) * numCycles;
- calcStats = true;
- break;
- case NodeActions.Overflow:
- var eff = this.calculateOverflowEffect(Player.hacking_skill);
- if (nodeObj.def < eff) {
- break;
- }
- nodeObj.def -= (eff / 5) * numCycles;
- nodeObj.atk += (eff / 5) * numCycles;
- calcStats = true;
- break;
- default:
- console.error(`Invalid Node Action: ${nodeObj.action}`);
- break;
- }
-
- // Stats can't go below 0
- if (nodeObj.atk < 0) {
- nodeObj.atk = 0;
- }
- if (nodeObj.def < 0) {
- nodeObj.def = 0;
- }
- if (targetNode && targetNode.atk < 0) {
- targetNode.atk = 0;
- }
- if (targetNode && targetNode.def < 0) {
- targetNode.def = 0;
- }
-
- // Conquering a node
- if (targetNode && targetNode.hp <= 0) {
- var conqueredByPlayer = nodeObj.plyrCtrl;
- targetNode.hp = targetNode.maxhp;
- targetNode.action = null;
- targetNode.conn = null;
- if (this.selectedNode == targetNode) {
- targetNode.deselect(this.actionButtons);
- }
-
- // The conquered node has its stats reduced
- targetNode.atk /= 2;
- targetNode.def /= 3.5;
-
- // Flag for whether the target node was a misc node
- var isMiscNode = !targetNode.plyrCtrl && !targetNode.enmyCtrl;
-
- // Remove all connections from Node
- this.dropAllConnectionsToNode(targetNode);
- this.dropAllConnectionsFromNode(targetNode);
-
- // Changes the css class and turn the node into a JsPlumb Source/Target
- if (conqueredByPlayer) {
- targetNode.setControlledByPlayer();
- this.jsplumbinstance.unmakeTarget(targetNode.el);
- this.jsplumbinstance.makeSource(targetNode.el, {
- deleteEndpointsOnEmpty: true,
- maxConnections: 1,
- anchor: "Continuous",
- connector: "Flowchart",
- });
- } else {
- targetNode.setControlledByEnemy();
- nodeObj.conn = null; // Clear connection
- this.jsplumbinstance.unmakeSource(targetNode.el);
- this.jsplumbinstance.makeTarget(targetNode.el, {
- maxConnections: -1,
- anchor: "Continuous",
- connector: ["Flowchart"],
- });
- }
-
- calcStats = true;
-
- // Helper function to swap nodes between the respective enemyNodes/playerNodes arrays
- function swapNodes(orig, dest, targetNode) {
- for (var i = 0; i < orig.length; ++i) {
- if (orig[i] == targetNode) {
- var node = orig.splice(i, 1);
- node = node[0];
- dest.push(node);
- break;
- }
- }
- }
-
- switch (targetNode.type) {
- case NodeTypes.Core:
- if (conqueredByPlayer) {
- swapNodes(this.enemyCores, this.playerCores, targetNode);
- this.configurePlayerNodeElement(targetNode.el);
- } else {
- swapNodes(this.playerCores, this.enemyCores, targetNode);
- this.configureEnemyNodeElement(targetNode.el);
- }
- break;
- case NodeTypes.Firewall:
- if (conqueredByPlayer) {
- swapNodes(this.enemyNodes, this.playerNodes, targetNode);
- } else {
- swapNodes(this.playerNodes, this.enemyNodes, targetNode);
- this.configureEnemyNodeElement(targetNode.el);
- }
- break;
- case NodeTypes.Database:
- if (conqueredByPlayer) {
- swapNodes(this.enemyDatabases, this.playerNodes, targetNode);
- } else {
- swapNodes(this.playerNodes, this.enemyDatabases, targetNode);
- }
- break;
- case NodeTypes.Spam:
- if (conqueredByPlayer) {
- swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
- // Conquering spam node increases time limit
- this.time += CONSTANTS.HackingMissionSpamTimeIncrease;
- } else {
- swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
- }
-
- break;
- case NodeTypes.Transfer:
- // Conquering a Transfer node increases the attack of all cores by some percentages
- if (conqueredByPlayer) {
- swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
- this.playerCores.forEach(function (node) {
- node.atk *= CONSTANTS.HackingMissionTransferAttackIncrease;
- });
- this.configurePlayerNodeElement(targetNode.el);
- } else {
- swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
- this.enemyCores.forEach(function (node) {
- node.atk *= CONSTANTS.HackingMissionTransferAttackIncrease;
- });
- this.configureEnemyNodeElement(targetNode.el);
- }
- break;
- case NodeTypes.Shield:
- if (conqueredByPlayer) {
- swapNodes(isMiscNode ? this.miscNodes : this.enemyNodes, this.playerNodes, targetNode);
- this.configurePlayerNodeElement(targetNode.el);
- } else {
- swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
- this.configureEnemyNodeElement(targetNode.el);
- }
- break;
- }
-
- // If a misc node was conquered, the defense for all misc nodes increases by some fixed amount
- if (isMiscNode) {
- //&& conqueredByPlayer) {
- this.miscNodes.forEach((node) => {
- if (node.targetedCount === 0) {
- node.def *= CONSTANTS.HackingMissionMiscDefenseIncrease;
- }
- });
- }
- }
-
- // Update node DOMs
- this.updateNodeDomElement(nodeObj);
- if (targetNode) {
- this.updateNodeDomElement(targetNode);
- }
- return calcStats;
-};
-
-// Enemy "AI" for CPU Core and Transfer Nodes
-HackingMission.prototype.enemyAISelectAction = function (nodeObj) {
- if (nodeObj == null) {
- return;
- }
- switch (nodeObj.type) {
- case NodeTypes.Core:
- /**
- * Select a single RANDOM target from miscNodes and player's Nodes
- * If it is reachable, it will target it. If not, no target will
- * be selected for now, and the next time process() gets called this will repeat
- */
- if (nodeObj.conn == null) {
- if (this.miscNodes.length === 0) {
- // Randomly pick a player node and attack it if its reachable
- var rand = getRandomInt(0, this.playerNodes.length - 1);
- var node;
- if (this.playerNodes.length === 0) {
- node = null;
- } else {
- node = this.playerNodes[rand];
- }
- if (this.nodeReachableByEnemy(node)) {
- // Create connection
- nodeObj.conn = this.jsplumbinstance.connect({
- source: nodeObj.el,
- target: node.el,
- });
- ++node.targetedCount;
- } else {
- // Randomly pick a player core and attack it if its reachable
- rand = getRandomInt(0, this.playerCores.length - 1);
- if (this.playerCores.length === 0) {
- return; // No Misc Nodes, no player Nodes, no Player cores. Player lost
- } else {
- node = this.playerCores[rand];
- }
-
- if (this.nodeReachableByEnemy(node)) {
- // Create connection
- nodeObj.conn = this.jsplumbinstance.connect({
- source: nodeObj.el,
- target: node.el,
- });
- ++node.targetedCount;
- }
- }
- } else {
- // Randomly pick a misc node and attack it if its reachable
- var rand = getRandomInt(0, this.miscNodes.length - 1);
- var node = this.miscNodes[rand];
- if (this.nodeReachableByEnemy(node)) {
- nodeObj.conn = this.jsplumbinstance.connect({
- source: nodeObj.el,
- target: node.el,
- });
- ++node.targetedCount;
- }
- }
-
- // If no connection was made, set the Core to Fortify
- nodeObj.action = NodeActions.Fortify;
- } else {
- // If this node has a selected target
- var targetNode;
- if (nodeObj.conn.target) {
- targetNode = this.getNodeFromElement(nodeObj.conn.target);
- } else {
- targetNode = this.getNodeFromElement(nodeObj.conn.targetId);
- }
- if (targetNode == null) {
- console.error("Error getting Target node Object in enemyAISelectAction()");
- }
-
- if (targetNode.def > this.enemyAtk + 15) {
- if (nodeObj.def < 50) {
- nodeObj.action = NodeActions.Fortify;
- } else {
- nodeObj.action = NodeActions.Overflow;
- }
- } else if (Math.abs(targetNode.def - this.enemyAtk) <= 15) {
- nodeObj.action = NodeActions.Scan;
- } else {
- nodeObj.action = NodeActions.Attack;
- }
- }
- break;
- case NodeTypes.Transfer:
- // Switch between fortifying and overflowing as necessary
- if (nodeObj.def < 125) {
- nodeObj.action = NodeActions.Fortify;
- } else {
- nodeObj.action = NodeActions.Overflow;
- }
- break;
- case NodeTypes.Firewall:
- case NodeTypes.Shield:
- nodeObj.action = NodeActions.Fortify;
- break;
- default:
- break;
- }
-};
-
-var hackEffWeightSelf = 130; // Weight for Node actions on self
-var hackEffWeightTarget = 25; // Weight for Node Actions against Target
-var hackEffWeightAttack = 80; // Weight for Attack action
-
-// Returns damage per cycle based on stats
-HackingMission.prototype.calculateAttackDamage = function (atk, def, hacking = 0) {
- return Math.max(0.55 * (atk + hacking / hackEffWeightAttack - def), 1);
-};
-
-HackingMission.prototype.calculateScanEffect = function (atk, def, hacking = 0) {
- return Math.max(0.6 * (atk + hacking / hackEffWeightTarget - def * 0.95), 2);
-};
-
-HackingMission.prototype.calculateWeakenEffect = function (atk, def, hacking = 0) {
- return Math.max(atk + hacking / hackEffWeightTarget - def * 0.95, 2);
-};
-
-HackingMission.prototype.calculateFortifyEffect = function (hacking = 0) {
- return (0.9 * hacking) / hackEffWeightSelf;
-};
-
-HackingMission.prototype.calculateOverflowEffect = function (hacking = 0) {
- return (0.95 * hacking) / hackEffWeightSelf;
-};
-
-// Updates timer display
-HackingMission.prototype.updateTimer = function () {
- var timer = document.getElementById("hacking-mission-timer");
-
- // Convert time remaining to a string of the form mm:ss
- var seconds = Math.round(this.time / 1000);
- var minutes = Math.trunc(seconds / 60);
- seconds %= 60;
- var str = ("0" + minutes).slice(-2) + ":" + ("0" + seconds).slice(-2);
- timer.innerText = "Time left: " + str;
-};
-
-// The 'win' argument is a bool for whether or not the player won
-HackingMission.prototype.finishMission = function (win) {
- inMission = false;
- currMission = null;
-
- if (win) {
- var favorMult = 1 + this.faction.favor / 100;
- var gain = this.reward * Player.faction_rep_mult * favorMult;
- dialogBoxCreate(
- <>
- Mission won! You earned {Reputation(gain)} reputation with {this.faction.name}
- >,
- );
- Player.gainIntelligenceExp(Math.pow(this.difficulty * CONSTANTS.IntelligenceHackingMissionBaseExpGain, 0.5));
- this.faction.playerReputation += gain;
- } else {
- dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
- }
- Router.toFaction();
-};
-
-export { HackingMission, inMission, setInMission, currMission };
diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts
index f9755b191..675a1d076 100644
--- a/src/NetscriptFunctions.ts
+++ b/src/NetscriptFunctions.ts
@@ -98,7 +98,6 @@ import { Terminal } from "./Terminal";
import { calculateSkill, calculateExp } from "./PersonObjects/formulas/skill";
import { Message } from "./Message/Message";
-import { inMission } from "./Missions";
import { Player } from "./Player";
import { Programs } from "./Programs/Programs";
import { Script } from "./Script/Script";
@@ -2965,10 +2964,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
universityCourse: function (universityName: any, className: any): any {
updateDynamicRam("universityCourse", getRamCost("universityCourse"));
checkSingularityAccess("universityCourse", 1);
- if (inMission) {
- workerScript.log("universityCourse", "You are in the middle of a mission.");
- return;
- }
if (Player.isWorking) {
const txt = Player.singularityStopWork();
workerScript.log("universityCourse", txt);
@@ -3049,10 +3044,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
gymWorkout: function (gymName: any, stat: any): any {
updateDynamicRam("gymWorkout", getRamCost("gymWorkout"));
checkSingularityAccess("gymWorkout", 1);
- if (inMission) {
- workerScript.log("gymWorkout", "You are in the middle of a mission.");
- return;
- }
if (Player.isWorking) {
const txt = Player.singularityStopWork();
workerScript.log("gymWorkout", txt);
@@ -3486,7 +3477,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
isBusy: function (): any {
updateDynamicRam("isBusy", getRamCost("isBusy"));
checkSingularityAccess("isBusy", 1);
- return Player.isWorking || inMission;
+ return Player.isWorking;
},
stopAction: function (): any {
updateDynamicRam("stopAction", getRamCost("stopAction"));
@@ -3553,12 +3544,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return false;
}
- // Cant work while in a mission
- if (inMission) {
- workerScript.log("workForCompany", "You are in the middle of a mission.");
- return false;
- }
-
// Check to make sure company position data is valid
const companyPositionName = Player.jobs[companyName];
const companyPosition = CompanyPositions[companyPositionName];
@@ -3708,11 +3693,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return;
}
- if (inMission) {
- workerScript.log("workForFaction", "You are in the middle of a mission.");
- return;
- }
-
if (!Player.factions.includes(name)) {
workerScript.log("workForFaction", `You are not a member of '${name}'`);
return false;
@@ -3900,10 +3880,6 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("createProgram", getRamCost("createProgram"));
checkSingularityAccess("createProgram", 3);
- if (inMission) {
- workerScript.log("createProgram", "You are in the middle of a mission.");
- return;
- }
if (Player.isWorking) {
const txt = Player.singularityStopWork();
workerScript.log("createProgram", txt);
@@ -3946,10 +3922,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
commitCrime: function (crimeRoughName: any): any {
updateDynamicRam("commitCrime", getRamCost("commitCrime"));
checkSingularityAccess("commitCrime", 3);
- if (inMission) {
- workerScript.log("commitCrime", "You are in the middle of a mission.");
- return;
- }
+
if (Player.isWorking) {
const txt = Player.singularityStopWork();
workerScript.log("commitCrime", txt);
diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx
index e314e6393..4aed01d3e 100644
--- a/src/Sidebar/ui/SidebarRoot.tsx
+++ b/src/Sidebar/ui/SidebarRoot.tsx
@@ -50,7 +50,6 @@ import { getAvailableCreatePrograms } from "../../Programs/ProgramHelpers";
import { Settings } from "../../Settings/Settings";
import { redPillFlag } from "../../RedPill";
-import { inMission } from "../../Missions";
import { KEY } from "../../utils/helpers/keyCodes";
const openedMixin = (theme: Theme): CSSObject => ({
@@ -266,7 +265,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
// Alt-o - Options
function handleShortcuts(this: Document, event: KeyboardEvent): any {
if (Settings.DisableHotkeys) return;
- if (props.player.isWorking || redPillFlag || inMission) return;
+ if (props.player.isWorking || redPillFlag) return;
if (event.keyCode == KEY.T && event.altKey) {
event.preventDefault();
clickTerminal();
diff --git a/src/engine.tsx b/src/engine.tsx
index 361c71685..a691952a6 100644
--- a/src/engine.tsx
+++ b/src/engine.tsx
@@ -23,7 +23,6 @@ import {
import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers";
import { iTutorialStart } from "./InteractiveTutorial";
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
-import { inMission, currMission } from "./Missions";
import { loadAllRunningScripts, updateOnlineScriptTimes } from "./NetscriptWorker";
import { Player } from "./Player";
import { saveObject, loadGame } from "./SaveObject";
@@ -131,11 +130,6 @@ const Engine: {
Player.gang.process(numCycles, Player);
}
- // Mission
- if (inMission && currMission) {
- currMission.process(numCycles);
- }
-
// Corporation
if (Player.corporation instanceof Corporation) {
// Stores cycles in a "buffer". Processed separately using Engine Counters
diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx
index 1816067d6..beeaffef4 100644
--- a/src/ui/GameRoot.tsx
+++ b/src/ui/GameRoot.tsx
@@ -56,7 +56,6 @@ import { TerminalRoot } from "../Terminal/ui/TerminalRoot";
import { TutorialRoot } from "../Tutorial/ui/TutorialRoot";
import { ActiveScriptsRoot } from "../ui/ActiveScripts/ActiveScriptsRoot";
import { FactionsRoot } from "../Faction/ui/FactionsRoot";
-import { HackingMissionRoot } from "../HackingMission/ui/HackingMissionRoot";
import { FactionRoot } from "../Faction/ui/FactionRoot";
import { CharacterStats } from "./CharacterStats";
import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot";
@@ -178,9 +177,6 @@ export let Router: IRouter = {
toLocation: () => {
throw new Error("Router called before initialization");
},
- toHackingMission: () => {
- throw new Error("Router called before initialization");
- },
};
function determineStartPage(player: IPlayer): Page {
@@ -270,10 +266,6 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
setLocation(location);
setPage(Page.Location);
},
- toHackingMission: (faction: Faction) => {
- setPage(Page.HackingMission);
- setFaction(faction);
- },
};
useEffect(() => {
@@ -296,8 +288,6 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
) : page === Page.Infiltration ? (
- ) : page === Page.HackingMission ? (
-
) : page === Page.BladeburnerCinematic ? (
) : page === Page.Work ? (
diff --git a/src/ui/React/Overview.tsx b/src/ui/React/Overview.tsx
index ca3d08024..3b0dc71bb 100644
--- a/src/ui/React/Overview.tsx
+++ b/src/ui/React/Overview.tsx
@@ -23,8 +23,7 @@ export function Overview({ children }: IProps): React.ReactElement {
const [open, setOpen] = useState(true);
const classes = useStyles();
const router = use.Router();
- if (router.page() === Page.BitVerse || router.page() === Page.HackingMission || router.page() === Page.Loading)
- return <>>;
+ if (router.page() === Page.BitVerse || router.page() === Page.Loading) return <>>;
let icon;
if (open) {
icon = ;
diff --git a/src/ui/Router.ts b/src/ui/Router.ts
index 206377b42..267d137a7 100644
--- a/src/ui/Router.ts
+++ b/src/ui/Router.ts
@@ -33,7 +33,6 @@ export enum Page {
Work,
BladeburnerCinematic,
Location,
- HackingMission,
Loading,
}
@@ -74,5 +73,4 @@ export interface IRouter {
toWork(): void;
toBladeburnerCinematic(): void;
toLocation(location: Location): void;
- toHackingMission(faction: Faction): void;
}