bitburner-src/src/Faction/ui/FactionsRoot.tsx

247 lines
8.6 KiB
TypeScript
Raw Normal View History

2022-05-20 21:46:45 +02:00
import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma } from "@mui/icons-material";
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
import React, { useEffect } from "react";
import { Player } from "@player";
2022-05-20 21:46:45 +02:00
import { Settings } from "../../Settings/Settings";
import { formatFavor, formatReputation } from "../../ui/formatNumber";
2022-09-06 15:07:12 +02:00
import { Router } from "../../ui/GameRoot";
import { FactionName } from "@enums";
import { Faction } from "../Faction";
2022-05-20 21:46:45 +02:00
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
import { Factions } from "../Factions";
import { useRerender } from "../../ui/React/hooks";
2021-09-20 07:18:20 +02:00
2021-10-23 21:22:58 +02:00
export const InvitationsSeen: string[] = [];
2022-05-20 21:46:45 +02:00
const fontSize = "small";
const marginRight = 0.5;
const WorkTypesOffered = (props: { faction: Faction }): React.ReactElement => {
2022-05-20 21:46:45 +02:00
const info = props.faction.getInfo();
return (
<>
{info.offerFieldWork && (
<Tooltip title="This Faction offers field work">
<Explore sx={{ color: Settings.theme.info, mr: marginRight }} fontSize={fontSize} />
</Tooltip>
)}
{info.offerHackingWork && (
<Tooltip title="This Faction offers hacking work">
<LastPage sx={{ color: Settings.theme.hack, mr: marginRight }} fontSize={fontSize} />
</Tooltip>
)}
{info.offerSecurityWork && (
<Tooltip title="This Faction offers security work">
<LocalPolice sx={{ color: Settings.theme.combat, mr: marginRight }} fontSize={fontSize} />
</Tooltip>
)}
</>
);
};
interface FactionElementProps {
2022-05-20 21:46:45 +02:00
faction: Faction;
/** Whether the player is a member of this faction already */
2022-05-20 21:46:45 +02:00
joined: boolean;
/** Rerender function to force the entire FactionsRoot to rerender */
2022-05-20 21:46:45 +02:00
rerender: () => void;
}
const FactionElement = (props: FactionElementProps): React.ReactElement => {
2022-05-20 21:46:45 +02:00
const facInfo = props.faction.getInfo();
const augsLeft = getFactionAugmentationsFiltered(props.faction).filter((aug) => !Player.hasAugmentation(aug)).length;
2022-05-20 21:46:45 +02:00
function openFaction(faction: Faction): void {
2022-09-06 15:07:12 +02:00
Router.toFaction(faction);
2022-05-20 21:46:45 +02:00
}
function openFactionAugPage(faction: Faction): void {
2022-09-06 15:07:12 +02:00
Router.toFaction(faction, true);
2022-05-20 21:46:45 +02:00
}
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement>, faction: string): void {
2022-05-20 21:46:45 +02:00
if (!event.isTrusted) return;
joinFaction(Factions[faction]);
props.rerender();
}
return (
<Paper
sx={{
display: "grid",
p: 1,
alignItems: "center",
gridTemplateColumns: "minmax(0, 4fr)" + (props.joined ? " 1fr" : ""),
}}
>
<Box display="flex" sx={{ alignItems: "center" }}>
{props.joined ? (
<Box
display="grid"
sx={{
mr: 1,
gridTemplateColumns: "1fr 1fr",
minWidth: "fit-content",
gap: 0.5,
"& .MuiButton-root": { height: "48px" },
}}
>
<Button onClick={() => openFaction(props.faction)}>Details</Button>
<Button onClick={() => openFactionAugPage(props.faction)}>Augments</Button>
</Box>
) : (
<Button sx={{ height: "48px", mr: 1 }} onClick={(e) => acceptInvitation(e, props.faction.name)}>
Join!
</Button>
)}
<span style={{ maxWidth: props.joined ? "70%" : "95%" }}>
<Typography
variant="h6"
sx={{
mr: 1,
display: "grid",
gridTemplateColumns: "fit-content(100vw) max-content",
alignItems: "center",
}}
>
<Tooltip title={props.faction.name}>
<span style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>
{props.faction.name}
</span>
</Tooltip>
2022-05-20 21:46:45 +02:00
<span style={{ display: "flex", alignItems: "center" }}>
2022-09-06 15:07:12 +02:00
{Player.hasGangWith(props.faction.name) && (
2022-05-20 21:46:45 +02:00
<Tooltip title="You have a gang with this Faction">
<SportsMma sx={{ color: Settings.theme.hp, ml: 1 }} />
</Tooltip>
)}
{facInfo.special && (
<Tooltip title="This is a special Faction">
<NewReleases sx={{ ml: 1, color: Settings.theme.money, transform: "rotate(180deg)" }} />
</Tooltip>
)}
{!props.joined && facInfo.enemies.length > 0 && (
<Tooltip
title={
<Typography>
This Faction is enemies with:
<ul>
{facInfo.enemies.map((enemy) => (
<li key={enemy}>{enemy}</li>
))}
</ul>
Joining this Faction will prevent you from joining its enemies
</Typography>
}
>
<Report sx={{ ml: 1, color: Settings.theme.error }} />
</Tooltip>
)}
</span>
</Typography>
<span style={{ display: "flex", alignItems: "center" }}>
2022-09-06 15:07:12 +02:00
{!Player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
<Typography variant="body2" sx={{ display: "flex" }}>{`${augsLeft || "No"} Augmentations left`}</Typography>
2022-05-20 21:46:45 +02:00
</span>
</span>
</Box>
{props.joined && (
<Box display="grid" sx={{ alignItems: "center", justifyItems: "left", gridAutoFlow: "row" }}>
<Typography sx={{ color: Settings.theme.rep }}>
{formatFavor(Math.floor(props.faction.favor))} favor
2022-05-20 21:46:45 +02:00
</Typography>
<Typography sx={{ color: Settings.theme.rep }}>
{formatReputation(props.faction.playerReputation)} rep
2022-05-20 21:46:45 +02:00
</Typography>
</Box>
)}
</Paper>
);
};
2022-09-06 15:07:12 +02:00
export function FactionsRoot(): React.ReactElement {
2022-05-20 21:46:45 +02:00
const theme = useTheme();
const rerender = useRerender(200);
2021-10-23 21:22:58 +02:00
useEffect(() => {
2022-09-06 15:07:12 +02:00
Player.factionInvitations.forEach((faction) => {
2021-10-23 21:22:58 +02:00
if (InvitationsSeen.includes(faction)) return;
InvitationsSeen.push(faction);
});
}, []);
const allFactions = Object.values(FactionName).map((faction) => faction as string);
2022-09-06 15:07:12 +02:00
const allJoinedFactions = [...Player.factions];
2022-03-23 17:17:03 +01:00
allJoinedFactions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
2022-09-06 15:07:12 +02:00
const invitations = Player.factionInvitations;
2021-09-05 01:09:30 +02:00
return (
2022-05-20 21:46:45 +02:00
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
<Typography variant="h4">
Factions
<Tooltip
title={
<Typography>
Throughout the game you may receive invitations from factions. There are many different factions, and each
faction has different criteria for determining its potential members. Joining a faction and furthering its
cause is crucial to progressing in the game and unlocking endgame content.
</Typography>
}
>
<Info sx={{ ml: 1, mb: 0 }} color="info" />
</Tooltip>
</Typography>
2022-05-20 21:46:45 +02:00
<Box
display="grid"
sx={{
gap: 1,
gridTemplateColumns: (invitations.length > 0 ? "1fr " : "") + "2fr",
2022-07-21 21:24:03 +02:00
[theme.breakpoints.down("lg")]: { gridTemplateColumns: "1fr", "& > span:nth-of-type(1)": { order: 1 } },
2022-05-20 21:46:45 +02:00
gridTemplateRows: "minmax(0, 1fr)",
"& > span > .MuiBox-root": {
display: "grid",
gridAutoRows: "70px",
gap: 1,
},
}}
>
{invitations.length > 0 && (
<span>
<Typography variant="h5" color="primary">
Faction Invitations
</Typography>
<Box>
{invitations.map((facName) => {
if (!Object.hasOwn(Factions, facName)) return null;
2022-09-06 15:07:12 +02:00
return <FactionElement key={facName} faction={Factions[facName]} joined={false} rerender={rerender} />;
2022-05-20 21:46:45 +02:00
})}
</Box>
</span>
)}
<span>
<Typography variant="h5" color="primary">
Your Factions
</Typography>
<Box>
{allJoinedFactions.length > 0 ? (
allJoinedFactions.map((facName) => {
if (!Object.hasOwn(Factions, facName)) return null;
2022-09-06 15:07:12 +02:00
return <FactionElement key={facName} faction={Factions[facName]} joined={true} rerender={rerender} />;
2022-05-20 21:46:45 +02:00
})
) : (
<Typography>You have not yet joined any Factions.</Typography>
)}
</Box>
</span>
</Box>
</Container>
2021-09-05 01:09:30 +02:00
);
}