diff --git a/css/resleeving.scss b/css/resleeving.scss index 81c83be69..3320bbb23 100644 --- a/css/resleeving.scss +++ b/css/resleeving.scss @@ -3,7 +3,12 @@ */ @import "theme"; -.resleeve-container { +#resleeve-container { + position: fixed; + padding: 6px; +} + +.resleeve-elem { border: 1px solid white; margin: 4px; width: 75%; diff --git a/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx b/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx new file mode 100644 index 000000000..4ae70ce01 --- /dev/null +++ b/src/PersonObjects/Resleeving/ui/ResleeveElem.tsx @@ -0,0 +1,159 @@ +import React, { useState } from "react"; +import { IPlayer } from "../../IPlayer"; +import { Resleeve } from "../Resleeve"; +import { Augmentations } from "../../../Augmentation/Augmentations"; +import { generateResleeves, purchaseResleeve } from "../Resleeving"; +import { Money } from "../../../ui/React/Money"; + +import { numeralWrapper } from "../../../ui/numeralFormat"; +import { dialogBoxCreate } from "../../../../utils/DialogBox"; + +interface IProps { + resleeve: Resleeve; + player: IPlayer; +} + +export function ResleeveElem(props: IProps): React.ReactElement { + const [aug, setAug] = useState(props.resleeve.augmentations[0].name); + + function openStats(): void { + dialogBoxCreate( + <> +

+ Total Multipliers: +

+ Hacking Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_mult)} +
+ Hacking Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_exp_mult)} +
+ Strength Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.strength_mult)} +
+ Strength Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.strength_exp_mult)} +
+ Defense Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.defense_mult)} +
+ Defense Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.defense_exp_mult)} +
+ Dexterity Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.dexterity_mult)} +
+ Dexterity Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.dexterity_exp_mult)} +
+ Agility Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.agility_mult)} +
+ Agility Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.agility_exp_mult)} +
+ Charisma Level multiplier: {numeralWrapper.formatPercentage(props.resleeve.charisma_mult)} +
+ Charisma Experience multiplier: {numeralWrapper.formatPercentage(props.resleeve.charisma_exp_mult)} +
+ Hacking Chance multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_chance_mult)} +
+ Hacking Speed multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_speed_mult)} +
+ Hacking Money multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_money_mult)} +
+ Hacking Growth multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacking_grow_mult)} +
+ Salary multiplier: {numeralWrapper.formatPercentage(props.resleeve.work_money_mult)} +
+ Company Reputation Gain multiplier: {numeralWrapper.formatPercentage(props.resleeve.company_rep_mult)} +
+ Faction Reputation Gain multiplier: {numeralWrapper.formatPercentage(props.resleeve.faction_rep_mult)} +
+ Crime Money multiplier: {numeralWrapper.formatPercentage(props.resleeve.crime_money_mult)} +
+ Crime Success multiplier: {numeralWrapper.formatPercentage(props.resleeve.crime_success_mult)} +
+ Hacknet Income multiplier: {numeralWrapper.formatPercentage(props.resleeve.hacknet_node_money_mult)} +
+ Hacknet Purchase Cost multiplier: + {numeralWrapper.formatPercentage(props.resleeve.hacknet_node_purchase_cost_mult)} +
+ Hacknet Level Upgrade Cost multiplier: + {numeralWrapper.formatPercentage(props.resleeve.hacknet_node_level_cost_mult)} +
+ Hacknet Ram Upgrade Cost multiplier: + {numeralWrapper.formatPercentage(props.resleeve.hacknet_node_ram_cost_mult)} +
+ Hacknet Core Upgrade Cost multiplier: + {numeralWrapper.formatPercentage(props.resleeve.hacknet_node_core_cost_mult)} +
+ Bladeburner Max Stamina multiplier: + {numeralWrapper.formatPercentage(props.resleeve.bladeburner_max_stamina_mult)} +
+ Bladeburner Stamina Gain multiplier: + {numeralWrapper.formatPercentage(props.resleeve.bladeburner_stamina_gain_mult)} +
+ Bladeburner Field Analysis multiplier: + {numeralWrapper.formatPercentage(props.resleeve.bladeburner_analysis_mult)} +
+ Bladeburner Success Chance multiplier: + {numeralWrapper.formatPercentage(props.resleeve.bladeburner_success_chance_mult)} + , + ); + } + + function onAugChange(event: React.ChangeEvent): void { + setAug(event.target.value); + } + + const currentAug = Augmentations[aug]; + const cost = props.resleeve.getCost(); + + function purchase(): void { + if (!purchaseResleeve(props.resleeve, props.player)) return; + dialogBoxCreate( + <> + You re-sleeved for ! + , + ); + } + + return ( +
+
+

+ Hacking: {numeralWrapper.formatSkill(props.resleeve.hacking_skill)} ( + {numeralWrapper.formatExp(props.resleeve.hacking_exp)} exp) +
+ Strength: {numeralWrapper.formatSkill(props.resleeve.strength)} ( + {numeralWrapper.formatExp(props.resleeve.strength_exp)} exp) +
+ Defense: {numeralWrapper.formatSkill(props.resleeve.defense)} ( + {numeralWrapper.formatExp(props.resleeve.defense_exp)} exp) +
+ Dexterity: {numeralWrapper.formatSkill(props.resleeve.dexterity)} ( + {numeralWrapper.formatExp(props.resleeve.dexterity_exp)} exp) +
+ Agility: {numeralWrapper.formatSkill(props.resleeve.agility)} ( + {numeralWrapper.formatExp(props.resleeve.agility_exp)} exp) +
+ Charisma: {numeralWrapper.formatSkill(props.resleeve.charisma)} ( + {numeralWrapper.formatExp(props.resleeve.charisma_exp)} exp) +
# Augmentations: {props.resleeve.augmentations.length} +

+ +
+
+ +

{currentAug !== undefined && currentAug.info}

+
+
+

+ It costs to purchase this Sleeve. +

+ +
+
+ ); +} diff --git a/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx b/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx new file mode 100644 index 000000000..5a7a753bf --- /dev/null +++ b/src/PersonObjects/Resleeving/ui/ResleeveRoot.tsx @@ -0,0 +1,121 @@ +import React, { useState } from "react"; + +import { IPlayer } from "../../IPlayer"; +import { generateResleeves, purchaseResleeve } from "../Resleeving"; +import { Resleeve } from "../Resleeve"; +import { ResleeveElem } from "./ResleeveElem"; + +const SortOption: { + [key: string]: string | undefined; + Cost: string; + Hacking: string; + Strength: string; + Defense: string; + Dexterity: string; + Agility: string; + Charisma: string; + AverageCombatStats: string; + AverageAllStats: string; + TotalNumAugmentations: string; +} = { + Cost: "Cost", + Hacking: "Hacking Level", + Strength: "Strength Level", + Defense: "Defense Level", + Dexterity: "Dexterity Level", + Agility: "Agility Level", + Charisma: "Charisma Level", + AverageCombatStats: "Average Combat Stats", + AverageAllStats: "Average Stats", + TotalNumAugmentations: "Number of Augmentations", +}; + +// 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 SortFunctions: { + [key: string]: ((a: Resleeve, b: Resleeve) => number) | undefined; + Cost: (a: Resleeve, b: Resleeve) => number; + Hacking: (a: Resleeve, b: Resleeve) => number; + Strength: (a: Resleeve, b: Resleeve) => number; + Defense: (a: Resleeve, b: Resleeve) => number; + Dexterity: (a: Resleeve, b: Resleeve) => number; + Agility: (a: Resleeve, b: Resleeve) => number; + Charisma: (a: Resleeve, b: Resleeve) => number; + AverageCombatStats: (a: Resleeve, b: Resleeve) => number; + AverageAllStats: (a: Resleeve, b: Resleeve) => number; + TotalNumAugmentations: (a: Resleeve, b: Resleeve) => number; +} = { + Cost: (a: Resleeve, b: Resleeve): number => a.getCost() - b.getCost(), + Hacking: (a: Resleeve, b: Resleeve): number => a.hacking_skill - b.hacking_skill, + Strength: (a: Resleeve, b: Resleeve): number => a.strength - b.strength, + Defense: (a: Resleeve, b: Resleeve): number => a.defense - b.defense, + 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) - + 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) - + 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, +}; + +interface IProps { + player: IPlayer; +} + +export function ResleeveRoot(props: IProps): React.ReactElement { + const [sort, setSort] = useState(SortOption.Cost); + // Randomly create all Resleeves if they dont already exist + if (props.player.resleeves.length === 0) { + props.player.resleeves = generateResleeves(); + } + + function onSortChange(event: React.ChangeEvent): void { + setSort(event.target.value); + } + + const sortFunction = SortFunctions[sort]; + if (sortFunction === undefined) throw new Error(`sort function '${sort}' is undefined`); + props.player.resleeves.sort(sortFunction); + + return ( + <> +

