mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-27 08:27:32 +01:00
Merge pull request #3131 from nickofolas/improvement/create-programs-ui
Refresh "Create Programs" page UI
This commit is contained in:
commit
80251818e0
@ -1,9 +1,19 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { use } from "../../ui/Context";
|
||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
||||
import { find } from "lodash";
|
||||
|
||||
import { Box, Tooltip, Typography } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Container,
|
||||
Paper
|
||||
} from "@mui/material";
|
||||
import { Check, Lock, Create } from "@mui/icons-material";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { Programs } from "../Programs";
|
||||
|
||||
export const ProgramsSeen: string[] = [];
|
||||
|
||||
@ -15,7 +25,20 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
const programs = getAvailableCreatePrograms(player);
|
||||
const programs = [...Object.values(Programs)]
|
||||
.filter(prog => {
|
||||
const create = prog.create;
|
||||
if (create === null) return false;
|
||||
if (prog.name === "b1t_flum3.exe") {
|
||||
return create.req(player);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (player.hasProgram(a.name)) return 1;
|
||||
if (player.hasProgram(b.name)) return -1;
|
||||
return (a.create?.level ?? 0) - (b.create?.level ?? 0);
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
programs.forEach((p) => {
|
||||
@ -29,8 +52,27 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const getHackingLevelRemaining = (lvl: number): number => {
|
||||
return Math.ceil(Math.max(lvl - (player.hacking + player.intelligence / 2), 0));
|
||||
}
|
||||
|
||||
const getProgCompletion = (name: string): number => {
|
||||
const programFile = find(player.getHomeComputer().programs, p => {
|
||||
return (p.startsWith(name) && p.endsWith("%-INC"));
|
||||
});
|
||||
if (!programFile) return -1;
|
||||
|
||||
const res = programFile.split("-");
|
||||
if (res.length != 3) return -1;
|
||||
const percComplete = Number(res[1].slice(0, -1));
|
||||
if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {
|
||||
return -1;
|
||||
}
|
||||
return percComplete;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
|
||||
<Typography variant="h4">Create program</Typography>
|
||||
<Typography>
|
||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
||||
@ -38,30 +80,45 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
time. Your progress will be saved and you can continue later.
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'grid', width: 'fit-content' }}>
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: "repeat(3, 1fr)", my: 1 }}>
|
||||
{programs.map((program) => {
|
||||
const create = program.create;
|
||||
if (create === null) return <></>;
|
||||
const curCompletion = getProgCompletion(program.name);
|
||||
|
||||
return (
|
||||
<React.Fragment key={program.name}>
|
||||
<Tooltip title={create.tooltip}>
|
||||
<Button
|
||||
sx={{ my: 1 }}
|
||||
onClick={(event) => {
|
||||
if (!event.isTrusted) return;
|
||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||
player.startFocusing();
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
{program.name}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</React.Fragment>
|
||||
<Box component={Paper} sx={{ p: 1, opacity: player.hasProgram(program.name) ? 0.75 : 1 }} key={program.name}>
|
||||
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
{player.hasProgram(program.name) && <Check sx={{ mr: 1 }} /> ||
|
||||
(create.req(player) && <Create sx={{ mr: 1 }} /> || <Lock sx={{ mr: 1 }} />)}
|
||||
{program.name}
|
||||
</Typography>
|
||||
{(!player.hasProgram(program.name) && create.req(player)) && <Button
|
||||
sx={{ my: 1, width: '100%' }}
|
||||
onClick={(event) => {
|
||||
if (!event.isTrusted) return;
|
||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||
player.startFocusing();
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
Create program
|
||||
</Button>}
|
||||
{(player.hasProgram(program.name) || getHackingLevelRemaining(create.level) === 0) ||
|
||||
<Typography color={Settings.theme.hack}>
|
||||
<b>Unlocks in:</b> {getHackingLevelRemaining(create.level)} hacking levels
|
||||
</Typography>}
|
||||
{(curCompletion !== -1) &&
|
||||
<Typography color={Settings.theme.infolight}>
|
||||
<b>Current completion:</b> {curCompletion}%
|
||||
</Typography>}
|
||||
<Typography>
|
||||
{create.tooltip}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -143,11 +143,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
const augmentationCount = props.player.queuedAugmentations.length;
|
||||
const invitationsCount = props.player.factionInvitations.filter((f) => !InvitationsSeen.includes(f)).length;
|
||||
const programCount = getAvailableCreatePrograms(props.player).length - ProgramsSeen.length;
|
||||
const canCreateProgram =
|
||||
getAvailableCreatePrograms(props.player).length > 0 ||
|
||||
props.player.augmentations.length > 0 ||
|
||||
props.player.queuedAugmentations.length > 0 ||
|
||||
props.player.sourceFiles.length > 0;
|
||||
|
||||
const canOpenFactions =
|
||||
props.player.factionInvitations.length > 0 ||
|
||||
@ -439,29 +434,27 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
{canCreateProgram && (
|
||||
<ListItem
|
||||
button
|
||||
key={"Create Program"}
|
||||
className={clsx({
|
||||
[classes.active]: props.page === Page.CreateProgram,
|
||||
})}
|
||||
onClick={clickCreateProgram}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||
<Tooltip title={!open ? "Create Program" : ""}>
|
||||
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
||||
</Tooltip>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
||||
Create Program
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
)}
|
||||
<ListItem
|
||||
button
|
||||
key={"Create Program"}
|
||||
className={clsx({
|
||||
[classes.active]: props.page === Page.CreateProgram,
|
||||
})}
|
||||
onClick={clickCreateProgram}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||
<Tooltip title={!open ? "Create Program" : ""}>
|
||||
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
||||
</Tooltip>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
||||
Create Program
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
{canStaneksGift && (
|
||||
<ListItem
|
||||
button
|
||||
|
Loading…
Reference in New Issue
Block a user