diff --git a/src/PersonObjects/Resleeving/ResleevingUI.tsx b/src/PersonObjects/Resleeving/ResleevingUI.tsx deleted file mode 100644 index 64ac8e0b1..000000000 --- a/src/PersonObjects/Resleeving/ResleevingUI.tsx +++ /dev/null @@ -1,428 +0,0 @@ -/** - * Module for handling the Re-sleeving UI - */ -import { Resleeve } from "./Resleeve"; -import { generateResleeves, purchaseResleeve } from "./Resleeving"; - -import { IPlayer } from "../IPlayer"; - -import { Augmentation } from "../../Augmentation/Augmentation"; -import { Augmentations } from "../../Augmentation/Augmentations"; - -import { numeralWrapper } from "../../ui/numeralFormat"; -import { Money } from "../../ui/React/Money"; -import { Page, routing } from "../../ui/navigationTracking"; - -import { dialogBoxCreate } from "../../../utils/DialogBox"; - -import { exceptionAlert } from "../../../utils/helpers/exceptionAlert"; - -import { createElement } from "../../../utils/uiHelpers/createElement"; -import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement"; -import { getSelectValue } from "../../../utils/uiHelpers/getSelectData"; -import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement"; -import { removeElement } from "../../../utils/uiHelpers/removeElement"; - -import * as React from "react"; -import { renderToStaticMarkup } from "react-dom/server"; - -interface IResleeveUIElems { - container: HTMLElement | null; - statsPanel: HTMLElement | null; - stats: HTMLElement | null; - multipliersButton: HTMLElement | null; - augPanel: HTMLElement | null; - augSelector: HTMLSelectElement | null; - augDescription: HTMLElement | null; - costPanel: HTMLElement | null; - costText: HTMLElement | null; - buyButton: HTMLElement | null; -} - -interface IPageUIElems { - container: HTMLElement | null; - info: HTMLElement | null; - sortTag: HTMLElement | null; - sortSelector: HTMLSelectElement | null; - resleeveList: HTMLElement | null; - resleeves: IResleeveUIElems[] | null; -} - -const UIElems: IPageUIElems = { - container: null, - info: null, - sortTag: null, - sortSelector: null, - resleeveList: null, - resleeves: null, -}; - -let playerRef: IPlayer | null; - -export function createResleevesPage(p: IPlayer): void { - if (!routing.isOn(Page.Resleeves)) { - return; - } - - try { - playerRef = p; - - UIElems.container = createElement("div", { - class: "generic-menupage-container", - id: "resleeves-container", - position: "fixed", - }); - - UIElems.info = createElement("p", { - display: "block", - innerHTML: - "Re-sleeving is the process of digitizing and transferring your consciousness " + - "into a new human body, or 'sleeve'. Here at VitaLife, you can purchase new " + - "specially-engineered bodies for the re-sleeve process. Many of these bodies " + - "even come with genetic and cybernetic Augmentations!

" + - "Re-sleeving will change your experience for every stat. It will also REMOVE " + - "all of your currently-installed Augmentations, and replace " + - "them with the ones provided by the purchased sleeve. However, Augmentations that you have " + - "purchased but not installed will NOT be removed. If you have purchased an " + - "Augmentation and then re-sleeve into a body which already has that Augmentation, " + - "it will be removed (since you cannot have duplicate Augmentations).

" + - "NOTE: The stats and multipliers displayed on this page do NOT include your bonuses from " + - "Source-File.", - width: "75%", - }); - - // Randomly create all Resleeves if they dont already exist - if (p.resleeves.length === 0) { - p.resleeves = generateResleeves(); - } - - // Create a selector for sorting the list of Resleeves - UIElems.sortTag = createElement("p", { - display: "inline-block", - innerText: "Sort By: ", - }); - UIElems.sortSelector = createElement("select", { - class: "dropdown", - }) as HTMLSelectElement; - - enum SortOption { - Cost = "Cost", - Hacking = "Hacking", - Strength = "Strength", - Defense = "Defense", - Dexterity = "Dexterity", - Agility = "Agility", - Charisma = "Charisma", - AverageCombatStats = "AverageCombat", - AverageAllStats = "AverageAllStats", - TotalNumAugmentations = "TotalNumAugmentations", - } - - UIElems.sortSelector.add(createOptionElement("Cost", SortOption.Cost)); - UIElems.sortSelector.add(createOptionElement("Hacking Level", SortOption.Hacking)); - UIElems.sortSelector.add(createOptionElement("Strength Level", SortOption.Strength)); - UIElems.sortSelector.add(createOptionElement("Defense Level", SortOption.Defense)); - UIElems.sortSelector.add(createOptionElement("Dexterity Level", SortOption.Dexterity)); - UIElems.sortSelector.add(createOptionElement("Agility Level", SortOption.Agility)); - UIElems.sortSelector.add(createOptionElement("Charisma Level", SortOption.Charisma)); - UIElems.sortSelector.add(createOptionElement("Average Combat Stats", SortOption.AverageCombatStats)); - UIElems.sortSelector.add(createOptionElement("Average Stats", SortOption.AverageAllStats)); - UIElems.sortSelector.add(createOptionElement("Number of Augmentations", SortOption.TotalNumAugmentations)); - - UIElems.resleeveList = createElement("ul"); - UIElems.sortSelector.onchange = () => { - removeChildrenFromElement(UIElems.resleeveList); - UIElems.resleeves = []; - - // Helper function for averaging - function getAverage(...values: number[]): number { - let sum = 0; - for (let i = 0; i < values.length; ++i) { - sum += values[i]; - } - - return sum / values.length; - } - - const sortOpt = getSelectValue(UIElems.sortSelector); - switch (sortOpt) { - case SortOption.Hacking: - p.resleeves.sort((a, b) => { - return a.hacking_skill - b.hacking_skill; - }); - break; - case SortOption.Strength: - p.resleeves.sort((a, b) => { - return a.strength - b.strength; - }); - break; - case SortOption.Defense: - p.resleeves.sort((a, b) => { - return a.defense - b.defense; - }); - break; - case SortOption.Dexterity: - p.resleeves.sort((a, b) => { - return a.dexterity - b.dexterity; - }); - break; - case SortOption.Agility: - p.resleeves.sort((a, b) => { - return a.agility - b.agility; - }); - break; - case SortOption.Charisma: - p.resleeves.sort((a, b) => { - return a.charisma - b.charisma; - }); - break; - case SortOption.AverageCombatStats: - p.resleeves.sort((a, b) => { - const aAvg = getAverage(a.strength, a.defense, a.dexterity, a.agility); - const bAvg = getAverage(b.strength, b.defense, b.dexterity, b.agility); - - return aAvg - bAvg; - }); - break; - case SortOption.AverageAllStats: - p.resleeves.sort((a, b) => { - const aAvg = getAverage(a.hacking_skill, a.strength, a.defense, a.dexterity, a.agility, a.charisma); - const bAvg = getAverage(b.hacking_skill, b.strength, b.defense, b.dexterity, b.agility, b.charisma); - - return aAvg - bAvg; - }); - break; - case SortOption.TotalNumAugmentations: - p.resleeves.sort((a, b) => { - return a.augmentations.length - b.augmentations.length; - }); - break; - case SortOption.Cost: - default: - p.resleeves.sort((a, b) => { - return a.getCost() - b.getCost(); - }); - break; - } - - if (UIElems.resleeveList == null) throw new Error("UIElems.resleeveList is null in sortSelector.click()"); - if (UIElems.resleeves == null) throw new Error("UIElems.resleeves is null in sortSelector.click()"); - - // Create UI for all Resleeves - for (const resleeve of p.resleeves) { - const resleeveUi = createResleeveUi(resleeve); - if (resleeveUi.container == null) throw new Error("resleeveUi.container is null in sortSelector.click()"); - UIElems.resleeveList.appendChild(resleeveUi.container); - UIElems.resleeves.push(resleeveUi); - } - }; - UIElems.sortSelector.dispatchEvent(new Event("change")); // Force onchange event - - UIElems.container.appendChild(UIElems.info); - UIElems.container.appendChild(createElement("br")); - UIElems.container.appendChild(UIElems.sortTag); - UIElems.container.appendChild(UIElems.sortSelector); - UIElems.container.appendChild(UIElems.resleeveList); - - const container = document.getElementById("entire-game-container"); - if (container == null) throw new Error("Could not find entire-game-container in createResleevesPage()"); - container.appendChild(UIElems.container); - } catch (e) { - exceptionAlert(e); - } -} - -export function clearResleevesPage(): void { - if (UIElems.container instanceof HTMLElement) { - removeElement(UIElems.container); - } - - for (const prop in UIElems) { - (UIElems as any)[prop] = null; - } - - playerRef = null; -} - -function createResleeveUi(resleeve: Resleeve): IResleeveUIElems { - const elems: IResleeveUIElems = { - container: null, - statsPanel: null, - stats: null, - multipliersButton: null, - augPanel: null, - augSelector: null, - augDescription: null, - costPanel: null, - costText: null, - buyButton: null, - }; - if (playerRef === null) return elems; - - if (!routing.isOn(Page.Resleeves)) { - return elems; - } - - elems.container = createElement("div", { - class: "resleeve-container", - display: "block", - }); - - elems.statsPanel = createElement("div", { - class: "resleeve-panel", - width: "30%", - }); - elems.stats = createElement("p", { - class: "resleeve-stats-text", - innerHTML: - `Hacking: ${numeralWrapper.formatSkill(resleeve.hacking_skill)} (${numeralWrapper.formatExp( - resleeve.hacking_exp, - )} exp)
` + - `Strength: ${numeralWrapper.formatSkill(resleeve.strength)} (${numeralWrapper.formatExp( - resleeve.strength_exp, - )} exp)
` + - `Defense: ${numeralWrapper.formatSkill(resleeve.defense)} (${numeralWrapper.formatExp( - resleeve.defense_exp, - )} exp)
` + - `Dexterity: ${numeralWrapper.formatSkill(resleeve.dexterity)} (${numeralWrapper.formatExp( - resleeve.dexterity_exp, - )} exp)
` + - `Agility: ${numeralWrapper.formatSkill(resleeve.agility)} (${numeralWrapper.formatExp( - resleeve.agility_exp, - )} exp)
` + - `Charisma: ${numeralWrapper.formatSkill(resleeve.charisma)} (${numeralWrapper.formatExp( - resleeve.charisma_exp, - )} exp)
` + - `# Augmentations: ${resleeve.augmentations.length}`, - }); - elems.multipliersButton = createElement("button", { - class: "std-button", - innerText: "Multipliers", - clickListener: () => { - dialogBoxCreate( - [ - "

Total Multipliers:

", - `Hacking Level multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_mult)}`, - `Hacking Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_exp_mult)}`, - `Strength Level multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_mult)}`, - `Strength Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.strength_exp_mult)}`, - `Defense Level multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_mult)}`, - `Defense Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.defense_exp_mult)}`, - `Dexterity Level multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_mult)}`, - `Dexterity Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.dexterity_exp_mult)}`, - `Agility Level multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_mult)}`, - `Agility Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.agility_exp_mult)}`, - `Charisma Level multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_mult)}`, - `Charisma Experience multiplier: ${numeralWrapper.formatPercentage(resleeve.charisma_exp_mult)}`, - `Hacking Chance multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_chance_mult)}`, - `Hacking Speed multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_speed_mult)}`, - `Hacking Money multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_money_mult)}`, - `Hacking Growth multiplier: ${numeralWrapper.formatPercentage(resleeve.hacking_grow_mult)}`, - `Salary multiplier: ${numeralWrapper.formatPercentage(resleeve.work_money_mult)}`, - `Company Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.company_rep_mult)}`, - `Faction Reputation Gain multiplier: ${numeralWrapper.formatPercentage(resleeve.faction_rep_mult)}`, - `Crime Money multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_money_mult)}`, - `Crime Success multiplier: ${numeralWrapper.formatPercentage(resleeve.crime_success_mult)}`, - `Hacknet Income multiplier: ${numeralWrapper.formatPercentage(resleeve.hacknet_node_money_mult)}`, - `Hacknet Purchase Cost multiplier: ${numeralWrapper.formatPercentage( - resleeve.hacknet_node_purchase_cost_mult, - )}`, - `Hacknet Level Upgrade Cost multiplier: ${numeralWrapper.formatPercentage( - resleeve.hacknet_node_level_cost_mult, - )}`, - `Hacknet Ram Upgrade Cost multiplier: ${numeralWrapper.formatPercentage( - resleeve.hacknet_node_ram_cost_mult, - )}`, - `Hacknet Core Upgrade Cost multiplier: ${numeralWrapper.formatPercentage( - resleeve.hacknet_node_core_cost_mult, - )}`, - `Bladeburner Max Stamina multiplier: ${numeralWrapper.formatPercentage( - resleeve.bladeburner_max_stamina_mult, - )}`, - `Bladeburner Stamina Gain multiplier: ${numeralWrapper.formatPercentage( - resleeve.bladeburner_stamina_gain_mult, - )}`, - `Bladeburner Field Analysis multiplier: ${numeralWrapper.formatPercentage( - resleeve.bladeburner_analysis_mult, - )}`, - `Bladeburner Success Chance multiplier: ${numeralWrapper.formatPercentage( - resleeve.bladeburner_success_chance_mult, - )}`, - ].join("
"), - false, - ); - }, - }); - elems.statsPanel.appendChild(elems.stats); - elems.statsPanel.appendChild(elems.multipliersButton); - - elems.augPanel = createElement("div", { - class: "resleeve-panel", - width: "50%", - }); - elems.augSelector = createElement("select", { - class: "resleeve-aug-selector dropdown", - }) as HTMLSelectElement; - elems.augDescription = createElement("p"); - for (let i = 0; i < resleeve.augmentations.length; ++i) { - elems.augSelector.add(createOptionElement(resleeve.augmentations[i].name)); - } - elems.augSelector.addEventListener("change", () => { - updateAugDescription(elems); - }); - elems.augSelector.dispatchEvent(new Event("change")); // Set inital description by manually triggering change event - elems.augPanel.appendChild(elems.augSelector); - elems.augPanel.appendChild(elems.augDescription); - - const cost: number = resleeve.getCost(); - elems.costPanel = createElement("div", { - class: "resleeve-panel", - width: "20%", - }); - elems.costText = createElement("p", { - innerHTML: - `It costs ${renderToStaticMarkup()} ` + `to purchase this Sleeve.`, - }); - elems.buyButton = createElement("button", { - class: "std-button", - innerText: "Purchase", - clickListener: () => { - if (playerRef == null) throw new Error("playerRef is null in buyButton.click()"); - if (purchaseResleeve(resleeve, playerRef)) { - dialogBoxCreate( - <> - You re-sleeved for ! - , - false, - ); - } else { - dialogBoxCreate(`You cannot afford to re-sleeve into this body`, false); - } - }, - }); - elems.costPanel.appendChild(elems.costText); - elems.costPanel.appendChild(elems.buyButton); - - elems.container.appendChild(elems.statsPanel); - elems.container.appendChild(elems.augPanel); - elems.container.appendChild(elems.costPanel); - - return elems; -} - -function updateAugDescription(elems: IResleeveUIElems): void { - if (elems.augDescription == null) throw new Error("elems.augDescription is null in updateAugDescription()"); - const augName: string = getSelectValue(elems.augSelector); - const aug: Augmentation | null = Augmentations[augName]; - if (aug == null) { - console.warn(`Could not find Augmentation with name ${augName}`); - return; - } - - let innerHTML = aug.info; - if (typeof innerHTML !== "string") { - innerHTML = renderToStaticMarkup(innerHTML); - } - - elems.augDescription.innerHTML = innerHTML; -} diff --git a/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx b/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx index 4ae70ce01..e651af12f 100644 --- a/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx +++ b/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { IPlayer } from "../../IPlayer"; import { Resleeve } from "../Resleeve"; import { Augmentations } from "../../../Augmentation/Augmentations"; -import { generateResleeves, purchaseResleeve } from "../Resleeving"; +import { purchaseResleeve } from "../Resleeving"; import { Money } from "../../../ui/React/Money"; import { numeralWrapper } from "../../../ui/numeralFormat"; diff --git a/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx b/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx index 5a7a753bf..404f7bf29 100644 --- a/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx +++ b/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { IPlayer } from "../../IPlayer"; -import { generateResleeves, purchaseResleeve } from "../Resleeving"; +import { generateResleeves } from "../Resleeving"; import { Resleeve } from "../Resleeve"; import { ResleeveElem } from "./ResleeveElem"; @@ -60,11 +60,9 @@ const SortFunctions: { Dexterity: (a: Resleeve, b: Resleeve): number => a.dexterity - b.dexterity, Agility: (a: Resleeve, b: Resleeve): number => a.agility - b.agility, Charisma: (a: Resleeve, b: Resleeve): number => a.charisma - b.charisma, - AverageCombatStats: (a: Resleeve, b: Resleeve): number => - getAverage(a.strength, a.defense, a.dexterity, a.agility) - + AverageCombatStats: (a: Resleeve, b: Resleeve): number => getAverage(a.strength, a.defense, a.dexterity, a.agility) - getAverage(b.strength, b.defense, b.dexterity, b.agility), - AverageAllStats: (a: Resleeve, b: Resleeve): number => - getAverage(a.hacking_skill, a.strength, a.defense, a.dexterity, a.agility, a.charisma) - + AverageAllStats: (a: Resleeve, b: Resleeve): number => getAverage(a.hacking_skill, a.strength, a.defense, a.dexterity, a.agility, a.charisma) - getAverage(b.hacking_skill, b.strength, b.defense, b.dexterity, b.agility, b.charisma), TotalNumAugmentations: (a: Resleeve, b: Resleeve): number => a.augmentations.length - b.augmentations.length, }; diff --git a/src/PersonObjects/Sleeve/SleeveUI.tsx b/src/PersonObjects/Sleeve/SleeveUI.tsx index 85d5af344..70ed0b2f5 100644 --- a/src/PersonObjects/Sleeve/SleeveUI.tsx +++ b/src/PersonObjects/Sleeve/SleeveUI.tsx @@ -2,22 +2,18 @@ * Module for handling the Sleeve UI */ import React from "react"; -import { createSleevePurchaseAugsPopup } from "./SleeveAugmentationsUI"; import { Sleeve } from "./Sleeve"; import { SleeveTaskType } from "./SleeveTaskTypesEnum"; import { SleeveFaq } from "./data/SleeveFaq"; import { IPlayer } from "../IPlayer"; -import { CONSTANTS } from "../../Constants"; - import { Faction } from "../../Faction/Faction"; import { Factions } from "../../Faction/Factions"; import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum"; import { Crime } from "../../Crime/Crime"; import { Crimes } from "../../Crime/Crimes"; -import { Cities } from "../../Locations/Cities"; import { CityName } from "../../Locations/data/CityNames"; import { LocationName } from "../../Locations/data/LocationNames"; @@ -32,13 +28,13 @@ import { exceptionAlert } from "../../../utils/helpers/exceptionAlert"; import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners"; import { createElement } from "../../../utils/uiHelpers/createElement"; import { createOptionElement } from "../../../utils/uiHelpers/createOptionElement"; -import { createPopup } from "../../../utils/uiHelpers/createPopup"; -import { createPopupCloseButton } from "../../../utils/uiHelpers/createPopupCloseButton"; +import { createPopup } from "../../ui/React/createPopup"; import { getSelectValue } from "../../../utils/uiHelpers/getSelectData"; import { removeChildrenFromElement } from "../../../utils/uiHelpers/removeChildrenFromElement"; import { removeElement } from "../../../utils/uiHelpers/removeElement"; -import { removeElementById } from "../../../utils/uiHelpers/removeElementById"; +import { SleeveAugmentationsPopup } from "./ui/SleeveAugmentationsPopup"; +import { TravelPopup } from "./ui/TravelPopup"; import { EarningsTableElement } from "./ui/EarningsTableElement"; import { Money } from "../../ui/React/Money"; import { MoneyRate } from "../../ui/React/MoneyRate"; @@ -47,7 +43,6 @@ import { StatsElement } from "./ui/StatsElement"; import { MoreStatsContent } from "./ui/MoreStatsContent"; import { MoreEarningsContent } from "./ui/MoreEarningsContent"; import * as ReactDOM from "react-dom"; -import { renderToStaticMarkup } from "react-dom/server"; // Object that keeps track of all DOM elements for the UI for a single Sleeve interface ISleeveUIElems { @@ -226,59 +221,20 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems { class: "std-button", innerText: "More Stats", clickListener: () => { - dialogBoxCreate(MoreStatsContent(sleeve)); + dialogBoxCreate(); }, }); elems.travelButton = createElement("button", { class: "std-button", innerText: "Travel", clickListener: () => { - if (playerRef === null) return; + if (playerRef == null) throw new Error("playerRef is null in purchaseAugsButton.click()"); const popupId = "sleeve-travel-popup"; - const popupArguments: HTMLElement[] = []; - popupArguments.push(createPopupCloseButton(popupId, { class: "std-button" })); - popupArguments.push( - createElement("p", { - innerHTML: - "Have this sleeve travel to a different city. This affects " + - "the gyms and universities at which this sleeve can study. " + - `Traveling to a different city costs ${renderToStaticMarkup( - , - )}. ` + - "It will also CANCEL the sleeve's current task (setting it to idle)", - }), - ); - for (const cityName in Cities) { - if (sleeve.city === cityName) { - continue; - } - (function (sleeve, cityName) { - popupArguments.push( - createElement("div", { - // Reusing this css class. It adds a border and makes it so that - // the background color changes when you hover - class: "cmpy-mgmt-find-employee-option", - innerText: cityName, - clickListener: () => { - if (playerRef == null) throw new Error("playerRef is null in popupArguments.click()"); - if (!playerRef.canAfford(CONSTANTS.TravelCost)) { - dialogBoxCreate("You cannot afford to have this sleeve travel to another city", false); - return false; - } - sleeve.city = cityName as CityName; - playerRef.loseMoney(CONSTANTS.TravelCost); - sleeve.resetTaskStatus(); - removeElementById(popupId); - updateSleeveUi(sleeve, elems); - updateSleeveTaskSelector(sleeve, elems, allSleeves); - return false; - }, - }), - ); - })(sleeve, cityName); - } - - createPopup(popupId, popupArguments); + createPopup(popupId, TravelPopup, { + popupId: popupId, + sleeve: sleeve, + player: playerRef, + }); }, }); elems.purchaseAugsButton = createElement("button", { @@ -287,7 +243,11 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems { innerText: "Manage Augmentations", clickListener: () => { if (playerRef == null) throw new Error("playerRef is null in purchaseAugsButton.click()"); - createSleevePurchaseAugsPopup(sleeve, playerRef); + const popupId = "sleeve-augmentation-popup"; + createPopup(popupId, SleeveAugmentationsPopup, { + sleeve: sleeve, + player: playerRef, + }); }, }); elems.statsPanel.appendChild(elems.stats); @@ -350,7 +310,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems { class: "std-button", innerText: "More Earnings Info", clickListener: () => { - dialogBoxCreate(MoreEarningsContent(sleeve)); + dialogBoxCreate(); }, }); diff --git a/src/PersonObjects/Sleeve/ui/MoreEarningsContent.tsx b/src/PersonObjects/Sleeve/ui/MoreEarningsContent.tsx index 7f1d62572..87f8a73b5 100644 --- a/src/PersonObjects/Sleeve/ui/MoreEarningsContent.tsx +++ b/src/PersonObjects/Sleeve/ui/MoreEarningsContent.tsx @@ -4,44 +4,48 @@ import { Money } from "../../../ui/React/Money"; import * as React from "react"; import { StatsTable } from "../../../ui/React/StatsTable"; -export function MoreEarningsContent(sleeve: Sleeve): React.ReactElement { +interface IProps { + sleeve: Sleeve; +} + +export function MoreEarningsContent(props: IProps): React.ReactElement { return ( <> {StatsTable( [ - ["Money ", ], - ["Hacking Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.hack)], - ["Strength Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.str)], - ["Defense Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.def)], - ["Dexterity Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.dex)], - ["Agility Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.agi)], - ["Charisma Exp ", numeralWrapper.formatExp(sleeve.earningsForTask.cha)], + ["Money ", ], + ["Hacking Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.hack)], + ["Strength Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.str)], + ["Defense Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.def)], + ["Dexterity Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.dex)], + ["Agility Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.agi)], + ["Charisma Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.cha)], ], "Earnings for Current Task:", )}
{StatsTable( [ - ["Money: ", ], - ["Hacking Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.hack)], - ["Strength Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.str)], - ["Defense Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.def)], - ["Dexterity Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.dex)], - ["Agility Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.agi)], - ["Charisma Exp: ", numeralWrapper.formatExp(sleeve.earningsForPlayer.cha)], + ["Money: ", ], + ["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.hack)], + ["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.str)], + ["Defense Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.def)], + ["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.dex)], + ["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.agi)], + ["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.cha)], ], "Total Earnings for Host Consciousness:", )}
{StatsTable( [ - ["Money: ", ], - ["Hacking Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.hack)], - ["Strength Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.str)], - ["Defense Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.def)], - ["Dexterity Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.dex)], - ["Agility Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.agi)], - ["Charisma Exp: ", numeralWrapper.formatExp(sleeve.earningsForSleeves.cha)], + ["Money: ", ], + ["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.hack)], + ["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.str)], + ["Defense Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.def)], + ["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.dex)], + ["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.agi)], + ["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.cha)], ], "Total Earnings for Other Sleeves:", )} diff --git a/src/PersonObjects/Sleeve/ui/MoreStatsContent.tsx b/src/PersonObjects/Sleeve/ui/MoreStatsContent.tsx index d0aeedab3..0ed3f8248 100644 --- a/src/PersonObjects/Sleeve/ui/MoreStatsContent.tsx +++ b/src/PersonObjects/Sleeve/ui/MoreStatsContent.tsx @@ -3,40 +3,44 @@ import { numeralWrapper } from "../../../ui/numeralFormat"; import { StatsTable } from "../../../ui/React/StatsTable"; import * as React from "react"; -export function MoreStatsContent(sleeve: Sleeve): React.ReactElement { +interface IProps { + sleeve: Sleeve; +} + +export function MoreStatsContent(props: IProps): React.ReactElement { return ( <> {StatsTable( [ - ["Hacking: ", sleeve.hacking_skill, `(${numeralWrapper.formatExp(sleeve.hacking_exp)} exp)`], - ["Strength: ", sleeve.strength, `(${numeralWrapper.formatExp(sleeve.strength_exp)} exp)`], - ["Defense: ", sleeve.defense, `(${numeralWrapper.formatExp(sleeve.defense_exp)} exp)`], - ["Dexterity: ", sleeve.dexterity, `(${numeralWrapper.formatExp(sleeve.dexterity_exp)} exp)`], - ["Agility: ", sleeve.agility, `(${numeralWrapper.formatExp(sleeve.agility_exp)} exp)`], - ["Charisma: ", sleeve.charisma, `(${numeralWrapper.formatExp(sleeve.charisma_exp)} exp)`], + ["Hacking: ", props.sleeve.hacking_skill, `(${numeralWrapper.formatExp(props.sleeve.hacking_exp)} exp)`], + ["Strength: ", props.sleeve.strength, `(${numeralWrapper.formatExp(props.sleeve.strength_exp)} exp)`], + ["Defense: ", props.sleeve.defense, `(${numeralWrapper.formatExp(props.sleeve.defense_exp)} exp)`], + ["Dexterity: ", props.sleeve.dexterity, `(${numeralWrapper.formatExp(props.sleeve.dexterity_exp)} exp)`], + ["Agility: ", props.sleeve.agility, `(${numeralWrapper.formatExp(props.sleeve.agility_exp)} exp)`], + ["Charisma: ", props.sleeve.charisma, `(${numeralWrapper.formatExp(props.sleeve.charisma_exp)} exp)`], ], "Stats:", )}
{StatsTable( [ - ["Hacking Level multiplier: ", numeralWrapper.formatPercentage(sleeve.hacking_mult)], - ["Hacking Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.hacking_exp_mult)], - ["Strength Level multiplier: ", numeralWrapper.formatPercentage(sleeve.strength_mult)], - ["Strength Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.strength_exp_mult)], - ["Defense Level multiplier: ", numeralWrapper.formatPercentage(sleeve.defense_mult)], - ["Defense Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.defense_exp_mult)], - ["Dexterity Level multiplier: ", numeralWrapper.formatPercentage(sleeve.dexterity_mult)], - ["Dexterity Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.dexterity_exp_mult)], - ["Agility Level multiplier: ", numeralWrapper.formatPercentage(sleeve.agility_mult)], - ["Agility Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.agility_exp_mult)], - ["Charisma Level multiplier: ", numeralWrapper.formatPercentage(sleeve.charisma_mult)], - ["Charisma Experience multiplier: ", numeralWrapper.formatPercentage(sleeve.charisma_exp_mult)], - ["Faction Reputation Gain multiplier: ", numeralWrapper.formatPercentage(sleeve.faction_rep_mult)], - ["Company Reputation Gain multiplier: ", numeralWrapper.formatPercentage(sleeve.company_rep_mult)], - ["Salary multiplier: ", numeralWrapper.formatPercentage(sleeve.work_money_mult)], - ["Crime Money multiplier: ", numeralWrapper.formatPercentage(sleeve.crime_money_mult)], - ["Crime Success multiplier: ", numeralWrapper.formatPercentage(sleeve.crime_success_mult)], + ["Hacking Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.hacking_mult)], + ["Hacking Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.hacking_exp_mult)], + ["Strength Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.strength_mult)], + ["Strength Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.strength_exp_mult)], + ["Defense Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.defense_mult)], + ["Defense Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.defense_exp_mult)], + ["Dexterity Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.dexterity_mult)], + ["Dexterity Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.dexterity_exp_mult)], + ["Agility Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.agility_mult)], + ["Agility Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.agility_exp_mult)], + ["Charisma Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.charisma_mult)], + ["Charisma Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.charisma_exp_mult)], + ["Faction Reputation Gain multiplier: ", numeralWrapper.formatPercentage(props.sleeve.faction_rep_mult)], + ["Company Reputation Gain multiplier: ", numeralWrapper.formatPercentage(props.sleeve.company_rep_mult)], + ["Salary multiplier: ", numeralWrapper.formatPercentage(props.sleeve.work_money_mult)], + ["Crime Money multiplier: ", numeralWrapper.formatPercentage(props.sleeve.crime_money_mult)], + ["Crime Success multiplier: ", numeralWrapper.formatPercentage(props.sleeve.crime_success_mult)], ], "Multipliers:", )} diff --git a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx new file mode 100644 index 000000000..c5e6cd4e9 --- /dev/null +++ b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from "react"; +import { Sleeve } from "../Sleeve"; +import { findSleevePurchasableAugs } from "../SleeveHelpers"; +import { Augmentations } from "../../../Augmentation/Augmentations"; +import { Augmentation } from "../../../Augmentation/Augmentation"; +import { IPlayer } from "../../IPlayer"; +import { Money } from "../../../ui/React/Money"; +import { renderToStaticMarkup } from "react-dom/server"; + +interface IProps { + sleeve: Sleeve; + player: IPlayer; +} + +export function SleeveAugmentationsPopup(props: IProps): React.ReactElement { + const setRerender = useState(false)[1]; + function rerender(): void { + setRerender((old) => !old); + } + + useEffect(() => { + const id = setInterval(rerender, 150); + return () => clearInterval(id); + }, []); + + // Array of all owned Augmentations. Names only + const ownedAugNames = props.sleeve.augmentations.map((e) => e.name); + + // You can only purchase Augmentations that are actually available from + // your factions. I.e. you must be in a faction that has the Augmentation + // and you must also have enough rep in that faction in order to purchase it. + const availableAugs = findSleevePurchasableAugs(props.sleeve, props.player); + + function purchaseAugmentation(aug: Augmentation): void { + props.sleeve.tryBuyAugmentation(props.player, aug); + rerender(); + } + + return ( +
+

Owned Augmentations:

+
+ {ownedAugNames.map((augName) => { + const aug = Augmentations[augName]; + let tooltip = aug.info; + if (typeof tooltip !== "string") { + tooltip = renderToStaticMarkup(tooltip); + } + tooltip += "

"; + tooltip += renderToStaticMarkup(aug.stats); + return ( +
+ {augName} + +
+ ); + })} +
+