+ 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. +

+

Sort By:

+ + {props.player.resleeves.map((resleeve, i) => ( + + ))} + + ); +} diff --git a/src/engine.jsx b/src/engine.jsx index 2621bc81b..c28fc9dfa 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -22,6 +22,7 @@ import { FactionList } from "./Faction/ui/FactionList"; import { Root as BladeburnerRoot } from "./Bladeburner/ui/Root"; import { Root as GangRoot } from "./Gang/ui/Root"; import { CorporationRoot } from "./Corporation/ui/CorporationRoot"; +import { ResleeveRoot } from "./PersonObjects/Resleeving/ui/ResleeveRoot"; import { displayInfiltrationContent } from "./Infiltration/Helper"; import { getHackingWorkRepGain, @@ -189,6 +190,7 @@ const Engine = { stockMarketContent: null, gangContent: null, bladeburnerContent: null, + resleeveContent: null, corporationContent: null, locationContent: null, workInProgressContent: null, @@ -439,13 +441,10 @@ const Engine = { }, loadResleevingContent: function () { - try { - Engine.hideAllContent(); - routing.navigateTo(Page.Resleeves); - createResleevesPage(Player); - } catch (e) { - exceptionAlert(e); - } + Engine.hideAllContent(); + routing.navigateTo(Page.Resleeves); + Engine.Display.resleeveContent.style.display = "block"; + ReactDOM.render(, Engine.Display.resleeveContent); }, // Helper function that hides all content @@ -486,16 +485,21 @@ const Engine = { Engine.Display.bladeburnerContent.style.display = "none"; ReactDOM.unmountComponentAtNode(Engine.Display.bladeburnerContent); + Engine.Display.resleeveContent.style.display = "none"; + ReactDOM.unmountComponentAtNode(Engine.Display.resleeveContent); + Engine.Display.corporationContent.style.display = "none"; ReactDOM.unmountComponentAtNode(Engine.Display.corporationContent); + Engine.Display.resleeveContent.style.display = "none"; + ReactDOM.unmountComponentAtNode(Engine.Display.resleeveContent); + Engine.Display.workInProgressContent.style.display = "none"; Engine.Display.redPillContent.style.display = "none"; Engine.Display.cinematicTextContent.style.display = "none"; Engine.Display.stockMarketContent.style.display = "none"; Engine.Display.missionContent.style.display = "none"; - clearResleevesPage(); clearSleevesPage(); // Make nav menu tabs inactive @@ -1252,6 +1256,9 @@ const Engine = { Engine.Display.bladeburnerContent = document.getElementById("bladeburner-container"); Engine.Display.bladeburnerContent.style.display = "none"; + Engine.Display.resleeveContent = document.getElementById("resleeve-container"); + Engine.Display.resleeveContent.style.display = "none"; + Engine.Display.corporationContent = document.getElementById("corporation-container"); Engine.Display.corporationContent.style.display = "none"; diff --git a/src/index.html b/src/index.html index d682c2e6d..14d1be80f 100644 --- a/src/index.html +++ b/src/index.html @@ -364,6 +364,7 @@
+