Refactored Main Menu UI implementation. Fixed several bugs related to recent JS -> TypeScript refactors

This commit is contained in:
danielyxie 2019-01-18 09:57:21 -08:00
parent aac262b736
commit 7db169f828
16 changed files with 14842 additions and 13117 deletions

25922
dist/engine.bundle.js vendored

File diff suppressed because it is too large Load Diff

1337
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -598,6 +598,9 @@
<!-- Bladeburner @ NSA --> <!-- Bladeburner @ NSA -->
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a> <a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
<!-- Re-sleeving @ VitaLife -->
<a id="location-vitalife-resleeve" class="a-link-button">Re-Sleeve</a>
</div> </div>
<div id="infiltration-container" class="generic-menupage-container"> <div id="infiltration-container" class="generic-menupage-container">

@ -1,3 +1,7 @@
import { Crimes } from "./Crimes";
import { dialogBoxCreate } from "../../utils/DialogBox";
export function determineCrimeSuccess(type, moneyGained) { export function determineCrimeSuccess(type, moneyGained) {
var chance = 0; var chance = 0;
var found = false; var found = false;

@ -15,6 +15,7 @@ import {Server, AllServers, AddToAllServers} from "./Server";
import {purchaseServer, import {purchaseServer,
purchaseRamForHomeComputer} from "./ServerPurchases"; purchaseRamForHomeComputer} from "./ServerPurchases";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps"; import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps";
import {numeralWrapper} from "./ui/numeralFormat"; import {numeralWrapper} from "./ui/numeralFormat";
@ -121,6 +122,8 @@ function displayLocationContent() {
var nsaBladeburner = document.getElementById("location-nsa-bladeburner"); var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
const vitalifeResleeve = document.getElementById("location-vitalife-resleeve");
var loc = Player.location; var loc = Player.location;
returnToWorld.addEventListener("click", function() { returnToWorld.addEventListener("click", function() {
@ -237,6 +240,7 @@ function displayLocationContent() {
cityHallCreateCorporation.style.display = "none"; cityHallCreateCorporation.style.display = "none";
nsaBladeburner.style.display = "none"; nsaBladeburner.style.display = "none";
vitalifeResleeve.style.display = "none";
//Check if the player is employed at this Location. If he is, display the "Work" button, //Check if the player is employed at this Location. If he is, display the "Work" button,
//update the job title, etc. //update the job title, etc.
@ -271,9 +275,9 @@ function displayLocationContent() {
work.addEventListener("click", function() { work.addEventListener("click", function() {
if (currPos.isPartTimeJob() || currPos.isSoftwareConsultantJob() || currPos.isBusinessConsultantJob()) { if (currPos.isPartTimeJob() || currPos.isSoftwareConsultantJob() || currPos.isBusinessConsultantJob()) {
Player.startWorkPartTime(); Player.startWorkPartTime(loc);
} else { } else {
Player.startWork(); Player.startWork(loc);
} }
return false; return false;
}); });
@ -761,6 +765,10 @@ function displayLocationContent() {
businessJob.style.display = "block"; businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife, setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife,
605, 22, 100, 3.5); 605, 22, 100, 3.5);
if (Player.bitNodeN === 10 || SourceFileFlags[10]) {
vitalifeResleeve.style.display = "block";
}
break; break;
case Locations.NewTokyoGlobalPharmaceuticals: case Locations.NewTokyoGlobalPharmaceuticals:
@ -1634,6 +1642,8 @@ function initLocationButtons() {
var nsaBladeburner = document.getElementById("location-nsa-bladeburner"); var nsaBladeburner = document.getElementById("location-nsa-bladeburner");
const vitalifeResleeve = document.getElementById("location-vitalife-resleeve");
var hospitalTreatment = document.getElementById("location-hospital-treatment"); var hospitalTreatment = document.getElementById("location-hospital-treatment");
softwareJob.addEventListener("click", function(e) { softwareJob.addEventListener("click", function(e) {
@ -2041,6 +2051,10 @@ function initLocationButtons() {
} }
}); });
vitalifeResleeve.addEventListener("click", function() {
Engine.loadResleevingContent();
});
hospitalTreatment.addEventListener("click", function(e) { hospitalTreatment.addEventListener("click", function(e) {
if (!e.isTrusted) {return false;} if (!e.isTrusted) {return false;}
if (Player.hp < 0) {Player.hp = 0;} if (Player.hp < 0) {Player.hp = 0;}

@ -419,7 +419,7 @@ function NetscriptFunctions(workerScript) {
// Check argument validity // Check argument validity
const server = safeGetServer(ip, 'hackAnalyzeThreads'); const server = safeGetServer(ip, 'hackAnalyzeThreads');
if (isNaN(hackAmount)) { if (isNaN(hackAmount)) {
throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into growthAnalyze: ${hackAmount}. Must be numeric`); throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into hackAnalyzeThreads: ${hackAmount}. Must be numeric`);
} }
if (hackAmount < 0 || hackAmount > server.moneyAvailable) { if (hackAmount < 0 || hackAmount > server.moneyAvailable) {
@ -3080,11 +3080,10 @@ function NetscriptFunctions(workerScript) {
} }
} }
Player.companyName = companyName;
if (companyPosition.isPartTimeJob()) { if (companyPosition.isPartTimeJob()) {
Player.startWorkPartTime(); Player.startWorkPartTime(companyName);
} else { } else {
Player.startWork(); Player.startWork(companyName);
} }
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.workForCompany == null) {
workerScript.log(`Began working at ${Player.companyName} as a ${companyPositionName}`); workerScript.log(`Began working at ${Player.companyName} as a ${companyPositionName}`);

@ -12,9 +12,13 @@ import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentatio
import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile"; import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile";
export interface IPlayer { export interface IPlayer {
// Class members
augmentations: IPlayerOwnedAugmentation[]; augmentations: IPlayerOwnedAugmentation[];
bladeburner: any;
companyName: string; companyName: string;
corporation: any;
factions: string[]; factions: string[];
hasWseAccount: boolean;
jobs: IMap<string>; jobs: IMap<string>;
money: any; money: any;
queuedAugmentations: IPlayerOwnedAugmentation[]; queuedAugmentations: IPlayerOwnedAugmentation[];
@ -22,6 +26,7 @@ export interface IPlayer {
sleeves: Sleeve[]; sleeves: Sleeve[];
sourceFiles: IPlayerOwnedSourceFile[]; sourceFiles: IPlayerOwnedSourceFile[];
// Stats
hacking_skill: number; hacking_skill: number;
strength: number; strength: number;
defense: number; defense: number;
@ -30,6 +35,7 @@ export interface IPlayer {
charisma: number; charisma: number;
intelligence: number; intelligence: number;
// Experience
hacking_exp: number; hacking_exp: number;
strength_exp: number; strength_exp: number;
defense_exp: number; defense_exp: number;
@ -37,8 +43,10 @@ export interface IPlayer {
agility_exp: number; agility_exp: number;
charisma_exp: number; charisma_exp: number;
// Multipliers
crime_success_mult: number; crime_success_mult: number;
// Methods
gainHackingExp(exp: number): void; gainHackingExp(exp: number): void;
gainStrengthExp(exp: number): void; gainStrengthExp(exp: number): void;
gainDefenseExp(exp: number): void; gainDefenseExp(exp: number): void;
@ -46,6 +54,9 @@ export interface IPlayer {
gainAgilityExp(exp: number): void; gainAgilityExp(exp: number): void;
gainCharismaExp(exp: number): void; gainCharismaExp(exp: number): void;
gainMoney(money: number): void; gainMoney(money: number): void;
hasCorporation(): boolean;
inBladeburner(): boolean;
inGang(): boolean;
loseMoney(money: number): void; loseMoney(money: number): void;
reapplyAllAugmentations(resetMultipliers: boolean): void; reapplyAllAugmentations(resetMultipliers: boolean): void;
startCrime(crimeType: string, startCrime(crimeType: string,

@ -3,6 +3,7 @@ import { applyAugmentation } from "./Augmentation/Augmentatio
import { PlayerOwnedAugmentation } from "./Augmentation/PlayerOwnedAugmentation"; import { PlayerOwnedAugmentation } from "./Augmentation/PlayerOwnedAugmentation";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { Bladeburner } from "./Bladeburner";
import { CodingContractRewardType } from "./CodingContracts"; import { CodingContractRewardType } from "./CodingContracts";
import { Company } from "./Company/Company"; import { Company } from "./Company/Company";
import { Companies } from "./Company/Companies"; import { Companies } from "./Company/Companies";
@ -688,9 +689,10 @@ PlayerObject.prototype.processWorkEarnings = function(numCycles=1) {
} }
/* Working for Company */ /* Working for Company */
PlayerObject.prototype.startWork = function() { PlayerObject.prototype.startWork = function(companyName) {
this.resetWorkStatus(); this.resetWorkStatus();
this.isWorking = true; this.isWorking = true;
this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompany; this.workType = CONSTANTS.WorkTypeCompany;
this.workHackExpGainRate = this.getWorkHackExpGain(); this.workHackExpGainRate = this.getWorkHackExpGain();
@ -811,9 +813,10 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
this.resetWorkStatus(); this.resetWorkStatus();
} }
PlayerObject.prototype.startWorkPartTime = function() { PlayerObject.prototype.startWorkPartTime = function(companyName) {
this.resetWorkStatus(); this.resetWorkStatus();
this.isWorking = true; this.isWorking = true;
this.companyName = companyName;
this.workType = CONSTANTS.WorkTypeCompanyPartTime; this.workType = CONSTANTS.WorkTypeCompanyPartTime;
this.workHackExpGainRate = this.getWorkHackExpGain(); this.workHackExpGainRate = this.getWorkHackExpGain();
@ -2309,6 +2312,18 @@ PlayerObject.prototype.startGang = function(factionName, hacking) {
this.gang = new Gang(factionName, hacking); this.gang = new Gang(factionName, hacking);
} }
/*************** Corporation ****************/
PlayerObject.prototype.hasCorporation = function() {
if (this.corporation == null) { return false; }
return (this.corporation instanceof Corporation);
}
/*************** Bladeburner ****************/
PlayerObject.prototype.inBladeburner = function() {
if (this.bladeburner == null) { return false; }
return (this.bladeburner instanceof Bladeburner);
}
/************* BitNodes **************/ /************* BitNodes **************/
PlayerObject.prototype.setBitNodeNumber = function(n) { PlayerObject.prototype.setBitNodeNumber = function(n) {
this.bitNodeN = n; this.bitNodeN = n;

@ -311,6 +311,11 @@ function prestigeSourceFile() {
Player.hasTixApiAccess = true; Player.hasTixApiAccess = true;
} }
// Bit Node 10: Digital Carbon
if (Player.bitNodeN === 10) {
dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!");
}
//Reset Stock market, gang, and corporation //Reset Stock market, gang, and corporation
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
initStockMarket(); initStockMarket();

@ -213,7 +213,8 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
var elem = clearEventListeners(elemId); var elem = clearEventListeners(elemId);
if (elem == null) {return;} if (elem == null) {return;}
if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 || if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 ||
i === 6 || i === 7 || i === 8 || i === 11 || i === 12) { i === 6 || i === 7 || i === 8 || i === 10 || i === 11 ||
i === 12) {
elem.addEventListener("click", function() { elem.addEventListener("click", function() {
var bitNodeKey = "BitNode" + i; var bitNodeKey = "BitNode" + i;
var bitNode = BitNodes[bitNodeKey]; var bitNode = BitNodes[bitNodeKey];

@ -153,8 +153,8 @@ function evaluateVersionCompatibility(ver) {
} }
// This version allowed players to hold multiple jobs // This version allowed players to hold multiple jobs
if (ver <= "0.43.0") { if (ver < "0.43.0") {
if (Player.companyName !== "" && Player.companyPosition !== "") { if (Player.companyName !== "" && Player.companyPosition != null && Player.companyPosition !== "") {
console.log("Copied player's companyName and companyPosition properties to the Player.jobs map for v0.43.0"); console.log("Copied player's companyName and companyPosition properties to the Player.jobs map for v0.43.0");
Player.jobs[Player.companyName] = Player.companyPosition; Player.jobs[Player.companyName] = Player.companyPosition;
} }

@ -1,16 +1,3 @@
import { dialogBoxCreate} from "../utils/DialogBox";
import { gameOptionsBoxClose,
gameOptionsBoxOpen } from "../utils/GameOptions";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
import { createElement } from "../utils/uiHelpers/createElement";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
import {numeralWrapper} from "./ui/numeralFormat";
import { createStatusText } from "./ui/createStatusText";
import {formatNumber, import {formatNumber,
convertTimeMsToTimeElapsedString, convertTimeMsToTimeElapsedString,
replaceAt} from "../utils/StringHelperFunctions"; replaceAt} from "../utils/StringHelperFunctions";
@ -68,7 +55,6 @@ import {loadAllRunningScripts, scriptEditorInit,
updateScriptEditorContent} from "./Script"; updateScriptEditorContent} from "./Script";
import {AllServers, Server, initForeignServers} from "./Server"; import {AllServers, Server, initForeignServers} from "./Server";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import {setSettingsLabels} from "./ui/setSettingsLabels";
import { initSourceFiles, SourceFiles } from "./SourceFile"; import { initSourceFiles, SourceFiles } from "./SourceFile";
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags"; import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
@ -79,8 +65,30 @@ import {StockMarket, StockSymbols,
processStockPrices, processStockPrices,
displayStockMarketContent} from "./StockMarket/StockMarket"; displayStockMarketContent} from "./StockMarket/StockMarket";
import {Terminal, postNetburnerText} from "./Terminal"; import {Terminal, postNetburnerText} from "./Terminal";
import {KEY} from "../utils/helpers/keyCodes";
import { clearResleevesPage,
createResleevesPage } from "./PersonObjects/Resleeving/ResleevingUI";
import { createStatusText } from "./ui/createStatusText";
import {Page, routing} from "./ui/navigationTracking"; import {Page, routing} from "./ui/navigationTracking";
import {numeralWrapper} from "./ui/numeralFormat";
import {setSettingsLabels} from "./ui/setSettingsLabels";
import { initializeMainMenuHeaders } from "./ui/MainMenu/Headers";
import { initializeMainMenuLinks,
MainMenuLinks } from "./ui/MainMenu/Links";
import { dialogBoxCreate} from "../utils/DialogBox";
import { gameOptionsBoxClose,
gameOptionsBoxOpen } from "../utils/GameOptions";
import { getRandomInt } from "../utils/helpers/getRandomInt";
import { removeChildrenFromElement } from "../utils/uiHelpers/removeChildrenFromElement";
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
import { createElement } from "../utils/uiHelpers/createElement";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
import {KEY} from "../utils/helpers/keyCodes";
// These should really be imported with the module that is presenting that UI, but because they very much depend on the // These should really be imported with the module that is presenting that UI, but because they very much depend on the
// cascade order, we'll pull them all in here. // cascade order, we'll pull them all in here.
@ -180,23 +188,6 @@ const Engine = {
//Clickable objects //Clickable objects
Clickables: { Clickables: {
//Main menu buttons //Main menu buttons
terminalMainMenuButton: null,
characterMainMenuButton: null,
scriptEditorMainMenuButton: null,
activeScriptsMainMenuButton: null,
hacknetNodesMainMenuButton: null,
worldMainMenuButton: null,
travelMainMenuButton: null,
jobMainMenuButton: null,
stockmarketMainMenuButton: null,
createProgramMainMenuButton: null,
factionsMainMenuButton: null,
augmentationsMainMenuButton: null,
tutorialMainMenuButton: null,
bladeburnerMenuButton: null,
corporationMenuButton: null,
gangMenuButton: null,
devMainMenuButton: null,
saveMainMenuButton: null, saveMainMenuButton: null,
deleteMainMenuButton: null, deleteMainMenuButton: null,
@ -256,7 +247,7 @@ const Engine = {
Engine.hideAllContent(); Engine.hideAllContent();
Engine.Display.terminalContent.style.display = "block"; Engine.Display.terminalContent.style.display = "block";
routing.navigateTo(Page.Terminal); routing.navigateTo(Page.Terminal);
document.getElementById("terminal-menu-link").classList.add("active"); MainMenuLinks.Terminal.classList.add("active");
}, },
loadCharacterContent: function() { loadCharacterContent: function() {
@ -264,7 +255,7 @@ const Engine = {
Engine.Display.characterContent.style.display = "block"; Engine.Display.characterContent.style.display = "block";
Engine.displayCharacterInfo(); Engine.displayCharacterInfo();
routing.navigateTo(Page.CharacterInfo); routing.navigateTo(Page.CharacterInfo);
document.getElementById("stats-menu-link").classList.add("active"); MainMenuLinks.Stats.classList.add("active");
}, },
loadScriptEditorContent: function(filename = "", code = "") { loadScriptEditorContent: function(filename = "", code = "") {
@ -278,7 +269,7 @@ const Engine = {
editor.focus(); editor.focus();
updateScriptEditorContent(); updateScriptEditorContent();
routing.navigateTo(Page.ScriptEditor); routing.navigateTo(Page.ScriptEditor);
document.getElementById("create-script-menu-link").classList.add("active"); MainMenuLinks.ScriptEditor.classList.add("active");
}, },
loadActiveScriptsContent: function() { loadActiveScriptsContent: function() {
@ -286,7 +277,7 @@ const Engine = {
Engine.Display.activeScriptsContent.style.display = "block"; Engine.Display.activeScriptsContent.style.display = "block";
updateActiveScriptsItems(); updateActiveScriptsItems();
routing.navigateTo(Page.ActiveScripts); routing.navigateTo(Page.ActiveScripts);
document.getElementById("active-scripts-menu-link").classList.add("active"); MainMenuLinks.ActiveScripts.classList.add("active");
}, },
loadHacknetNodesContent: function() { loadHacknetNodesContent: function() {
@ -294,7 +285,7 @@ const Engine = {
Engine.Display.hacknetNodesContent.style.display = "block"; Engine.Display.hacknetNodesContent.style.display = "block";
displayHacknetNodesContent(); displayHacknetNodesContent();
routing.navigateTo(Page.HacknetNodes); routing.navigateTo(Page.HacknetNodes);
document.getElementById("hacknet-nodes-menu-link").classList.add("active"); MainMenuLinks.HacknetNodes.classList.add("active");
}, },
loadWorldContent: function() { loadWorldContent: function() {
@ -302,7 +293,7 @@ const Engine = {
Engine.Display.worldContent.style.display = "block"; Engine.Display.worldContent.style.display = "block";
Engine.displayWorldInfo(); Engine.displayWorldInfo();
routing.navigateTo(Page.World); routing.navigateTo(Page.World);
document.getElementById("city-menu-link").classList.add("active"); MainMenuLinks.City.classList.add("active");
}, },
loadCreateProgramContent: function() { loadCreateProgramContent: function() {
@ -310,7 +301,7 @@ const Engine = {
Engine.Display.createProgramContent.style.display = "block"; Engine.Display.createProgramContent.style.display = "block";
displayCreateProgramContent(); displayCreateProgramContent();
routing.navigateTo(Page.CreateProgram); routing.navigateTo(Page.CreateProgram);
document.getElementById("create-program-menu-link").classList.add("active"); MainMenuLinks.CreateProgram.classList.add("active");
}, },
loadFactionsContent: function() { loadFactionsContent: function() {
@ -318,7 +309,7 @@ const Engine = {
Engine.Display.factionsContent.style.display = "block"; Engine.Display.factionsContent.style.display = "block";
Engine.displayFactionsInfo(); Engine.displayFactionsInfo();
routing.navigateTo(Page.Factions); routing.navigateTo(Page.Factions);
document.getElementById("factions-menu-link").classList.add("active"); MainMenuLinks.Factions.classList.add("active");
}, },
loadFactionContent: function() { loadFactionContent: function() {
@ -332,7 +323,7 @@ const Engine = {
Engine.Display.augmentationsContent.style.display = "block"; Engine.Display.augmentationsContent.style.display = "block";
displayAugmentationsContent(Engine.Display.augmentationsContent); displayAugmentationsContent(Engine.Display.augmentationsContent);
routing.navigateTo(Page.Augmentations); routing.navigateTo(Page.Augmentations);
document.getElementById("augmentations-menu-link").classList.add("active"); MainMenuLinks.Augmentations.classList.add("active");
}, },
loadTutorialContent: function() { loadTutorialContent: function() {
@ -340,14 +331,14 @@ const Engine = {
Engine.Display.tutorialContent.style.display = "block"; Engine.Display.tutorialContent.style.display = "block";
Engine.displayTutorialContent(); Engine.displayTutorialContent();
routing.navigateTo(Page.Tutorial); routing.navigateTo(Page.Tutorial);
document.getElementById("tutorial-menu-link").classList.add("active"); MainMenuLinks.Tutorial.classList.add("active");
}, },
loadDevMenuContent: function() { loadDevMenuContent: function() {
Engine.hideAllContent(); Engine.hideAllContent();
createDevMenu(); createDevMenu();
routing.navigateTo(Page.DevMenu); routing.navigateTo(Page.DevMenu);
document.getElementById("dev-menu-link").classList.add("active"); MainMenuLinks.DevMenu.classList.add("active");
}, },
loadLocationContent: function() { loadLocationContent: function() {
@ -479,7 +470,17 @@ const Engine = {
}, },
loadSleevesContent: function() { loadSleevesContent: function() {
// This is for Duplicate Sleeves page, not Re-sleeving @ Vita Life
},
loadResleevingContent: function() {
try {
Engine.hideAllContent();
routing.navigateTo(Page.Resleeves);
createResleevesPage(Player);
} catch(e) {
exceptionAlert(e);
}
}, },
//Helper function that hides all content //Helper function that hides all content
@ -527,23 +528,24 @@ const Engine = {
Engine.volhavenLocationsList.style.display = "none"; Engine.volhavenLocationsList.style.display = "none";
//Make nav menu tabs inactive //Make nav menu tabs inactive
document.getElementById("terminal-menu-link").classList.remove("active"); MainMenuLinks.Terminal.classList.remove("active");
document.getElementById("create-script-menu-link").classList.remove("active"); MainMenuLinks.ScriptEditor.classList.remove("active");
document.getElementById("active-scripts-menu-link").classList.remove("active"); MainMenuLinks.ActiveScripts.classList.remove("active");
document.getElementById("create-program-menu-link").classList.remove("active"); MainMenuLinks.CreateProgram.classList.remove("active");
document.getElementById("stats-menu-link").classList.remove("active"); MainMenuLinks.Stats.classList.remove("active");
document.getElementById("factions-menu-link").classList.remove("active"); MainMenuLinks.Factions.classList.remove("active");
document.getElementById("augmentations-menu-link").classList.remove("active"); MainMenuLinks.Augmentations.classList.remove("active");
document.getElementById("hacknet-nodes-menu-link").classList.remove("active"); MainMenuLinks.HacknetNodes.classList.remove("active");
document.getElementById("city-menu-link").classList.remove("active"); MainMenuLinks.City.classList.remove("active");
document.getElementById("travel-menu-link").classList.remove("active"); MainMenuLinks.Travel.classList.remove("active");
document.getElementById("stock-market-menu-link").classList.remove("active"); MainMenuLinks.Job.classList.remove("active");
document.getElementById("tutorial-menu-link").classList.remove("active"); MainMenuLinks.StockMarket.classList.remove("active");
document.getElementById("options-menu-link").classList.remove("active"); MainMenuLinks.Bladeburner.classList.remove("active");
document.getElementById("dev-menu-link").classList.remove("active"); MainMenuLinks.Corporation.classList.remove("active");
document.getElementById("bladeburner-menu-link").classList.remove("active"); MainMenuLinks.Gang.classList.remove("active");
document.getElementById("corporation-menu-link").classList.remove("active"); MainMenuLinks.Tutorial.classList.remove("active");
document.getElementById("gang-menu-link").classList.remove("active"); MainMenuLinks.Options.classList.remove("active");
MainMenuLinks.DevMenu.classList.remove("active");
// Close dev menu // Close dev menu
closeDevMenu(); closeDevMenu();
@ -1514,6 +1516,14 @@ const Engine = {
Engine.Clickables.tutorialBackButton.addEventListener("click", function() { Engine.Clickables.tutorialBackButton.addEventListener("click", function() {
Engine.displayTutorialContent(); Engine.displayTutorialContent();
}); });
// Initialize references to main menu links
if (!initializeMainMenuLinks()) {
const errorMsg = "Failed to initialize Main Menu Links. Please try refreshing the page. " +
"If that doesn't work, report the issue to the developer";
exceptionAlert(new Error(errorMsg));
return;
}
}, },
/* Initialization */ /* Initialization */
@ -1523,221 +1533,99 @@ const Engine = {
saveObject.importGame(); saveObject.importGame();
}; };
//Main menu accordions // Initialize Main Menu Headers (this must be done after initializing the links)
var hackingHdr = document.getElementById("hacking-menu-header"); if (!initializeMainMenuHeaders(Player, process.env.NODE_ENV === "development")) {
var characterHdr = document.getElementById("character-menu-header"); const errorMsg = "Failed to initialize Main Menu Headers. Please try refreshing the page. " +
var worldHdr = document.getElementById("world-menu-header"); "If that doesn't work, report the issue to the developer";
var helpHdr = document.getElementById("help-menu-header"); exceptionAlert(new Error(errorMsg));
return;
hackingHdr.onclick = function() {
var terminal = document.getElementById("terminal-tab");
var terminalLink = document.getElementById("terminal-menu-link");
var createScript = document.getElementById("create-script-tab");
var createScriptLink = document.getElementById("create-script-menu-link");
var activeScripts = document.getElementById("active-scripts-tab");
var activeScriptsLink = document.getElementById("active-scripts-menu-link");
var createProgram = document.getElementById("create-program-tab");
var createProgramLink = document.getElementById("create-program-menu-link");
var createProgramNot = document.getElementById("create-program-notification");
this.classList.toggle("opened");
if (terminal.style.maxHeight) {
Engine.toggleMainMenuHeader(false,
[terminal, createScript, activeScripts, createProgram],
[terminalLink, createScriptLink, activeScriptsLink, createProgramLink]
);
createProgramNot.style.display = "none";
} else {
Engine.toggleMainMenuHeader(true,
[terminal, createScript, activeScripts, createProgram],
[terminalLink, createScriptLink, activeScriptsLink, createProgramLink]
);
createProgramNot.style.display = "block"
}
} }
characterHdr.onclick = function() { MainMenuLinks.Terminal.addEventListener("click", function() {
var stats = document.getElementById("stats-tab");
var statsLink = document.getElementById("stats-menu-link");
var factions = document.getElementById("factions-tab");
var factionsLink = document.getElementById("factions-menu-link");
var augmentations = document.getElementById("augmentations-tab");
var augmentationsLink = document.getElementById("augmentations-menu-link");
var hacknetnodes = document.getElementById("hacknet-nodes-tab");
var hacknetnodesLink = document.getElementById("hacknet-nodes-menu-link");
this.classList.toggle("opened");
if (stats.style.maxHeight) {
Engine.toggleMainMenuHeader(false,
[stats, factions, augmentations, hacknetnodes],
[statsLink, factionsLink, augmentationsLink, hacknetnodesLink]
);
} else {
Engine.toggleMainMenuHeader(true,
[stats, factions, augmentations, hacknetnodes],
[statsLink, factionsLink, augmentationsLink, hacknetnodesLink]
);
}
}
worldHdr.onclick = function() {
var city = document.getElementById("city-tab");
var cityLink = document.getElementById("city-menu-link");
var travel = document.getElementById("travel-tab");
var travelLink = document.getElementById("travel-menu-link");
var job = document.getElementById("job-tab");
var jobLink = document.getElementById("job-menu-link");
var stockmarket = document.getElementById("stock-market-tab");
var stockmarketLink = document.getElementById("stock-market-menu-link");
var bladeburner = document.getElementById("bladeburner-tab");
var bladeburnerLink = document.getElementById("bladeburner-menu-link");
var corporation = document.getElementById("corporation-tab");
var corporationLink = document.getElementById("corporation-menu-link");
var gang = document.getElementById("gang-tab");
var gangLink = document.getElementById("gang-menu-link");
// Determine whether certain links should show up
job.style.display = Player.companyName !== "" ? "list-item" : "none";
stockmarket.style.display = Player.hasWseAccount ? "list-item" : "none";
bladeburner.style.display = Player.bladeburner instanceof Bladeburner ? "list-item" : "none";
corporation.style.display = Player.corporation instanceof Corporation ? "list-item" : "none";
gang.style.display = Player.inGang() ? "list-item" : "none";
this.classList.toggle("opened");
if (city.style.maxHeight) {
Engine.toggleMainMenuHeader(false,
[city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
);
} else {
Engine.toggleMainMenuHeader(true,
[city, travel, job, stockmarket, bladeburner, corporation, gang],
[cityLink, travelLink, jobLink, stockmarketLink, bladeburnerLink, corporationLink, gangLink]
);
}
}
helpHdr.onclick = function() {
var tutorial = document.getElementById("tutorial-tab");
var tutorialLink = document.getElementById("tutorial-menu-link");
var options = document.getElementById("options-tab");
var optionsLink = document.getElementById("options-menu-link");
this.classList.toggle("opened");
const elems = [tutorial, options];
const links = [tutorialLink, optionsLink];
if (process.env.NODE_ENV === "development") {
elems.push(document.getElementById("dev-tab"));
links.push(document.getElementById("dev-menu-link"));
}
if (tutorial.style.maxHeight) {
Engine.toggleMainMenuHeader(false, elems, links);
} else {
Engine.toggleMainMenuHeader(true, elems, links);
}
}
//Main menu buttons and content
Engine.Clickables.terminalMainMenuButton = clearEventListeners("terminal-menu-link");
Engine.Clickables.terminalMainMenuButton.addEventListener("click", function() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
return false; return false;
}); });
Engine.Clickables.characterMainMenuButton = clearEventListeners("stats-menu-link"); MainMenuLinks.ScriptEditor.addEventListener("click", function() {
Engine.Clickables.characterMainMenuButton.addEventListener("click", function() {
Engine.loadCharacterContent();
return false;
});
Engine.Clickables.scriptEditorMainMenuButton = clearEventListeners("create-script-menu-link");
Engine.Clickables.scriptEditorMainMenuButton.addEventListener("click", function() {
Engine.loadScriptEditorContent(); Engine.loadScriptEditorContent();
return false; return false;
}); });
Engine.Clickables.activeScriptsMainMenuButton = clearEventListeners("active-scripts-menu-link"); MainMenuLinks.ActiveScripts.addEventListener("click", function() {
Engine.Clickables.activeScriptsMainMenuButton.addEventListener("click", function() {
Engine.loadActiveScriptsContent(); Engine.loadActiveScriptsContent();
return false; return false;
}); });
Engine.Clickables.hacknetNodesMainMenuButton = clearEventListeners("hacknet-nodes-menu-link"); MainMenuLinks.CreateProgram.addEventListener("click", function() {
Engine.Clickables.hacknetNodesMainMenuButton.addEventListener("click", function() {
Engine.loadHacknetNodesContent();
return false;
});
Engine.Clickables.worldMainMenuButton = clearEventListeners("city-menu-link");
Engine.Clickables.worldMainMenuButton.addEventListener("click", function() {
Engine.loadWorldContent();
return false;
});
Engine.Clickables.travelMainMenuButton = clearEventListeners("travel-menu-link");
Engine.Clickables.travelMainMenuButton.addEventListener("click", function() {
Engine.loadTravelContent();
Engine.Clickables.travelMainMenuButton.classList.add("active");
return false;
});
Engine.Clickables.jobMainMenuButton = clearEventListeners("job-menu-link");
Engine.Clickables.jobMainMenuButton.addEventListener("click", function() {
Engine.loadJobContent();
return false;
});
Engine.Clickables.stockmarketMainMenuButton = clearEventListeners("stock-market-menu-link");
Engine.Clickables.stockmarketMainMenuButton.addEventListener("click", function() {
Engine.loadStockMarketContent();
Engine.Clickables.stockmarketMainMenuButton.classList.add("active");
return false;
});
Engine.Clickables.createProgramMainMenuButton = clearEventListeners("create-program-menu-link");
Engine.Clickables.createProgramMainMenuButton.addEventListener("click", function() {
Engine.loadCreateProgramContent(); Engine.loadCreateProgramContent();
return false; return false;
}); });
Engine.Clickables.factionsMainMenuButton = clearEventListeners("factions-menu-link"); MainMenuLinks.Stats.addEventListener("click", function() {
Engine.Clickables.factionsMainMenuButton.addEventListener("click", function() { Engine.loadCharacterContent();
return false;
});
MainMenuLinks.Factions.addEventListener("click", function() {
Engine.loadFactionsContent(); Engine.loadFactionsContent();
return false; return false;
}); });
Engine.Clickables.augmentationsMainMenuButton = clearEventListeners("augmentations-menu-link"); MainMenuLinks.Augmentations.addEventListener("click", function() {
Engine.Clickables.augmentationsMainMenuButton.addEventListener("click", function() {
Engine.loadAugmentationsContent(); Engine.loadAugmentationsContent();
return false; return false;
}); });
Engine.Clickables.tutorialMainMenuButton = clearEventListeners("tutorial-menu-link"); MainMenuLinks.HacknetNodes.addEventListener("click", function() {
Engine.Clickables.tutorialMainMenuButton.addEventListener("click", function() { Engine.loadHacknetNodesContent();
Engine.loadTutorialContent();
return false; return false;
}); });
Engine.Clickables.bladeburnerMenuButton = clearEventListeners("bladeburner-menu-link"); MainMenuLinks.City.addEventListener("click", function() {
Engine.Clickables.bladeburnerMenuButton.addEventListener("click", function() { Engine.loadWorldContent();
return false;
});
MainMenuLinks.Travel.addEventListener("click", function() {
Engine.loadTravelContent();
MainMenuLinks.Travel.classList.add("active");
return false;
});
MainMenuLinks.Job.addEventListener("click", function() {
Engine.loadJobContent();
MainMenuLinks.Job.classList.add("active");
return false;
});
MainMenuLinks.StockMarket.addEventListener("click", function() {
Engine.loadStockMarketContent();
MainMenuLinks.StockMarket.classList.add("active");
return false;
});
MainMenuLinks.Bladeburner.addEventListener("click", function() {
Engine.loadBladeburnerContent(); Engine.loadBladeburnerContent();
return false; return false;
}); });
Engine.Clickables.corporationMenuButton = clearEventListeners("corporation-menu-link");
Engine.Clickables.corporationMenuButton.addEventListener("click", function() { MainMenuLinks.Corporation.addEventListener("click", function() {
Engine.loadCorporationContent(); Engine.loadCorporationContent();
Engine.Clickables.corporationMenuButton.classList.add("active"); MainMenuLinks.Corporation.classList.add("active");
return false; return false;
}); });
Engine.Clickables.gangMenuButton = clearEventListeners("gang-menu-link");
Engine.Clickables.gangMenuButton.addEventListener("click", function() { MainMenuLinks.Gang.addEventListener("click", function() {
Engine.loadGangContent(); Engine.loadGangContent();
return false; return false;
}); });
MainMenuLinks.Tutorial.addEventListener("click", function() {
Engine.loadTutorialContent();
return false;
});
Engine.Clickables.devMainMenuButton = clearEventListeners("dev-menu-link"); MainMenuLinks.DevMenu.addEventListener("click", function() {
Engine.Clickables.devMainMenuButton.addEventListener("click", function() {
if (process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {
Engine.loadDevMenuContent(); Engine.loadDevMenuContent();
} }

@ -600,6 +600,9 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<!-- Bladeburner @ NSA --> <!-- Bladeburner @ NSA -->
<a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a> <a id="location-nsa-bladeburner" class="a-link-button">Bladeburner Division</a>
<!-- Re-sleeving @ VitaLife -->
<a id="location-vitalife-resleeve" class="a-link-button">Re-Sleeve</a>
</div> </div>
<div id="infiltration-container" class="generic-menupage-container"> <div id="infiltration-container" class="generic-menupage-container">

152
src/ui/MainMenu/Headers.ts Normal file

@ -0,0 +1,152 @@
// Implement the collapsible main menu headers
import { MainMenuLinks } from "./Links";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IMainMenuHeaders {
Hacking: HTMLElement | null;
Character: HTMLElement | null;
World: HTMLElement | null;
Help: HTMLElement | null;
}
export const MainMenuHeaders: IMainMenuHeaders = {
Hacking: null,
Character: null,
World: null,
Help: null,
}
// Implements collapsible toggle feature when a header is clicked
function toggleHeader(open: boolean, elems: HTMLElement[], links: HTMLElement[]) {
for (var i = 0; i < elems.length; ++i) {
if (open) {
elems[i].style.opacity = "1";
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
} else {
elems[i].style.opacity = "0";
elems[i].style.maxHeight = null;
}
}
for (var i = 0; i < links.length; ++i) {
if (open) {
links[i].style.opacity = "1";
links[i].style.maxHeight = links[i].scrollHeight + "px";
links[i].style.pointerEvents = "auto";
} else {
links[i].style.opacity = "0";
links[i].style.maxHeight = null;
links[i].style.pointerEvents = "none";
}
}
}
export function initializeMainMenuHeaders(p: IPlayer, dev: boolean=false): boolean {
function safeGetElement(id: string): HTMLElement {
const elem: HTMLElement | null = document.getElementById(id);
if (elem == null) {
throw new Error(`Failed to find element with id ${id} in initializeMainMenuHeaders()`);
}
return elem!;
}
try {
// Get references to the DOM elements
MainMenuHeaders.Hacking = safeGetElement("hacking-menu-header");
MainMenuHeaders.Character = safeGetElement("character-menu-header");
MainMenuHeaders.World = safeGetElement("world-menu-header");
MainMenuHeaders.Help = safeGetElement("help-menu-header");
// Set click handlers to turn the headers into collapsibles
MainMenuHeaders.Hacking.onclick = function() {
const terminal: HTMLElement = safeGetElement("terminal-tab");
const createScript: HTMLElement = safeGetElement("create-script-tab");
const activeScripts: HTMLElement = safeGetElement("active-scripts-tab");
const createProgram: HTMLElement = safeGetElement("create-program-tab");
const createProgramNot: HTMLElement = safeGetElement("create-program-notification");
this.classList.toggle("opened");
const elems: HTMLElement[] = [terminal, createScript, activeScripts, createProgram];
const links: HTMLElement[] = [MainMenuLinks.Terminal!, MainMenuLinks.ScriptEditor!, MainMenuLinks.ActiveScripts!, MainMenuLinks.CreateProgram!];
if (terminal.style.maxHeight) {
toggleHeader(false, elems, links);
createProgramNot!.style.display = "none";
} else {
toggleHeader(true, elems, links);
createProgramNot!.style.display = "block"
}
}
MainMenuHeaders.Character.onclick = function() {
const stats: HTMLElement = safeGetElement("stats-tab");
const factions: HTMLElement = safeGetElement("factions-tab");
const augmentations: HTMLElement = safeGetElement("augmentations-tab");
const hacknetnodes: HTMLElement = safeGetElement("hacknet-nodes-tab");
this.classList.toggle("opened");
const elems: HTMLElement[] = [stats, factions, augmentations, hacknetnodes];
const links: HTMLElement[] = [MainMenuLinks.Stats!, MainMenuLinks.Factions!, MainMenuLinks.Augmentations!, MainMenuLinks.HacknetNodes!];
if (stats.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
}
MainMenuHeaders.World.onclick = function() {
const city: HTMLElement = safeGetElement("city-tab");
const travel: HTMLElement = safeGetElement("travel-tab");
const job: HTMLElement = safeGetElement("job-tab");
const stockmarket: HTMLElement = safeGetElement("stock-market-tab");
const bladeburner: HTMLElement = safeGetElement("bladeburner-tab");
const corporation: HTMLElement = safeGetElement("corporation-tab");
const gang: HTMLElement = safeGetElement("gang-tab");
// Determine whether certain links should show up
job.style.display = p.companyName !== "" ? "list-item" : "none";
stockmarket.style.display = p.hasWseAccount ? "list-item" : "none";
bladeburner.style.display = p.inBladeburner() ? "list-item" : "none";
corporation.style.display = p.hasCorporation() ? "list-item" : "none";
gang.style.display = p.inGang() ? "list-item" : "none";
this.classList.toggle("opened");
const elems: HTMLElement[] = [city, travel, job, stockmarket, bladeburner, corporation, gang];
const links: HTMLElement[] = [MainMenuLinks.City!, MainMenuLinks.Travel!, MainMenuLinks.Job!, MainMenuLinks.StockMarket!, MainMenuLinks.Bladeburner!, MainMenuLinks.Corporation!, MainMenuLinks.Gang!];
if (city.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
}
MainMenuHeaders.Help.onclick = function() {
const tutorial: HTMLElement = safeGetElement("tutorial-tab");
const options: HTMLElement = safeGetElement("options-tab");
this.classList.toggle("opened");
const elems: HTMLElement[] = [tutorial, options];
const links: HTMLElement[] = [MainMenuLinks.Tutorial!, MainMenuLinks.Options!];
if (dev) {
elems.push(safeGetElement("dev-tab"));
links.push(safeGetElement("dev-menu-link"));
}
if (tutorial.style.maxHeight) {
toggleHeader(false, elems, links);
} else {
toggleHeader(true, elems, links);
}
}
return true;
} catch(e) {
console.error(`Failed to initialize Main Menu Headers: ${e}`);
return false;
}
}

82
src/ui/MainMenu/Links.ts Normal file

@ -0,0 +1,82 @@
// Get references to the Main Menu link DOM elements
// Does NOT include collapsible headers for the links
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
interface IMainMenuLinks {
Terminal: HTMLElement | null;
ScriptEditor: HTMLElement | null;
ActiveScripts: HTMLElement | null;
CreateProgram: HTMLElement | null;
Stats: HTMLElement | null;
Factions: HTMLElement | null;
Augmentations: HTMLElement | null;
HacknetNodes: HTMLElement | null;
City: HTMLElement | null;
Travel: HTMLElement | null;
Job: HTMLElement | null;
StockMarket: HTMLElement | null;
Bladeburner: HTMLElement | null;
Corporation: HTMLElement | null;
Gang: HTMLElement | null;
Tutorial: HTMLElement | null;
Options: HTMLElement | null;
DevMenu: HTMLElement | null;
}
export const MainMenuLinks: IMainMenuLinks = {
Terminal: null,
ScriptEditor: null,
ActiveScripts: null,
CreateProgram: null,
Stats: null,
Factions: null,
Augmentations: null,
HacknetNodes: null,
City: null,
Travel: null,
Job: null,
StockMarket: null,
Bladeburner: null,
Corporation: null,
Gang: null,
Tutorial: null,
Options: null,
DevMenu: null,
}
export function initializeMainMenuLinks(): boolean {
try {
function safeGetLink(id: string): HTMLElement {
const elem: HTMLElement | null = clearEventListeners(id);
if (elem == null) {
throw new Error(`clearEventListeners() failed for element with id: ${id}`);
}
return elem!;
}
MainMenuLinks.Terminal = safeGetLink("terminal-menu-link");
MainMenuLinks.ScriptEditor = safeGetLink("create-script-menu-link");
MainMenuLinks.ActiveScripts = safeGetLink("active-scripts-menu-link");
MainMenuLinks.CreateProgram = safeGetLink("create-program-menu-link");
MainMenuLinks.Stats = safeGetLink("stats-menu-link");
MainMenuLinks.Factions = safeGetLink("factions-menu-link");
MainMenuLinks.Augmentations = safeGetLink("augmentations-menu-link");
MainMenuLinks.HacknetNodes = safeGetLink("hacknet-nodes-menu-link");
MainMenuLinks.City = safeGetLink("city-menu-link");
MainMenuLinks.Travel = safeGetLink("travel-menu-link");
MainMenuLinks.Job = safeGetLink("job-menu-link");
MainMenuLinks.StockMarket = safeGetLink("stock-market-menu-link");
MainMenuLinks.Bladeburner = safeGetLink("bladeburner-menu-link");
MainMenuLinks.Corporation = safeGetLink("corporation-menu-link");
MainMenuLinks.Gang = safeGetLink("gang-menu-link");
MainMenuLinks.Tutorial = safeGetLink("tutorial-menu-link");
MainMenuLinks.Options = document.getElementById("options-menu-link"); // This click listener is already set, so don't clear it
MainMenuLinks.DevMenu = safeGetLink("dev-menu-link");
return true;
} catch(e) {
console.error(`Failed to initialize Main Menu Links: ${e}`);
return false;
}
}

@ -11,6 +11,7 @@ function Reviver(key, value) {
console.log("Reviver WRONGLY called with key: " + key + ", and value: " + value); console.log("Reviver WRONGLY called with key: " + key + ", and value: " + value);
return 0; return 0;
} }
if (typeof value === "object" && if (typeof value === "object" &&
typeof value.ctor === "string" && typeof value.ctor === "string" &&
typeof value.data !== "undefined") { typeof value.data !== "undefined") {