mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-22 22:22:26 +01:00
BLADEBURNER: Add visual cues to warn player of dangerous actions and status of population, chaos (#1856)
This commit is contained in:
parent
c49a507031
commit
28da81f3f1
@ -12,6 +12,7 @@ import { clampNumber } from "../../utils/helpers/clampNumber";
|
||||
|
||||
export interface ActionParams {
|
||||
desc: string;
|
||||
warning?: string;
|
||||
successScaling?: string;
|
||||
baseDifficulty?: number;
|
||||
rewardFac?: number;
|
||||
@ -26,6 +27,7 @@ export interface ActionParams {
|
||||
|
||||
export abstract class ActionClass {
|
||||
desc = "";
|
||||
warning = "";
|
||||
successScaling = "";
|
||||
// For LevelableActions, the base difficulty can be increased based on action level
|
||||
baseDifficulty = 100;
|
||||
@ -63,6 +65,7 @@ export abstract class ActionClass {
|
||||
constructor(params: ActionParams | null = null) {
|
||||
if (!params) return;
|
||||
this.desc = params.desc;
|
||||
if (params.warning) this.warning = params.warning;
|
||||
if (params.successScaling) this.successScaling = params.successScaling;
|
||||
if (params.baseDifficulty) this.baseDifficulty = addOffset(params.baseDifficulty, 10);
|
||||
|
||||
|
@ -829,24 +829,25 @@ export class Bladeburner implements OperationTeam {
|
||||
}
|
||||
|
||||
completeContract(success: boolean, action: Contract): void {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
const city = this.getCurrentCity();
|
||||
if (success) {
|
||||
switch (action.name) {
|
||||
case BladeburnerContractName.Tracking:
|
||||
// Increase estimate accuracy by a relatively small amount
|
||||
city.improvePopulationEstimateByCount(
|
||||
getRandomIntInclusive(100, 1e3) * this.getSkillMult(BladeburnerMultName.SuccessChanceEstimate),
|
||||
);
|
||||
break;
|
||||
case BladeburnerContractName.BountyHunter:
|
||||
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
|
||||
city.changeChaosByCount(0.02);
|
||||
break;
|
||||
case BladeburnerContractName.Retirement:
|
||||
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
|
||||
city.changeChaosByCount(0.04);
|
||||
break;
|
||||
}
|
||||
switch (action.name) {
|
||||
case BladeburnerContractName.Tracking:
|
||||
// Increase estimate accuracy by a relatively small amount
|
||||
city.improvePopulationEstimateByCount(
|
||||
getRandomIntInclusive(100, 1e3) * this.getSkillMult(BladeburnerMultName.SuccessChanceEstimate),
|
||||
);
|
||||
break;
|
||||
case BladeburnerContractName.BountyHunter:
|
||||
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
|
||||
city.changeChaosByCount(0.02);
|
||||
break;
|
||||
case BladeburnerContractName.Retirement:
|
||||
city.changePopulationByCount(-1, { estChange: -1, estOffset: 0 });
|
||||
city.changeChaosByCount(0.04);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,8 @@ export function createContracts(): Record<BladeburnerContractName, Contract> {
|
||||
name: BladeburnerContractName.Tracking,
|
||||
desc:
|
||||
"Identify and locate Synthoids. This contract involves reconnaissance and information-gathering ONLY. Do NOT " +
|
||||
"engage. Stealth is of the utmost importance.\n\n" +
|
||||
"Successfully completing Tracking contracts will slightly improve your Synthoid population estimate for whatever " +
|
||||
"city you are currently in.",
|
||||
"engage. Stealth is of the utmost importance.\n" +
|
||||
"Successfully completing this contract will slightly improve the Synthoid population estimate of your current city.",
|
||||
successScaling:
|
||||
"Significantly affected by Dexterity and Agility. Minor bonus from combat stats and Charisma. Unaffected by Hacking skill.",
|
||||
baseDifficulty: 125,
|
||||
@ -44,9 +43,8 @@ export function createContracts(): Record<BladeburnerContractName, Contract> {
|
||||
[BladeburnerContractName.BountyHunter]: new Contract({
|
||||
name: BladeburnerContractName.BountyHunter,
|
||||
desc:
|
||||
"Hunt down and capture fugitive Synthoids. These Synthoids are wanted alive.\n\n" +
|
||||
"Successfully completing a Bounty Hunter contract will lower the population in your current city, and will also " +
|
||||
"increase its chaos level.",
|
||||
"Hunt down and capture fugitive Synthoids. These Synthoids are wanted alive.\n" +
|
||||
"Successfully completing this contract will decrease the Synthoid population of your current city and increase its chaos level.",
|
||||
successScaling:
|
||||
"Significantly affected by Dexterity and Agility. Minor bonus from combat stats and Charisma. Unaffected by Hacking skill.",
|
||||
baseDifficulty: 250,
|
||||
@ -79,9 +77,8 @@ export function createContracts(): Record<BladeburnerContractName, Contract> {
|
||||
[BladeburnerContractName.Retirement]: new Contract({
|
||||
name: BladeburnerContractName.Retirement,
|
||||
desc:
|
||||
"Hunt down and retire (kill) rogue Synthoids.\n\n" +
|
||||
"Successfully completing a Retirement contract will lower the population in your current city, and will also " +
|
||||
"increase its chaos level.",
|
||||
"Hunt down and retire (kill) rogue Synthoids.\n" +
|
||||
"Successfully completing this contract will decrease the Synthoid population of your current city and increase its chaos level.",
|
||||
successScaling: "Affected by combat stats. Minor bonus from Charisma. Unaffected by Hacking skill.",
|
||||
baseDifficulty: 200,
|
||||
difficultyFac: 1.03,
|
||||
|
@ -16,7 +16,7 @@ export const GeneralActions: Record<BladeburnerGeneralActionName, GeneralAction>
|
||||
desc:
|
||||
"Mine and analyze Synthoid-related data. This improves the Bladeburner unit's intelligence on Synthoid locations " +
|
||||
"and activities. Completing this action will improve the accuracy of your Synthoid population estimated in the " +
|
||||
"current city.\n\n" +
|
||||
"current city.\n" +
|
||||
"Does NOT require stamina.",
|
||||
}),
|
||||
[BladeburnerGeneralActionName.Recruitment]: new GeneralAction({
|
||||
@ -30,7 +30,7 @@ export const GeneralActions: Record<BladeburnerGeneralActionName, GeneralAction>
|
||||
return Math.pow(person.skills.charisma, 0.45) / (bladeburner.teamSize - bladeburner.sleeveSize + 1);
|
||||
},
|
||||
desc:
|
||||
"Attempt to recruit members for your Bladeburner team. These members can help you conduct operations.\n\n" +
|
||||
"Attempt to recruit members for your Bladeburner team. These members can help you conduct operations.\n" +
|
||||
"Does NOT require stamina.",
|
||||
successScaling: "Success chance is affected by Charisma.",
|
||||
}),
|
||||
@ -38,8 +38,8 @@ export const GeneralActions: Record<BladeburnerGeneralActionName, GeneralAction>
|
||||
name: BladeburnerGeneralActionName.Diplomacy,
|
||||
getActionTime: () => 60,
|
||||
desc:
|
||||
"Improve diplomatic relations with the Synthoid population. Completing this action will reduce the Chaos level in " +
|
||||
"your current city.\n\n" +
|
||||
"Improve diplomatic relations with the Synthoid population. Completing this action will reduce the chaos level of " +
|
||||
"your current city.\n" +
|
||||
"Does NOT require stamina.",
|
||||
}),
|
||||
[BladeburnerGeneralActionName.HyperbolicRegen]: new GeneralAction({
|
||||
@ -54,6 +54,8 @@ export const GeneralActions: Record<BladeburnerGeneralActionName, GeneralAction>
|
||||
getActionTime: () => 60,
|
||||
desc:
|
||||
"Purposefully stir trouble in the synthoid community in order to gain a political edge. This will generate " +
|
||||
"additional contracts and operations, at the cost of increased Chaos.",
|
||||
"additional contracts and operations at the cost of increasing the chaos level of all cities.\n" +
|
||||
"Does NOT require stamina.",
|
||||
warning: "This action increases chaos of all cities by percentage.",
|
||||
}),
|
||||
};
|
||||
|
@ -9,8 +9,8 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
[BladeburnerOperationName.Investigation]: new Operation({
|
||||
name: BladeburnerOperationName.Investigation,
|
||||
desc:
|
||||
"As a field agent, investigate and identify Synthoid populations, movements, and operations.\n\n" +
|
||||
"Successful Investigation ops will increase the accuracy of your synthoid data.\n\n" +
|
||||
"As a field agent, investigate and identify Synthoid populations, movements, and operations.\n" +
|
||||
"Successful Investigation ops will increase the accuracy of your synthoid data.\n" +
|
||||
"You will NOT lose HP from failed Investigation ops.",
|
||||
successScaling: "Significantly affected by Hacking skill and Charisma. Minor bonus from combat stats.",
|
||||
baseDifficulty: 400,
|
||||
@ -43,7 +43,7 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
[BladeburnerOperationName.Undercover]: new Operation({
|
||||
name: BladeburnerOperationName.Undercover,
|
||||
desc:
|
||||
"Conduct undercover operations to identify hidden and underground Synthoid communities and organizations.\n\n" +
|
||||
"Conduct undercover operations to identify hidden and underground Synthoid communities and organizations.\n" +
|
||||
"Successful Undercover ops will increase the accuracy of your synthoid data.",
|
||||
successScaling:
|
||||
"Affected by Hacking skill, Dexterity, Agility and Charisma. Minor bonus from Defense and Strength.",
|
||||
@ -77,7 +77,10 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
}),
|
||||
[BladeburnerOperationName.Sting]: new Operation({
|
||||
name: BladeburnerOperationName.Sting,
|
||||
desc: "Conduct a sting operation to bait and capture particularly notorious Synthoid criminals.",
|
||||
desc:
|
||||
"Conduct a sting operation to bait and capture particularly notorious Synthoid criminals.\n" +
|
||||
"Completing this operation will increase the chaos level of your current city. If you complete it successfully, it will decrease the Synthoid population of your current city.",
|
||||
warning: "This action decreases population by percentage.",
|
||||
successScaling:
|
||||
"Significantly affected by Hacking skill and Dexterity. Major bonus from Charisma. Minor bonus from combat stats.",
|
||||
baseDifficulty: 650,
|
||||
@ -111,7 +114,9 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
name: BladeburnerOperationName.Raid,
|
||||
desc:
|
||||
"Lead an assault on a known Synthoid community. Note that there must be an existing Synthoid community in your " +
|
||||
"current city in order for this Operation to be successful.",
|
||||
"current city in order for this Operation to be successful.\n" +
|
||||
"Completing this operation will decrease the Synthoid population of your current city and increase its chaos level.",
|
||||
warning: "This action decreases population and increases chaos by percentage.",
|
||||
successScaling: "Affected by combat stats. Minor bonus from Hacking skill. Unaffected by Charisma.",
|
||||
baseDifficulty: 800,
|
||||
difficultyFac: 1.045,
|
||||
@ -148,7 +153,9 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
name: BladeburnerOperationName.StealthRetirement,
|
||||
desc:
|
||||
"Lead a covert operation to retire Synthoids. The objective is to complete the task without drawing any " +
|
||||
"attention. Stealth and discretion are key.",
|
||||
"attention. Stealth and discretion are key.\n" +
|
||||
"Completing this operation will DECREASE the chaos level of your current city. If you complete it successfully, it will decrease the Synthoid population of your current city.",
|
||||
warning: "This action decreases population by percentage.",
|
||||
successScaling:
|
||||
"Significantly affected by Dexterity and Agility. Minor bonus from combat stats and Hacking skill. Unaffected by Charisma.",
|
||||
baseDifficulty: 1000,
|
||||
@ -183,7 +190,9 @@ export function createOperations(): Record<BladeburnerOperationName, Operation>
|
||||
name: BladeburnerOperationName.Assassination,
|
||||
desc:
|
||||
"Assassinate Synthoids that have been identified as important, high-profile social and political leaders in the " +
|
||||
"Synthoid communities.",
|
||||
"Synthoid communities.\n" +
|
||||
"Completing this operation may increase the chaos level of your current city. If you complete it successfully, it will decrease the Synthoid population of your current city.",
|
||||
warning: "This action may increase chaos by percentage.",
|
||||
successScaling:
|
||||
"Significantly affected by Dexterity and Agility. Minor bonus from combat stats and Hacking skill.\n" +
|
||||
"Unaffected by Charisma.",
|
||||
|
@ -2,7 +2,7 @@ import type { Bladeburner } from "../Bladeburner";
|
||||
import type { Action } from "../Types";
|
||||
|
||||
import React from "react";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, Tooltip, Typography } from "@mui/material";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import { StartButton } from "./StartButton";
|
||||
@ -13,6 +13,8 @@ import { formatNumberNoSuffix } from "../../ui/formatNumber";
|
||||
import { BlackOperation, Operation } from "../Actions";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import WarningIcon from "@mui/icons-material/Warning";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
interface ActionHeaderProps {
|
||||
bladeburner: Bladeburner;
|
||||
@ -87,6 +89,13 @@ export function ActionHeader({ bladeburner, action, rerender }: ActionHeaderProp
|
||||
return (
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<CopyableText value={action.name} />
|
||||
{action.warning && (
|
||||
<Tooltip title={action.warning} sx={{ marginLeft: "10px" }}>
|
||||
<Typography color={Settings.theme.warning}>
|
||||
<WarningIcon />
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
)}
|
||||
<StartButton bladeburner={bladeburner} action={action} rerender={rerender} />
|
||||
{allowTeam && <TeamSizeButton bladeburner={bladeburner} action={action} />}
|
||||
</Box>
|
||||
|
@ -2,14 +2,13 @@ import type { Bladeburner } from "../Bladeburner";
|
||||
import type { GeneralAction } from "../Actions/GeneralAction";
|
||||
|
||||
import React from "react";
|
||||
import { formatNumberNoSuffix } from "../../ui/formatNumber";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { Player } from "@player";
|
||||
import { Paper, Typography } from "@mui/material";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { ActionHeader } from "./ActionHeader";
|
||||
import { BladeburnerGeneralActionName } from "@enums";
|
||||
import { clampNumber } from "../../utils/helpers/clampNumber";
|
||||
import { SuccessChance } from "./SuccessChance";
|
||||
|
||||
interface GeneralActionElemProps {
|
||||
bladeburner: Bladeburner;
|
||||
@ -24,15 +23,14 @@ export function GeneralActionElem({ bladeburner, action }: GeneralActionElemProp
|
||||
<Paper sx={{ my: 1, p: 1 }}>
|
||||
<ActionHeader bladeburner={bladeburner} action={action} rerender={rerender}></ActionHeader>
|
||||
<br />
|
||||
<Typography>{action.desc}</Typography>
|
||||
<Typography whiteSpace={"pre-wrap"}>{action.desc}</Typography>
|
||||
<br />
|
||||
<Typography>
|
||||
Time Required: {convertTimeMsToTimeElapsedString(actionTime * 1000)}
|
||||
{action.name === BladeburnerGeneralActionName.Recruitment && (
|
||||
<>
|
||||
<br />
|
||||
Estimated success chance:{" "}
|
||||
{formatNumberNoSuffix(clampNumber(action.getSuccessChance(bladeburner, Player), 0, 1) * 100, 1)}%
|
||||
<SuccessChance action={action} bladeburner={bladeburner} />
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
|
@ -13,6 +13,8 @@ import { Factions } from "../../Faction/Factions";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { TravelModal } from "./TravelModal";
|
||||
import WarningIcon from "@mui/icons-material/Warning";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
interface StatsProps {
|
||||
bladeburner: Bladeburner;
|
||||
@ -29,6 +31,35 @@ export function Stats({ bladeburner }: StatsProps): React.ReactElement {
|
||||
if (success) Router.toPage(Page.Faction, { faction: Factions[FactionName.Bladeburners] });
|
||||
}
|
||||
|
||||
let populationTextColor = Settings.theme.primary;
|
||||
let populationWarning: string | null = null;
|
||||
/**
|
||||
* The initial population is randomized between 1e9 and 1.5e9. If it drops below 1e9, the success chance is reduced.
|
||||
* We use 2 thresholds:
|
||||
* - 8e8: The success chance is reduced by ~15%. On average, random events usually do not reduce the population to
|
||||
* this low number.
|
||||
* - 1e8: The success chance is reduced by ~80%. If the population is reduced to this number, it's very likely that
|
||||
* the player is performing actions that decrease the population by percentage.
|
||||
*/
|
||||
if (bladeburner.getCurrentCity().pop <= 1e8) {
|
||||
populationTextColor = Settings.theme.error;
|
||||
populationWarning = "extremely low";
|
||||
} else if (bladeburner.getCurrentCity().pop < 9e8) {
|
||||
populationTextColor = Settings.theme.warning;
|
||||
populationWarning = "low";
|
||||
}
|
||||
|
||||
let chaosTextColor = Settings.theme.primary;
|
||||
let chaosWarning: string | null = null;
|
||||
// When chaos is 1e4, the success chance is reduced by ~99%.
|
||||
if (bladeburner.getCurrentCity().chaos >= 1e4) {
|
||||
chaosTextColor = Settings.theme.error;
|
||||
chaosWarning = "extremely high";
|
||||
} else if (bladeburner.getCurrentCity().chaos >= BladeburnerConstants.ChaosThreshold) {
|
||||
chaosTextColor = Settings.theme.warning;
|
||||
chaosWarning = "high";
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper sx={{ p: 1, overflowY: "auto", overflowX: "hidden", wordBreak: "break-all" }}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 1, maxHeight: "60vh" }}>
|
||||
@ -96,13 +127,30 @@ export function Stats({ bladeburner }: StatsProps): React.ReactElement {
|
||||
<Box display="flex">
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
This is your Bladeburner division's estimate of how many Synthoids exist in your current city. An
|
||||
accurate population count increases success rate estimates.
|
||||
<Typography component="div">
|
||||
<Typography>
|
||||
This is your Bladeburner division's estimate of how many Synthoids exist in your current city. An
|
||||
accurate population estimate increases success rate estimates.
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography>
|
||||
You should be careful with actions that decrease Synthoid population by percentage. Those actions can
|
||||
kill a large number of Synthoids in a short amount of time. Low population count decreases the success
|
||||
chance of most actions. If the population count is too low, you will need to move to another city.
|
||||
</Typography>
|
||||
{populationWarning && (
|
||||
<>
|
||||
<br />
|
||||
The intelligence agency notifies us that Synthoid population is {populationWarning}.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>Est. Synthoid Population: {formatPopulation(bladeburner.getCurrentCity().popEst)}</Typography>
|
||||
<Typography color={populationTextColor} display="flex">
|
||||
Est. Synthoid Population: {formatPopulation(bladeburner.getCurrentCity().popEst)}
|
||||
{populationWarning && <WarningIcon sx={{ marginLeft: "10px" }} />}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Box display="flex">
|
||||
@ -120,13 +168,24 @@ export function Stats({ bladeburner }: StatsProps): React.ReactElement {
|
||||
<Box display="flex">
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
The city's chaos level due to tensions and conflicts between humans and Synthoids. Having too high of a
|
||||
chaos level can make contracts and operations harder.
|
||||
<Typography component="div">
|
||||
<Typography>
|
||||
Tensions and conflicts between humans and Synthoids increase the city's chaos level. High chaos level
|
||||
makes contracts and operations harder.
|
||||
</Typography>
|
||||
{chaosWarning && (
|
||||
<>
|
||||
<br />
|
||||
Chaos level is {chaosWarning}.
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<Typography>City Chaos: {formatBigNumber(bladeburner.getCurrentCity().chaos)}</Typography>
|
||||
<Typography color={chaosTextColor} display="flex">
|
||||
City Chaos: {formatBigNumber(bladeburner.getCurrentCity().chaos)}
|
||||
{chaosWarning && <WarningIcon sx={{ marginLeft: "10px" }} />}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<br />
|
||||
|
@ -7,6 +7,7 @@ import { Player } from "@player";
|
||||
import { formatPercent } from "../../ui/formatNumber";
|
||||
import { StealthIcon } from "./StealthIcon";
|
||||
import { KillIcon } from "./KillIcon";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import { Tooltip, Typography } from "@mui/material";
|
||||
|
||||
interface SuccessChanceProps {
|
||||
@ -22,10 +23,10 @@ export function SuccessChance({ bladeburner, action }: SuccessChanceProps): Reac
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={action.successScaling ? <Typography>{action.successScaling}</Typography> : ""}>
|
||||
<span>
|
||||
<Typography component="span" sx={{ marginRight: "15px" }}>
|
||||
Estimated success chance: {chance}
|
||||
{/* Intentional space*/}{" "}
|
||||
</span>
|
||||
{action.successScaling && <InfoIcon sx={{ fontSize: "1.1rem", marginLeft: "10px" }} />}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
{action.isStealth ? <StealthIcon /> : <></>}
|
||||
{action.isKill ? <KillIcon /> : <></>}
|
||||
|
Loading…
Reference in New Issue
Block a user