+ You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they + would for you. You can only purchase Augmentations that you have unlocked through Factions. +
+
+ When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the + Duplicate Sleeve will immediately lose all of its stat experience. +

+ {availableAugs.map((aug) => { + let info = aug.info; + if (typeof info !== "string") { + info = renderToStaticMarkup(info); + } + info += "

"; + info += renderToStaticMarkup(aug.stats); + + return ( +
purchaseAugmentation(aug)}> +
+

{aug.name}

+
+ Cost: +
+
+ +
+
+ ); + })} +
+ ); +} diff --git a/src/PersonObjects/Sleeve/ui/TravelPopup.tsx b/src/PersonObjects/Sleeve/ui/TravelPopup.tsx new file mode 100644 index 000000000..22620104b --- /dev/null +++ b/src/PersonObjects/Sleeve/ui/TravelPopup.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Sleeve } from "../Sleeve"; +import { IPlayer } from "../../IPlayer"; +import { CONSTANTS } from "../../../Constants"; +import { Cities } from "../../../Locations/Cities"; +import { removePopup } from "../../../ui/React/createPopup"; +import { Money } from "../../../ui/React/Money"; +import { CityName } from "../../../Locations/data/CityNames"; +import { dialogBoxCreate } from "../../../../utils/DialogBox"; + +interface IProps { + popupId: string; + sleeve: Sleeve; + player: IPlayer; +} + +export function TravelPopup(props: IProps): React.ReactElement { + function travel(city: string): void { + if (!props.player.canAfford(CONSTANTS.TravelCost)) { + dialogBoxCreate("You cannot afford to have this sleeve travel to another city"); + } + props.sleeve.city = city as CityName; + props.player.loseMoney(CONSTANTS.TravelCost); + props.sleeve.resetTaskStatus(); + removePopup(props.popupId); + } + + return ( + <> +

+ Have this sleeve travel to a different city. This affects the gyms and universities at which this sleeve can + study. Traveling to a different city costs . It will + also set your current sleeve task to idle. +

+ {Object.keys(Cities) + .filter((city: string) => props.sleeve.city !== city) + .map((city: string) => ( +
travel(city)}> + {city} +
+ ))} + + ); +} diff --git a/src/engine.jsx b/src/engine.jsx index c28fc9dfa..904853c15 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -58,7 +58,6 @@ import { displayMilestonesContent } from "./Milestones/MilestoneHelpers"; import { Terminal, postNetburnerText } from "./Terminal"; import { Sleeve } from "./PersonObjects/Sleeve/Sleeve"; import { clearSleevesPage, createSleevesPage, updateSleevesPage } from "./PersonObjects/Sleeve/SleeveUI"; -import { clearResleevesPage, createResleevesPage } from "./PersonObjects/Resleeving/ResleevingUI"; import { createStatusText } from "./ui/createStatusText"; import { CharacterInfo } from "./ui/CharacterInfo";