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