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