diff --git a/src/Corporation/ui/IndustryOffice.tsx b/src/Corporation/ui/IndustryOffice.tsx index 62c6b2205..af04c7591 100644 --- a/src/Corporation/ui/IndustryOffice.tsx +++ b/src/Corporation/ui/IndustryOffice.tsx @@ -431,17 +431,21 @@ export function IndustryOffice(props: IProps): React.ReactElement { Size: {props.office.employees.length} / {props.office.size} employees - - + + Automatically hires an employee and gives him/her a random name}> - + + + Upgrade the office's size so that it can hold more employees!}> - + + + Throw an office party to increase your employee's morale and happiness} > - + + + )} - diff --git a/src/Faction/data/FactionNames.ts b/src/Faction/data/FactionNames.ts index ad24e8e6b..6ebd4de63 100644 --- a/src/Faction/data/FactionNames.ts +++ b/src/Faction/data/FactionNames.ts @@ -18,8 +18,8 @@ export enum FactionNames { Aevum = "Aevum", Chongqing = "Chongqing", Ishima = "Ishima", - NewTokyo = "NewTokyo", - Sector12 = "Sector12", + NewTokyo = "New Tokyo", + Sector12 = "Sector-12", Volhaven = "Volhaven", SpeakersForTheDead = "Speakers for the Dead", TheDarkArmy = "The Dark Army", diff --git a/src/Gang/ui/EquipmentsSubpage.tsx b/src/Gang/ui/EquipmentsSubpage.tsx index 5c057eed7..5fea585db 100644 --- a/src/Gang/ui/EquipmentsSubpage.tsx +++ b/src/Gang/ui/EquipmentsSubpage.tsx @@ -3,7 +3,6 @@ */ import React, { useState } from "react"; import { useGang } from "./Context"; -import { generateTableRow } from "./GangMemberStats"; import Typography from "@mui/material/Typography"; import Button from "@mui/material/Button"; @@ -22,7 +21,7 @@ import { GangMember } from "../GangMember"; import { UpgradeType } from "../data/upgrades"; import { use } from "../../ui/Context"; import { Settings } from "../../Settings/Settings"; -import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview"; +import { StatsRow } from "../../ui/React/StatsRow"; interface INextRevealProps { upgrades: string[]; @@ -91,7 +90,6 @@ interface IPanelProps { } function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { - const classes = useStyles(); const gang = useGang(); const player = use.Player(); const setRerender = useState(false)[1]; @@ -178,12 +176,12 @@ function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { > - {generateTableRow("Hacking", props.member.hack, props.member.hack_exp, Settings.theme.hack, classes)} - {generateTableRow("Strength", props.member.str, props.member.str_exp, Settings.theme.combat, classes)} - {generateTableRow("Defense", props.member.def, props.member.def_exp, Settings.theme.combat, classes)} - {generateTableRow("Dexterity", props.member.dex, props.member.dex_exp, Settings.theme.combat, classes)} - {generateTableRow("Agility", props.member.agi, props.member.agi_exp, Settings.theme.combat, classes)} - {generateTableRow("Charisma", props.member.cha, props.member.cha_exp, Settings.theme.cha, classes)} + + + + + +
diff --git a/src/Gang/ui/GangMemberStats.tsx b/src/Gang/ui/GangMemberStats.tsx index 859057837..66fe16582 100644 --- a/src/Gang/ui/GangMemberStats.tsx +++ b/src/Gang/ui/GangMemberStats.tsx @@ -17,36 +17,14 @@ import { import { numeralWrapper } from "../../ui/numeralFormat"; import { GangMember } from "../GangMember"; import { Settings } from "../../Settings/Settings"; -import { formatNumber } from "../../utils/StringHelperFunctions"; import { MoneyRate } from "../../ui/React/MoneyRate"; +import { StatsRow } from "../../ui/React/StatsRow"; import { characterOverviewStyles as useStyles } from "../../ui/React/CharacterOverview"; interface IProps { member: GangMember; } -export const generateTableRow = ( - name: string, - level: number, - exp: number, - color: string, - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - classes: any -): React.ReactElement => { - return ( - - - {name} - - - - {formatNumber(level, 0)} ({numeralWrapper.formatExp(exp)} exp) - - - - ) -} - export function GangMemberStats(props: IProps): React.ReactElement { const classes = useStyles(); @@ -102,12 +80,12 @@ export function GangMemberStats(props: IProps): React.ReactElement { > - {generateTableRow("Hacking", props.member.hack, props.member.hack_exp, Settings.theme.hack, classes)} - {generateTableRow("Strength", props.member.str, props.member.str_exp, Settings.theme.combat, classes)} - {generateTableRow("Defense", props.member.def, props.member.def_exp, Settings.theme.combat, classes)} - {generateTableRow("Dexterity", props.member.dex, props.member.dex_exp, Settings.theme.combat, classes)} - {generateTableRow("Agility", props.member.agi, props.member.agi_exp, Settings.theme.combat, classes)} - {generateTableRow("Charisma", props.member.cha, props.member.cha_exp, Settings.theme.cha, classes)} + + + + + +
diff --git a/src/Gang/ui/TerritoryInfoModal.tsx b/src/Gang/ui/TerritoryInfoModal.tsx new file mode 100644 index 000000000..cbd8640f0 --- /dev/null +++ b/src/Gang/ui/TerritoryInfoModal.tsx @@ -0,0 +1,54 @@ +import React from "react"; + +import Typography from "@mui/material/Typography"; + +import { Modal } from "../../ui/React/Modal"; + +interface IProps { + open: boolean; + onClose: () => void; +} + +export const TerritoryInfoModal = ({ open, onClose }: IProps): React.ReactElement => { + return ( + + <> + + Clashing + + + Every ~20 seconds, your gang has a chance to 'clash' with other gangs. Your chance to win a clash depends on + your gang's power, which is listed in the display below. Your gang's power slowly accumulates over time. The + accumulation rate is determined by the stats of all Gang members you have assigned to the 'Territory Warfare' + task. Gang members that are not assigned to this task do not contribute to your gang's power. Your gang also + loses a small amount of power whenever you lose a clash. +
+
+ NOTE: Gang members assigned to 'Territory Warfare' can be killed during clashes. This can happen regardless of + whether you win or lose the clash. A gang member being killed results in both respect and power loss for your + gang. +
+
+ + Territory + + + The amount of territory you have affects all aspects of your Gang members' production, including money, respect, + and wanted level. It is very beneficial to have high territory control. +
+
+ To increase your chances of winning territory, assign gang members to "Territory Warfare". This will build your + gang power. Then, enable "Engage in Territory Warfare" to start fighting over territory. +
+
+ + Territory Clash Chance + + + This percentage represents the chance you have of 'clashing' with another gang. If you do not wish to + gain/lose territory, then keep this percentage at 0% by not engaging in territory warfare. + + +
+ ); +} diff --git a/src/Gang/ui/TerritorySubpage.tsx b/src/Gang/ui/TerritorySubpage.tsx index 434bf1c3e..9a52ea2ab 100644 --- a/src/Gang/ui/TerritorySubpage.tsx +++ b/src/Gang/ui/TerritorySubpage.tsx @@ -1,133 +1,100 @@ /** * React Component for the territory subpage. */ -import React from "react"; +import React, { useState } from "react"; + +import { + Container, + Button, + Paper, + Box, + Tooltip, + Switch, + FormControlLabel, + Typography +} from "@mui/material"; +import { Help } from "@mui/icons-material"; + import { numeralWrapper } from "../../ui/numeralFormat"; import { formatNumber } from "../../utils/StringHelperFunctions"; -import { AllGangs } from "../AllGangs"; -import { useGang } from "./Context"; -import Typography from "@mui/material/Typography"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import Switch from "@mui/material/Switch"; -import Tooltip from "@mui/material/Tooltip"; -import Box from "@mui/material/Box"; -import Paper from "@mui/material/Paper"; +import { AllGangs } from "../AllGangs"; + +import { useGang } from "./Context"; +import { TerritoryInfoModal } from "./TerritoryInfoModal"; export function TerritorySubpage(): React.ReactElement { const gang = useGang(); const gangNames = Object.keys(AllGangs).filter((g) => g != gang.facName); + const [infoOpen, setInfoOpen] = useState(false); return ( - <> + This page shows how much territory your Gang controls. This statistic is listed as a percentage, which represents how much of the total territory you control. -
-
- Every ~20 seconds, your gang has a chance to 'clash' with other gangs. Your chance to win a clash depends on - your gang's power, which is listed in the display below. Your gang's power slowly accumulates over time. The - accumulation rate is determined by the stats of all Gang members you have assigned to the 'Territory Warfare' - task. Gang members that are not assigned to this task do not contribute to your gang's power. Your gang also - loses a small amount of power whenever you lose a clash. -
-
- NOTE: Gang members assigned to 'Territory Warfare' can be killed during clashes. This can happen regardless of - whether you win or lose the clash. A gang member being killed results in both respect and power loss for your - gang. -
-
- The amount of territory you have affects all aspects of your Gang members' production, including money, respect, - and wanted level. It is very beneficial to have high territory control. -
-
- To increase your chances of winning territory assign gang members to "Territory Warfare", this will build your - gang power. Then enable "Engage in Territory Warfare" to start fighting over territory.
- setInfoOpen(true)} sx={{ my: 1 }}> + + About Gang Territory + + + + + {gang.facName} (Your gang) + + + (gang.territoryWarfareEngaged = event.target.checked)} - /> - } - label={ - - Engaging in Territory Warfare sets your clash chance to 100%. Disengaging will cause your clash chance - to gradually decrease until it reaches 0%. - - } - > + />} + label={ + Engaging in Territory Warfare sets your clash chance to 100%. Disengaging will cause your clash chance + to gradually decrease until it reaches 0%. + }> Engage in Territory Warfare - - } - /> -
- - - This percentage represents the chance you have of 'clashing' with with another gang. If you do not wish to - gain/lose territory, then keep this percentage at 0% by not engaging in territory warfare. - - } - > - - Territory Clash Chance: {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)} - - - -
- } /> +
+ (gang.notifyMemberDeath = event.target.checked)} - /> - } - label={ - - If this is enabled, then you will receive a pop-up notifying you whenever one of your Gang Members dies - in a territory clash. - - } - > + />} + label={ + If this is enabled, then you will receive a pop-up notifying you whenever one of your Gang Members dies + in a territory clash. + }> Notify about Gang Member Deaths - - } - /> -
- +
} /> + - - {gang.facName} - -
- Power: {formatNumber(AllGangs[gang.facName].power, 6)} -
- Territory: {formatTerritory(AllGangs[gang.facName].territory)}% -
-
+ Territory Clash Chance: {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)}
+ Power: {formatNumber(AllGangs[gang.facName].power, 3)}
+ Territory: {formatTerritory(AllGangs[gang.facName].territory)}%
+
+ {gangNames.map((name) => ( ))} - - + + setInfoOpen(false)} /> +
); } function formatTerritory(n: number): string { const v = n * 100; + const precision = 3; if (v <= 0) { - return formatNumber(0, 2); + return formatNumber(0, precision); } else if (v >= 100) { - return formatNumber(100, 2); + return formatNumber(100, precision); } else { - return formatNumber(v, 2); + return formatNumber(v, precision); } } @@ -141,15 +108,15 @@ function OtherGangTerritory(props: ITerritoryProps): React.ReactElement { const power = AllGangs[props.name].power; const clashVictoryChance = playerPower / (power + playerPower); return ( - - {props.name} -
- Power: {formatNumber(power, 6)} -
- Territory: {formatTerritory(AllGangs[props.name].territory)}%
- Chance to win clash with this gang: {numeralWrapper.formatPercentage(clashVictoryChance, 3)} -
-
-
+ + + {props.name} + + + Power: {formatNumber(power, 3)}
+ Territory: {formatTerritory(AllGangs[props.name].territory)}%
+ Clash Win Chance: {numeralWrapper.formatPercentage(clashVictoryChance, 3)} +
+
); } diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index 338cbae7d..70a6c2b0f 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -181,6 +181,8 @@ export const RamCosts: IMap = { getForecast: RamCostConstants.ScriptBuySellStockRamCost, purchase4SMarketData: RamCostConstants.ScriptBuySellStockRamCost, purchase4SMarketDataTixApi: RamCostConstants.ScriptBuySellStockRamCost, + purchaseWseAccount: RamCostConstants.ScriptBuySellStockRamCost, + purchaseTixApi: RamCostConstants.ScriptBuySellStockRamCost, }, getPurchasedServerLimit: RamCostConstants.ScriptGetPurchasedServerLimit, getPurchasedServerMaxRam: RamCostConstants.ScriptGetPurchasedServerMaxRam, diff --git a/src/NetscriptFunctions/StockMarket.ts b/src/NetscriptFunctions/StockMarket.ts index 6f4408855..7e0e64f60 100644 --- a/src/NetscriptFunctions/StockMarket.ts +++ b/src/NetscriptFunctions/StockMarket.ts @@ -8,7 +8,7 @@ import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/St import { OrderTypes } from "../StockMarket/data/OrderTypes"; import { PositionTypes } from "../StockMarket/data/PositionTypes"; import { StockSymbols } from "../StockMarket/data/StockSymbols"; -import { getStockMarket4SDataCost, getStockMarket4STixApiCost } from "../StockMarket/StockMarketCosts"; +import { getStockMarket4SDataCost, getStockMarket4STixApiCost, getStockMarketWseCost, getStockMarketTixApiCost } from "../StockMarket/StockMarketCosts"; import { Stock } from "../StockMarket/Stock"; import { TIX } from "../ScriptEditor/NetscriptDefinitions"; @@ -388,5 +388,47 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API"); return true; }, + purchaseWseAccount: function (): boolean { + helper.updateDynamicRam("PurchaseWseAccount", getRamCost(player, "stock", "purchaseWseAccount")); + + if (player.hasWseAccount) { + workerScript.log("stock.purchaseWseAccount", () => "Already purchased WSE Account"); + return true; + } + + if (player.money < getStockMarketWseCost()) { + workerScript.log( + "stock.purchaseWseAccount", + () => "Not enough money to purchase WSE Account Access", + ); + return false; + } + + player.hasWseAccount = true; + player.loseMoney(getStockMarketWseCost(), "stock"); + workerScript.log("stock.purchaseWseAccount", () => "Purchased WSE Account Access"); + return true; + }, + purchaseTixApi: function (): boolean { + helper.updateDynamicRam("purchaseTixApi", getRamCost(player, "stock", "purchaseTixApi")); + + if (player.hasTixApiAccess) { + workerScript.log("stock.purchaseTixApi", () => "Already purchased TIX API"); + return true; + } + + if (player.money < getStockMarketTixApiCost()) { + workerScript.log( + "stock.purchaseTixApi", + () => "Not enough money to purchase TIX API Access", + ); + return false; + } + + player.hasTixApiAccess = true; + player.loseMoney(getStockMarketTixApiCost(), "stock"); + workerScript.log("stock.purchaseTixApi", () => "Purchased TIX API"); + return true; + }, }; } diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx index 022819b21..968e50cde 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.tsx @@ -932,7 +932,9 @@ export function startFactionSecurityWork(this: IPlayer, faction: Faction): void export function workForFaction(this: IPlayer, numCycles: number): boolean { const faction = Factions[this.currentWorkFactionName]; - if (!faction) { return false; } + if (!faction) { + return false; + } //Constantly update the rep gain rate switch (this.factionWorkType) { @@ -1252,12 +1254,7 @@ export function getWorkRepGain(this: IPlayer): number { // } /* Creating a Program */ -export function startCreateProgramWork( - this: IPlayer, - programName: string, - time: number, - reqLevel: number, -): void { +export function startCreateProgramWork(this: IPlayer, programName: string, time: number, reqLevel: number): void { this.resetWorkStatus(); this.isWorking = true; this.workType = CONSTANTS.WorkTypeCreateProgram; @@ -1510,20 +1507,20 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string { if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) { ws.scriptRef.log( "SUCCESS: Crime successful! Gained " + - numeralWrapper.formatMoney(this.workMoneyGained) + - ", " + - numeralWrapper.formatExp(this.workHackExpGained) + - " hack exp, " + - numeralWrapper.formatExp(this.workStrExpGained) + - " str exp, " + - numeralWrapper.formatExp(this.workDefExpGained) + - " def exp, " + - numeralWrapper.formatExp(this.workDexExpGained) + - " dex exp, " + - numeralWrapper.formatExp(this.workAgiExpGained) + - " agi exp, " + - numeralWrapper.formatExp(this.workChaExpGained) + - " cha exp.", + numeralWrapper.formatMoney(this.workMoneyGained) + + ", " + + numeralWrapper.formatExp(this.workHackExpGained) + + " hack exp, " + + numeralWrapper.formatExp(this.workStrExpGained) + + " str exp, " + + numeralWrapper.formatExp(this.workDefExpGained) + + " def exp, " + + numeralWrapper.formatExp(this.workDexExpGained) + + " dex exp, " + + numeralWrapper.formatExp(this.workAgiExpGained) + + " agi exp, " + + numeralWrapper.formatExp(this.workChaExpGained) + + " cha exp.", ); } } else { @@ -1562,18 +1559,18 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string { if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) { ws.scriptRef.log( "FAIL: Crime failed! Gained " + - numeralWrapper.formatExp(this.workHackExpGained) + - " hack exp, " + - numeralWrapper.formatExp(this.workStrExpGained) + - " str exp, " + - numeralWrapper.formatExp(this.workDefExpGained) + - " def exp, " + - numeralWrapper.formatExp(this.workDexExpGained) + - " dex exp, " + - numeralWrapper.formatExp(this.workAgiExpGained) + - " agi exp, " + - numeralWrapper.formatExp(this.workChaExpGained) + - " cha exp.", + numeralWrapper.formatExp(this.workHackExpGained) + + " hack exp, " + + numeralWrapper.formatExp(this.workStrExpGained) + + " str exp, " + + numeralWrapper.formatExp(this.workDefExpGained) + + " def exp, " + + numeralWrapper.formatExp(this.workDexExpGained) + + " dex exp, " + + numeralWrapper.formatExp(this.workAgiExpGained) + + " agi exp, " + + numeralWrapper.formatExp(this.workChaExpGained) + + " cha exp.", ); } } else { @@ -2000,13 +1997,15 @@ export function isQualified(this: IPlayer, company: Company, position: CompanyPo const reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity + offset : 0; const reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma + offset : 0; - return this.hacking >= reqHacking && + return ( + this.hacking >= reqHacking && this.strength >= reqStrength && this.defense >= reqDefense && this.dexterity >= reqDexterity && this.agility >= reqAgility && this.charisma >= reqCharisma && - company.playerReputation >= position.requiredReputation; + company.playerReputation >= position.requiredReputation + ); } /********** Reapplying Augmentations and Source File ***********/ @@ -2237,7 +2236,8 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] { //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company const fulcrumsecrettechonologiesFac = Factions[FactionNames.FulcrumSecretTechnologies]; const fulcrumSecretServer = GetServer(SpecialServers.FulcrumSecretTechnologies); - if (!(fulcrumSecretServer instanceof Server)) throw new Error(`${FactionNames.FulcrumSecretTechnologies} should be normal server`); + if (!(fulcrumSecretServer instanceof Server)) + throw new Error(`${FactionNames.FulcrumSecretTechnologies} should be normal server`); if (fulcrumSecretServer == null) { console.error(`Could not find ${FactionNames.FulcrumSecretTechnologies} Server`); } else if ( diff --git a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx index 301137b24..57c402878 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx @@ -50,74 +50,62 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement { return ( <> - - 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) => { - return ( - - - - - - - - {aug.name} - - - - - - - - ); - })} - -
+ + + 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) => { + return ( + + + + + + + + {aug.name} + + + + + + + + ); + })} + +
+
+
{ownedAugNames.length > 0 && ( <> - Owned Augmentations: - {ownedAugNames.map((augName) => { - const aug = Augmentations[augName]; - let tooltip = <>; - if (typeof aug.info === "string") { - tooltip = ( - <> - {aug.info} -
-
- {aug.stats} - - ); - } else { - tooltip = ( - <> - {aug.info} -
-
- {aug.stats} - - ); - } + Owned Augmentations: + + {ownedAugNames.map((augName) => { + const aug = Augmentations[augName]; + const info = typeof aug.info === "string" ? {aug.info} : aug.info + const tooltip = (<>{info}

{aug.stats}); - return ( - {tooltip}}> - - {augName} - - - ); - })} + return ( + {tooltip}}> + + {augName} + + + ); + })} +
)} diff --git a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx index 45a3e909d..5d73a762d 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx @@ -1,34 +1,29 @@ import React, { useState } from "react"; +import { + Box, + Paper, + Typography, + Button, + Tooltip +} from "@mui/material"; + +import { CONSTANTS } from "../../../Constants"; +import { Crimes } from "../../../Crime/Crimes"; +import { numeralWrapper } from "../../../ui/numeralFormat"; +import { createProgressBarText } from "../../../utils/helpers/createProgressBarText"; +import { use } from "../../../ui/Context"; +import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum"; + import { Sleeve } from "../Sleeve"; import { SleeveTaskType } from "../SleeveTaskTypesEnum"; -import { CONSTANTS } from "../../../Constants"; - -import { Crimes } from "../../../Crime/Crimes"; - -import { numeralWrapper } from "../../../ui/numeralFormat"; - -import { createProgressBarText } from "../../../utils/helpers/createProgressBarText"; - import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal"; import { TravelModal } from "./TravelModal"; -import { Money } from "../../../ui/React/Money"; -import { MoneyRate } from "../../../ui/React/MoneyRate"; -import { use } from "../../../ui/Context"; -import { ReputationRate } from "../../../ui/React/ReputationRate"; -import { StatsElement } from "./StatsElement"; +import { StatsElement, EarningsElement } from "./StatsElement"; import { MoreStatsModal } from "./MoreStatsModal"; import { MoreEarningsModal } from "./MoreEarningsModal"; import { TaskSelector } from "./TaskSelector"; -import { FactionWorkType } from "../../../Faction/FactionWorkTypeEnum"; -import { StatsTable } from "../../../ui/React/StatsTable"; - -import Typography from "@mui/material/Typography"; -import Paper from "@mui/material/Paper"; -import Grid from "@mui/material/Grid"; -import Button from "@mui/material/Button"; -import Tooltip from "@mui/material/Tooltip"; interface IProps { sleeve: Sleeve; @@ -141,86 +136,71 @@ export function SleeveElem(props: IProps): React.ReactElement { console.error(`Invalid/Unrecognized taskValue in updateSleeveTaskDescription(): ${abc[0]}`); } - let data: any[][] = []; - if (props.sleeve.currentTask === SleeveTaskType.Crime) { - data = [ - [`Money`, , `(on success)`], - [`Hacking Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.hack), `(2x on success)`], - [`Strength Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.str), `(2x on success)`], - [`Defense Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.def), `(2x on success)`], - [`Dexterity Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.dex), `(2x on success)`], - [`Agility Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.agi), `(2x on success)`], - [`Charisma Exp`, numeralWrapper.formatExp(props.sleeve.gainRatesForTask.cha), `(2x on success)`], - ]; - } else { - data = [ - [`Money:`, ], - [`Hacking Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.hack)} / s`], - [`Strength Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.str)} / s`], - [`Defense Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.def)} / s`], - [`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.dex)} / s`], - [`Agility Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.agi)} / s`], - [`Charisma Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.cha)} / s`], - ]; - if (props.sleeve.currentTask === SleeveTaskType.Company || props.sleeve.currentTask === SleeveTaskType.Faction) { - const repGain: number = props.sleeve.getRepGain(player); - data.push([`Reputation:`, ]); - } - } - return ( - <> - - - - - Insufficient funds : ""}> - - - - - Unlocked when sleeve has fully recovered : ""} - > - - - - - - - - {desc} - - {props.sleeve.currentTask === SleeveTaskType.Crime && - createProgressBarText({ - progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime, - totalTicks: 25, - })} - - - - - - - - - setStatsOpen(false)} sleeve={props.sleeve} /> - setEarningsOpen(false)} sleeve={props.sleeve} /> - setTravelOpen(false)} - sleeve={props.sleeve} - rerender={props.rerender} - /> - setAugmentationsOpen(false)} - sleeve={props.sleeve} - /> - + + + + + + + + + Insufficient funds : ""}> + + + + + Unlocked when sleeve has fully recovered : ""} + > + + + + + + + + + + + + {desc} + + {props.sleeve.currentTask === SleeveTaskType.Crime && + createProgressBarText({ + progress: props.sleeve.currentTaskTime / props.sleeve.currentTaskMaxTime, + totalTicks: 25, + })} + + + + setStatsOpen(false)} sleeve={props.sleeve} /> + setEarningsOpen(false)} sleeve={props.sleeve} /> + setTravelOpen(false)} + sleeve={props.sleeve} + rerender={props.rerender} + /> + setAugmentationsOpen(false)} + sleeve={props.sleeve} + /> + + + ); } diff --git a/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx b/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx index 808b84723..5d553a495 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx @@ -1,12 +1,16 @@ import React, { useState, useEffect } from "react"; +import { + Box, + Typography, + Button, + Container +} from "@mui/material"; + +import { use } from "../../../ui/Context"; + import { SleeveElem } from "./SleeveElem"; import { FAQModal } from "./FAQModal"; -import { use } from "../../../ui/Context"; - -import Typography from "@mui/material/Typography"; -import Button from "@mui/material/Button"; -import Link from "@mui/material/Link"; export function SleeveRoot(): React.ReactElement { const player = use.Player(); @@ -23,27 +27,29 @@ export function SleeveRoot(): React.ReactElement { return ( <> - Sleeves - - Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness has been copied. In - other words, these Synthoids contain a perfect duplicate of your mind. -
-
- Sleeves can be used to perform different tasks synchronously. -
-
-
+ + Sleeves + + Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness has been copied. In + other words, these Synthoids contain a perfect duplicate of your mind. +
+
+ Sleeves can be used to perform different tasks synchronously. +
+
+
+ +
- - Documentation - - {player.sleeves.map((sleeve, i) => ( - - ))} + + + {player.sleeves.map((sleeve, i) => ( + + ))} + setFAQOpen(false)} /> ); diff --git a/src/PersonObjects/Sleeve/ui/StatsElement.tsx b/src/PersonObjects/Sleeve/ui/StatsElement.tsx index 9e51214fc..901348a8e 100644 --- a/src/PersonObjects/Sleeve/ui/StatsElement.tsx +++ b/src/PersonObjects/Sleeve/ui/StatsElement.tsx @@ -1,31 +1,110 @@ -import { Sleeve } from "../Sleeve"; -import { numeralWrapper } from "../../../ui/numeralFormat"; import React from "react"; -import { StatsTable } from "../../../ui/React/StatsTable"; +import { + Typography, + Table, + TableBody, + TableCell, + TableRow, +} from "@mui/material"; + +import { numeralWrapper } from "../../../ui/numeralFormat"; +import { Settings } from "../../../Settings/Settings"; +import { StatsRow } from "../../../ui/React/StatsRow"; +import { characterOverviewStyles as useStyles } from "../../../ui/React/CharacterOverview"; +import { Money } from "../../../ui/React/Money"; +import { MoneyRate } from "../../../ui/React/MoneyRate"; +import { ReputationRate } from "../../../ui/React/ReputationRate"; +import { use } from "../../../ui/Context"; + +import { Sleeve } from "../Sleeve"; +import { SleeveTaskType } from "../SleeveTaskTypesEnum"; interface IProps { sleeve: Sleeve; } export function StatsElement(props: IProps): React.ReactElement { - const rows = [ - [ - "HP: ", - <> - {numeralWrapper.formatHp(props.sleeve.hp)} / {numeralWrapper.formatHp(props.sleeve.max_hp)} - , - ], - ["City: ", <>{props.sleeve.city}], - ["Hacking: ", <>{numeralWrapper.formatSkill(props.sleeve.hacking)}], - ["Strength: ", <>{numeralWrapper.formatSkill(props.sleeve.strength)}], - ["Defense: ", <>{numeralWrapper.formatSkill(props.sleeve.defense)}], - ["Dexterity: ", <>{numeralWrapper.formatSkill(props.sleeve.dexterity)}], - ["Agility: ", <>{numeralWrapper.formatSkill(props.sleeve.agility)}], - ["Charisma: ", <>{numeralWrapper.formatSkill(props.sleeve.charisma)}], - ["Shock: ", <>{numeralWrapper.formatSleeveShock(100 - props.sleeve.shock)}], - ["Sync: ", <>{numeralWrapper.formatSleeveSynchro(props.sleeve.sync)}], - ["Memory: ", <>{numeralWrapper.formatSleeveMemory(props.sleeve.memory)}], - ]; - return ; + const classes = useStyles(); + + return ( + + + + + + + + + + + + +
+
+
+ + + +
+
+ ) +} + +export function EarningsElement(props: IProps): React.ReactElement { + const classes = useStyles(); + const player = use.Player(); + + let data: any[][] = []; + if (props.sleeve.currentTask === SleeveTaskType.Crime) { + data = [ + [`Money`, <> (on success)], + [`Hacking Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.hack)} (2x on success)`], + [`Strength Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.str)} (2x on success)`], + [`Defense Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.def)} (2x on success)`], + [`Dexterity Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.dex)} (2x on success)`], + [`Agility Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.agi)} (2x on success)`], + [`Charisma Exp`, `${numeralWrapper.formatExp(props.sleeve.gainRatesForTask.cha)} (2x on success)`], + ]; + } else { + data = [ + [`Money:`, ], + [`Hacking Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.hack)} / sec`], + [`Strength Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.str)} / sec`], + [`Defense Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.def)} / sec`], + [`Dexterity Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.dex)} / sec`], + [`Agility Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.agi)} / sec`], + [`Charisma Exp:`, `${numeralWrapper.formatExp(5 * props.sleeve.gainRatesForTask.cha)} / sec`], + ]; + if (props.sleeve.currentTask === SleeveTaskType.Company || props.sleeve.currentTask === SleeveTaskType.Faction) { + const repGain: number = props.sleeve.getRepGain(player); + data.push([`Reputation:`, ]); + } + } + + return ( + + + + + + Earnings + + + + {data.map(([a, b]) => ( + + + {a} + + + {b} + + + ))} + +
+ ) } diff --git a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx index 766efcc95..70d5aac15 100644 --- a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx +++ b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx @@ -279,7 +279,7 @@ export function TaskSelector(props: IProps): React.ReactElement { return ( <> - {validActions.map((task) => ( {task} @@ -288,8 +288,7 @@ export function TaskSelector(props: IProps): React.ReactElement { {!(details.first.length === 1 && details.first[0] === "------") && ( <> -
- {details.first.map((detail) => ( {detail} @@ -300,8 +299,7 @@ export function TaskSelector(props: IProps): React.ReactElement { )} {!(details2.length === 1 && details2[0] === "------") && ( <> -
- {details2.map((detail) => ( {detail} diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index d46b1b0f6..ca5a20644 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -1506,6 +1506,20 @@ export interface TIX { * @returns True if you successfully purchased it or if you already have access, false otherwise. */ purchase4SMarketDataTixApi(): boolean; + + /** + * Purchase WSE Account. + * @remarks RAM cost: 2.5 GB + * @returns True if you successfully purchased it or if you already have access, false otherwise. + */ + purchaseWseAccount(): boolean; + + /** + * Purchase TIX API Access + * @remarks RAM cost: 2.5 GB + * @returns True if you successfully purchased it or if you already have access, false otherwise. + */ + purchaseTixApi(): boolean; } /** diff --git a/src/StockMarket/StockMarketCosts.ts b/src/StockMarket/StockMarketCosts.ts index 623f382a2..a8887298d 100644 --- a/src/StockMarket/StockMarketCosts.ts +++ b/src/StockMarket/StockMarketCosts.ts @@ -8,3 +8,11 @@ export function getStockMarket4SDataCost(): number { export function getStockMarket4STixApiCost(): number { return CONSTANTS.MarketDataTixApi4SCost * BitNodeMultipliers.FourSigmaMarketDataApiCost; } + +export function getStockMarketWseCost(): number { + return CONSTANTS.WSEAccountCost; +} + +export function getStockMarketTixApiCost(): number { + return CONSTANTS.TIXAPICost; +} diff --git a/src/ui/React/StatsRow.tsx b/src/ui/React/StatsRow.tsx new file mode 100644 index 000000000..ce623ccd3 --- /dev/null +++ b/src/ui/React/StatsRow.tsx @@ -0,0 +1,49 @@ +import React from "react"; + +import { + Typography, + TableCell, + TableRow, +} from "@mui/material"; + +import { numeralWrapper } from "../numeralFormat"; +import { formatNumber } from "../../utils/StringHelperFunctions"; +import { characterOverviewStyles as useStyles } from "./CharacterOverview"; + +interface ITableRowData { + content?: string; + level?: number; + exp?: number; +} + +interface IProps { + name: string; + color: string; + classes?: any; + data: ITableRowData; +} + +export const StatsRow = ({ name, color, classes = useStyles(), data }: IProps): React.ReactElement => { + let content; + + if (data.content !== undefined) { + content = data.content; + } else if (data.level !== undefined && data.exp !== undefined) { + content = `${formatNumber(data.level, 0)} (${numeralWrapper.formatExp(data.exp)} exp)`; + } else if (data.level !== undefined && data.exp === undefined) { + content = `${formatNumber(data.level, 0)}`; + } + + return ( + + + {name} + + + + {content} + + + + ) +}