mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
Merge branch 'dev' of https://github.com/deathly809/bitburner into dev
This commit is contained in:
commit
0002daa3e9
8
.github/ISSUE_TEMPLATE
vendored
Normal file
8
.github/ISSUE_TEMPLATE
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# include (where relevant)
|
||||||
|
|
||||||
|
You can delete this section
|
||||||
|
|
||||||
|
- [ ] Save file
|
||||||
|
- [ ] Minimal scripts to reproduce the issue
|
||||||
|
- [ ] Steps to reproduce
|
||||||
|
- [ ] Version of the game, e.g. Bitburner v1.3.0 (216bf616)
|
9
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
9
.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Documentation
|
||||||
|
|
||||||
|
- DO NOT CHANGE any markdown/\*.md, these files are autogenerated from NetscriptDefinitions.d.ts and will be overwritten
|
||||||
|
- DO NOT re-generate the documentation, makes it harder to review.
|
||||||
|
|
||||||
|
# Bug fix
|
||||||
|
|
||||||
|
- Include how it was tested
|
||||||
|
- Include screenshot / gif (if possible)
|
34
dist/vendor.bundle.js
vendored
34
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -3,6 +3,9 @@ const greenworks = require("./greenworks");
|
|||||||
const log = require("electron-log");
|
const log = require("electron-log");
|
||||||
|
|
||||||
function enableAchievementsInterval(window) {
|
function enableAchievementsInterval(window) {
|
||||||
|
// If the Steam API could not be initialized on game start, we'll abort this.
|
||||||
|
if (global.greenworksError) return;
|
||||||
|
|
||||||
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
|
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
|
||||||
// here. Hey if it works it works.
|
// here. Hey if it works it works.
|
||||||
const steamAchievements = greenworks.getAchievementNames();
|
const steamAchievements = greenworks.getAchievementNames();
|
||||||
|
@ -16,10 +16,18 @@ process.on('uncaughtException', function () {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (greenworks.init()) {
|
// We want to fail gracefully if we cannot connect to Steam
|
||||||
|
try {
|
||||||
|
if (greenworks.init()) {
|
||||||
log.info("Steam API has been initialized.");
|
log.info("Steam API has been initialized.");
|
||||||
} else {
|
} else {
|
||||||
log.warn("Steam API has failed to initialize.");
|
const error = "Steam API has failed to initialize.";
|
||||||
|
log.warn(error);
|
||||||
|
global.greenworksError = error;
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
log.warn(ex.message);
|
||||||
|
global.greenworksError = ex.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStopProcessHandler(app, window, enabled) {
|
function setStopProcessHandler(app, window, enabled) {
|
||||||
@ -113,4 +121,13 @@ app.whenReady().then(async () => {
|
|||||||
} else {
|
} else {
|
||||||
startWindow(process.argv.includes("--no-scripts"));
|
startWindow(process.argv.includes("--no-scripts"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (global.greenworksError) {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
title: 'Bitburner',
|
||||||
|
message: 'Could not connect to Steam',
|
||||||
|
detail: `${global.greenworksError}\n\nYou won't be able to receive achievements until this is resolved and you restart the game.`,
|
||||||
|
type: 'warning', buttons: ['OK']
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
23
markdown/bitburner.userinterface.getstyles.md
Normal file
23
markdown/bitburner.userinterface.getstyles.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [UserInterface](./bitburner.userinterface.md) > [getStyles](./bitburner.userinterface.getstyles.md)
|
||||||
|
|
||||||
|
## UserInterface.getStyles() method
|
||||||
|
|
||||||
|
Get the current styles
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
getStyles(): IStyleSettings;
|
||||||
|
```
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
IStyleSettings
|
||||||
|
|
||||||
|
An object containing the player's styles
|
||||||
|
|
||||||
|
## Remarks
|
||||||
|
|
||||||
|
RAM cost: cost: 0 GB
|
||||||
|
|
@ -16,7 +16,10 @@ interface UserInterface
|
|||||||
|
|
||||||
| Method | Description |
|
| Method | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
| [getStyles()](./bitburner.userinterface.getstyles.md) | Get the current styles |
|
||||||
| [getTheme()](./bitburner.userinterface.gettheme.md) | Get the current theme |
|
| [getTheme()](./bitburner.userinterface.gettheme.md) | Get the current theme |
|
||||||
|
| [resetStyles()](./bitburner.userinterface.resetstyles.md) | Resets the player's styles to the default values |
|
||||||
| [resetTheme()](./bitburner.userinterface.resettheme.md) | Resets the player's theme to the default values |
|
| [resetTheme()](./bitburner.userinterface.resettheme.md) | Resets the player's theme to the default values |
|
||||||
|
| [setStyles(newStyles)](./bitburner.userinterface.setstyles.md) | Sets the current styles |
|
||||||
| [setTheme(newTheme)](./bitburner.userinterface.settheme.md) | Sets the current theme |
|
| [setTheme(newTheme)](./bitburner.userinterface.settheme.md) | Sets the current theme |
|
||||||
|
|
||||||
|
21
markdown/bitburner.userinterface.resetstyles.md
Normal file
21
markdown/bitburner.userinterface.resetstyles.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [UserInterface](./bitburner.userinterface.md) > [resetStyles](./bitburner.userinterface.resetstyles.md)
|
||||||
|
|
||||||
|
## UserInterface.resetStyles() method
|
||||||
|
|
||||||
|
Resets the player's styles to the default values
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
resetStyles(): void;
|
||||||
|
```
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
void
|
||||||
|
|
||||||
|
## Remarks
|
||||||
|
|
||||||
|
RAM cost: cost: 0 GB
|
||||||
|
|
38
markdown/bitburner.userinterface.setstyles.md
Normal file
38
markdown/bitburner.userinterface.setstyles.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [UserInterface](./bitburner.userinterface.md) > [setStyles](./bitburner.userinterface.setstyles.md)
|
||||||
|
|
||||||
|
## UserInterface.setStyles() method
|
||||||
|
|
||||||
|
Sets the current styles
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
setStyles(newStyles: IStyleSettings): void;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| newStyles | IStyleSettings | |
|
||||||
|
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
void
|
||||||
|
|
||||||
|
## Remarks
|
||||||
|
|
||||||
|
RAM cost: cost: 0 GB
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Usage example (NS2)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const styles = ns.ui.getStyles();
|
||||||
|
styles.fontFamily = 'Comic Sans Ms';
|
||||||
|
ns.ui.setStyles(styles);
|
||||||
|
```
|
||||||
|
|
@ -2582,7 +2582,6 @@ function installAugmentations(): boolean {
|
|||||||
augmentationList += aug.name + level + "<br>";
|
augmentationList += aug.name + level + "<br>";
|
||||||
}
|
}
|
||||||
Player.queuedAugmentations = [];
|
Player.queuedAugmentations = [];
|
||||||
|
|
||||||
dialogBoxCreate(
|
dialogBoxCreate(
|
||||||
"You slowly drift to sleep as scientists put you under in order " +
|
"You slowly drift to sleep as scientists put you under in order " +
|
||||||
"to install the following Augmentations:<br>" +
|
"to install the following Augmentations:<br>" +
|
||||||
|
@ -12,7 +12,7 @@ export const ConsoleHelpText: {
|
|||||||
} = {
|
} = {
|
||||||
helpList: [
|
helpList: [
|
||||||
"Use 'help [command]' to get more information about a particular Bladeburner console command.",
|
"Use 'help [command]' to get more information about a particular Bladeburner console command.",
|
||||||
"",
|
" ",
|
||||||
" automate [var] [val] [hi/low] Configure simple automation for Bladeburner tasks",
|
" automate [var] [val] [hi/low] Configure simple automation for Bladeburner tasks",
|
||||||
" clear/cls Clear the console",
|
" clear/cls Clear the console",
|
||||||
" help [cmd] Display this help text, or help text for a specific command",
|
" help [cmd] Display this help text, or help text for a specific command",
|
||||||
@ -20,96 +20,103 @@ export const ConsoleHelpText: {
|
|||||||
" skill [action] [name] Level or display info about your Bladeburner skills",
|
" skill [action] [name] Level or display info about your Bladeburner skills",
|
||||||
" start [type] [name] Start a Bladeburner action/task",
|
" start [type] [name] Start a Bladeburner action/task",
|
||||||
" stop Stops your current Bladeburner action/task",
|
" stop Stops your current Bladeburner action/task",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
automate: [
|
automate: [
|
||||||
"automate [var] [val] [hi/low]",
|
"Usage: automate [var] [val] [hi/low]",
|
||||||
"",
|
" ",
|
||||||
"A simple way to automate your Bladeburner actions. This console command can be used " +
|
"A simple way to automate your Bladeburner actions. This console command can be used " +
|
||||||
"to automatically start an action when your stamina rises above a certain threshold, and " +
|
"to automatically start an action when your stamina rises above a certain threshold, and " +
|
||||||
"automatically switch to another action when your stamina drops below another threshold.",
|
"automatically switch to another action when your stamina drops below another threshold.",
|
||||||
|
" ",
|
||||||
" automate status - Check the current status of your automation and get a brief description of what it'll do",
|
" automate status - Check the current status of your automation and get a brief description of what it'll do",
|
||||||
" automate en - Enable the automation feature",
|
" automate en - Enable the automation feature",
|
||||||
" automate dis - Disable the automation feature",
|
" automate dis - Disable the automation feature",
|
||||||
"",
|
" ",
|
||||||
"There are four properties that must be set for this automation to work properly. Here is how to set them:",
|
"There are four properties that must be set for this automation to work properly. Here is how to set them:",
|
||||||
"",
|
" ",
|
||||||
" automate stamina 100 high",
|
" automate stamina 100 high",
|
||||||
" automate contract Tracking high",
|
" automate contract Tracking high",
|
||||||
" automate stamina 50 low",
|
" automate stamina 50 low",
|
||||||
" automate general 'Field Analysis' low",
|
" automate general 'Field Analysis' low",
|
||||||
"",
|
" ",
|
||||||
"Using the four console commands above will set the automation to perform Tracking contracts " +
|
"Using the four console commands above will set the automation to perform Tracking contracts " +
|
||||||
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
|
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
|
||||||
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
|
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
|
||||||
"exactly match whatever the name is in the UI.",
|
"exactly match whatever the name is in the UI.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
clear: ["clear", "", "Clears the console"],
|
clear: ["Usage: clear", " ", "Clears the console", " "],
|
||||||
cls: ["cls", "", "Clears the console"],
|
cls: ["Usage: cls", " ", "Clears the console", " "],
|
||||||
help: [
|
help: [
|
||||||
"help [command]",
|
"Usage: help [command]",
|
||||||
"",
|
" ",
|
||||||
"Running 'help' with no arguments displays the general help text, which lists all console commands " +
|
"Running 'help' with no arguments displays the general help text, which lists all console commands " +
|
||||||
"and a brief description of what they do. A command can be specified to get more specific help text " +
|
"and a brief description of what they do. A command can be specified to get more specific help text " +
|
||||||
"about that particular command. For example:",
|
"about that particular command. For example:",
|
||||||
"",
|
" ",
|
||||||
" help automate",
|
" help automate",
|
||||||
"",
|
" ",
|
||||||
"will display specific information about using the automate console command",
|
"will display specific information about using the automate console command",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
log: [
|
log: [
|
||||||
"log [en/dis] [type]",
|
"Usage: log [en/dis] [type]",
|
||||||
"",
|
" ",
|
||||||
"Enable or disable logging. By default, the results of completing actions such as contracts/operations are logged " +
|
"Enable or disable logging. By default, the results of completing actions such as contracts/operations are logged " +
|
||||||
"in the console. There are also random events that are logged in the console as well. The five categories of " +
|
"in the console. There are also random events that are logged in the console as well. The five categories of " +
|
||||||
"things that get logged are:",
|
"things that get logged are:",
|
||||||
"",
|
" ",
|
||||||
"[general, contracts, ops, blackops, events]",
|
"[general, contracts, ops, blackops, events]",
|
||||||
"",
|
" ",
|
||||||
"The logging for these categories can be enabled or disabled like so:",
|
"The logging for these categories can be enabled or disabled like so:",
|
||||||
"",
|
" ",
|
||||||
" log dis contracts - Disables logging that occurs when contracts are completed",
|
" log dis contracts - Disables logging that occurs when contracts are completed",
|
||||||
" log en contracts - Enables logging that occurs when contracts are completed",
|
" log en contracts - Enables logging that occurs when contracts are completed",
|
||||||
" log dis events - Disables logging for Bladeburner random events",
|
" log dis events - Disables logging for Bladeburner random events",
|
||||||
"",
|
" ",
|
||||||
"Logging can be universally enabled/disabled using the 'all' keyword:",
|
"Logging can be universally enabled/disabled using the 'all' keyword:",
|
||||||
"",
|
" ",
|
||||||
" log dis all",
|
" log dis all",
|
||||||
" log en all",
|
" log en all",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
skill: [
|
skill: [
|
||||||
"skill [action] [name]",
|
"Usage: skill [action] [name]",
|
||||||
"",
|
" ",
|
||||||
"Level or display information about your skills.",
|
"Level or display information about your skills.",
|
||||||
"",
|
" ",
|
||||||
"To display information about all of your skills and your multipliers, use:",
|
"To display information about all of your skills and your multipliers, use:",
|
||||||
"",
|
" ",
|
||||||
" skill list",
|
" skill list",
|
||||||
"",
|
" ",
|
||||||
"To display information about a specific skill, specify the name of the skill afterwards. " +
|
"To display information about a specific skill, specify the name of the skill afterwards. " +
|
||||||
"Note that the name of the skill is case-sensitive. Enter it exactly as seen in the UI. If " +
|
"Note that the name of the skill is case-sensitive. Enter it exactly as seen in the UI. If " +
|
||||||
"the name of the skill has whitespace, enclose the name of the skill in double quotation marks:",
|
"the name of the skill has whitespace, enclose the name of the skill in double quotation marks:",
|
||||||
"",
|
" ",
|
||||||
" skill list Reaper",
|
" skill list Reaper",
|
||||||
" skill list 'Digital Observer'",
|
" skill list 'Digital Observer'",
|
||||||
"",
|
" ",
|
||||||
"This console command can also be used to level up skills:",
|
"This console command can also be used to level up skills:",
|
||||||
"",
|
" ",
|
||||||
" skill level [skill name]",
|
" skill level [skill name]",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
start: [
|
start: [
|
||||||
"start [type] [name]",
|
"Usage: start [type] [name]",
|
||||||
"",
|
" ",
|
||||||
"Start an action. An action is specified by its type and its name. The " +
|
"Start an action. An action is specified by its type and its name. The " +
|
||||||
"name is case-sensitive. It must appear exactly as it does in the UI. If " +
|
"name is case-sensitive. It must appear exactly as it does in the UI. If " +
|
||||||
"the name of the action has whitespace, enclose it in double quotation marks. " +
|
"the name of the action has whitespace, enclose it in double quotation marks. " +
|
||||||
"Valid action types include:",
|
"Valid action types include:",
|
||||||
"",
|
" ",
|
||||||
"[general, contract, op, blackop]",
|
"[general, contract, op, blackop]",
|
||||||
"",
|
" ",
|
||||||
"Examples:",
|
"Examples:",
|
||||||
"",
|
" ",
|
||||||
" start contract Tracking",
|
" start contract Tracking",
|
||||||
" start op 'Undercover Operation'",
|
" start op 'Undercover Operation'",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
stop: ["stop", "", "Stop your current action and go idle."],
|
stop: ["Usage: stop", " ", "Stop your current action and go idle.", " "],
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,6 @@ import { Console } from "./Console";
|
|||||||
import { AllPages } from "./AllPages";
|
import { AllPages } from "./AllPages";
|
||||||
|
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
|
||||||
export function BladeburnerRoot(): React.ReactElement {
|
export function BladeburnerRoot(): React.ReactElement {
|
||||||
@ -24,14 +23,10 @@ export function BladeburnerRoot(): React.ReactElement {
|
|||||||
if (bladeburner === null) return <></>;
|
if (bladeburner === null) return <></>;
|
||||||
return (
|
return (
|
||||||
<Box display="flex" flexDirection="column">
|
<Box display="flex" flexDirection="column">
|
||||||
<Grid container>
|
<Box sx={{ display: "grid", gridTemplateColumns: "4fr 8fr", p: 1 }}>
|
||||||
<Grid item xs={6}>
|
|
||||||
<Stats bladeburner={bladeburner} player={player} router={router} />
|
<Stats bladeburner={bladeburner} player={player} router={router} />
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Console bladeburner={bladeburner} player={player} />
|
<Console bladeburner={bladeburner} player={player} />
|
||||||
</Grid>
|
</Box>
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<AllPages bladeburner={bladeburner} player={player} />
|
<AllPages bladeburner={bladeburner} player={player} />
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -23,7 +23,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
backgroundColor: "#000",
|
backgroundColor: theme.colors.backgroundsecondary,
|
||||||
},
|
},
|
||||||
nopadding: {
|
nopadding: {
|
||||||
padding: theme.spacing(0),
|
padding: theme.spacing(0),
|
||||||
@ -56,6 +56,7 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [command, setCommand] = useState("");
|
const [command, setCommand] = useState("");
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
|
const consoleInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
function handleCommandChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
function handleCommandChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
setCommand(event.target.value);
|
setCommand(event.target.value);
|
||||||
@ -131,15 +132,21 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleClick(): void {
|
||||||
|
if (!consoleInput.current) return;
|
||||||
|
consoleInput.current.focus();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper>
|
<Paper sx={{ p: 1 }}>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
height: '60vh',
|
height: '60vh',
|
||||||
paddingBottom: '8px',
|
paddingBottom: '8px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch',
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
}}>
|
}}
|
||||||
|
onClick={handleClick}>
|
||||||
<Box>
|
<Box>
|
||||||
<Logs entries={[...props.bladeburner.consoleLogs]} />
|
<Logs entries={[...props.bladeburner.consoleLogs]} />
|
||||||
</Box>
|
</Box>
|
||||||
@ -149,6 +156,7 @@ export function Console(props: IProps): React.ReactElement {
|
|||||||
autoFocus
|
autoFocus
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
type="text"
|
type="text"
|
||||||
|
inputRef={consoleInput}
|
||||||
value={command}
|
value={command}
|
||||||
onChange={handleCommandChange}
|
onChange={handleCommandChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
@ -171,7 +179,7 @@ interface ILogProps {
|
|||||||
entries: string[];
|
entries: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function Logs({entries}: ILogProps): React.ReactElement {
|
function Logs({ entries }: ILogProps): React.ReactElement {
|
||||||
const scrollHook = useRef<HTMLUListElement>(null);
|
const scrollHook = useRef<HTMLUListElement>(null);
|
||||||
|
|
||||||
// TODO: Text gets shifted up as new entries appear, if the user scrolled up it should attempt to keep the text focused
|
// TODO: Text gets shifted up as new entries appear, if the user scrolled up it should attempt to keep the text focused
|
||||||
@ -182,7 +190,7 @@ function Logs({entries}: ILogProps): React.ReactElement {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}, [entries]);
|
}, [entries.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List sx={{ height: "100%", overflow: "auto", p: 1 }} ref={scrollHook}>
|
<List sx={{ height: "100%", overflow: "auto", p: 1 }} ref={scrollHook}>
|
||||||
|
@ -3,7 +3,6 @@ import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/Stri
|
|||||||
import { BladeburnerConstants } from "../data/Constants";
|
import { BladeburnerConstants } from "../data/Constants";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { StatsTable } from "../../ui/React/StatsTable";
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
import { IRouter } from "../../ui/Router";
|
import { IRouter } from "../../ui/Router";
|
||||||
@ -44,7 +43,19 @@ export function Stats(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ p: 1 }}>
|
<Paper sx={{ p: 1, overflowY: 'auto', overflowX: 'hidden', wordBreak: 'break-all' }}>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, maxHeight: '60vh' }}>
|
||||||
|
<Box sx={{ alignSelf: 'flex-start', width: '100%' }}>
|
||||||
|
<Button onClick={() => setTravelOpen(true)} sx={{ width: '50%' }}>Travel</Button>
|
||||||
|
<Tooltip title={!inFaction ? <Typography>Rank 25 required.</Typography> : ""}>
|
||||||
|
<span>
|
||||||
|
<Button disabled={!inFaction} onClick={openFaction} sx={{ width: '50%' }}>
|
||||||
|
Faction
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<TravelModal open={travelOpen} onClose={() => setTravelOpen(false)} bladeburner={props.bladeburner} />
|
||||||
|
</Box>
|
||||||
<Box display="flex">
|
<Box display="flex">
|
||||||
<Tooltip title={<Typography>Your rank within the Bladeburner division.</Typography>}>
|
<Tooltip title={<Typography>Your rank within the Bladeburner division.</Typography>}>
|
||||||
<Typography>Rank: {formatNumber(props.bladeburner.rank, 2)}</Typography>
|
<Typography>Rank: {formatNumber(props.bladeburner.rank, 2)}</Typography>
|
||||||
@ -158,24 +169,16 @@ export function Stats(props: IProps): React.ReactElement {
|
|||||||
)}
|
)}
|
||||||
<Typography>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</Typography>
|
<Typography>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</Typography>
|
||||||
<br />
|
<br />
|
||||||
<StatsTable
|
<Typography>
|
||||||
rows={[
|
Aug. Success Chance mult: {formatNumber(props.player.bladeburner_success_chance_mult * 100, 1)}%
|
||||||
["Aug. Success Chance mult: ", formatNumber(props.player.bladeburner_success_chance_mult * 100, 1) + "%"],
|
|
||||||
["Aug. Max Stamina mult: ", formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1) + "%"],
|
|
||||||
["Aug. Stamina Gain mult: ", formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1) + "%"],
|
|
||||||
["Aug. Field Analysis mult: ", formatNumber(props.player.bladeburner_analysis_mult * 100, 1) + "%"],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
<br />
|
||||||
<Button onClick={() => setTravelOpen(true)}>Travel</Button>
|
Aug. Max Stamina mult: {formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1)}%
|
||||||
<Tooltip title={!inFaction ? <Typography>Rank 25 required.</Typography> : ""}>
|
<br />
|
||||||
<span>
|
Aug. Stamina Gain mult: {formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1)}%
|
||||||
<Button disabled={!inFaction} onClick={openFaction}>
|
<br />
|
||||||
Faction
|
Aug. Field Analysis mult: {formatNumber(props.player.bladeburner_analysis_mult * 100, 1)}%
|
||||||
</Button>
|
</Typography>
|
||||||
</span>
|
</Box>
|
||||||
</Tooltip>
|
|
||||||
<TravelModal open={travelOpen} onClose={() => setTravelOpen(false)} bladeburner={props.bladeburner} />
|
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import { hasAugmentationPrereqs } from "../FactionHelpers";
|
|||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { Reputation } from "../../ui/React/Reputation";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
import { Favor } from "../../ui/React/Favor";
|
import { Favor } from "../../ui/React/Favor";
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
@ -203,7 +204,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Typography>Price multiplier: x {mult.toFixed(3)}</Typography>
|
<Typography>Price multiplier: x {numeralWrapper.formatMultiplier(mult)}</Typography>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
||||||
|
@ -364,6 +364,9 @@ export const RamCosts: IMap<any> = {
|
|||||||
getTheme: 0,
|
getTheme: 0,
|
||||||
setTheme: 0,
|
setTheme: 0,
|
||||||
resetTheme: 0,
|
resetTheme: 0,
|
||||||
|
getStyles: 0,
|
||||||
|
setStyles: 0,
|
||||||
|
resetStyles: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
heart: {
|
heart: {
|
||||||
|
@ -432,8 +432,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
throw makeRuntimeErrorMsg(funcName, `${argName} should be a string`);
|
throw makeRuntimeErrorMsg(funcName, `${argName} should be a string`);
|
||||||
},
|
},
|
||||||
number: (funcName: string, argName: string, v: any): number => {
|
number: (funcName: string, argName: string, v: any): number => {
|
||||||
if (!isNaN(v))
|
if (!isNaN(v)) {
|
||||||
{
|
|
||||||
if (typeof v === "number") return v;
|
if (typeof v === "number") return v;
|
||||||
if (!isNaN(parseFloat(v))) return parseFloat(v);
|
if (!isNaN(parseFloat(v))) return parseFloat(v);
|
||||||
}
|
}
|
||||||
@ -700,8 +699,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
|||||||
workerScript.log(
|
workerScript.log(
|
||||||
"weaken",
|
"weaken",
|
||||||
() =>
|
() =>
|
||||||
`'${server.hostname}' security level weakened to ${
|
`'${server.hostname}' security level weakened to ${server.hackDifficulty
|
||||||
server.hackDifficulty
|
|
||||||
}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`,
|
}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`,
|
||||||
);
|
);
|
||||||
workerScript.scriptRef.onlineExpGained += expGain;
|
workerScript.scriptRef.onlineExpGained += expGain;
|
||||||
|
@ -53,23 +53,22 @@ export function NetscriptCodingContract(
|
|||||||
const serv = helper.getServer(hostname, "codingcontract.attempt");
|
const serv = helper.getServer(hostname, "codingcontract.attempt");
|
||||||
if (contract.isSolution(answer)) {
|
if (contract.isSolution(answer)) {
|
||||||
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
|
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
|
||||||
workerScript.log("attempt", () => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
|
workerScript.log("codingcontract.attempt", () => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
|
||||||
serv.removeContract(filename);
|
serv.removeContract(filename);
|
||||||
return returnReward ? reward : true;
|
return returnReward ? reward : true;
|
||||||
} else {
|
} else {
|
||||||
++contract.tries;
|
++contract.tries;
|
||||||
if (contract.tries >= contract.getMaxNumTries()) {
|
if (contract.tries >= contract.getMaxNumTries()) {
|
||||||
workerScript.log(
|
workerScript.log(
|
||||||
"attempt",
|
"codingcontract.attempt",
|
||||||
() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`,
|
() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`,
|
||||||
);
|
);
|
||||||
serv.removeContract(filename);
|
serv.removeContract(filename);
|
||||||
} else {
|
} else {
|
||||||
workerScript.log(
|
workerScript.log(
|
||||||
"attempt",
|
"codingcontract.attempt",
|
||||||
() =>
|
() =>
|
||||||
`Coding Contract attempt '${filename}' failed. ${
|
`Coding Contract attempt '${filename}' failed. ${contract.getMaxNumTries() - contract.tries
|
||||||
contract.getMaxNumTries() - contract.tries
|
|
||||||
} attempts remaining.`,
|
} attempts remaining.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
|||||||
}
|
}
|
||||||
const node = getHacknetNode(i, "upgradeCache");
|
const node = getHacknetNode(i, "upgradeCache");
|
||||||
if (!(node instanceof HacknetServer)) {
|
if (!(node instanceof HacknetServer)) {
|
||||||
workerScript.log("upgradeCache", () => "Can only be called on hacknet servers");
|
workerScript.log("hacknet.upgradeCache", () => "Can only be called on hacknet servers");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const res = purchaseCacheUpgrade(player, node, n);
|
const res = purchaseCacheUpgrade(player, node, n);
|
||||||
@ -138,7 +138,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
|||||||
}
|
}
|
||||||
const node = getHacknetNode(i, "upgradeCache");
|
const node = getHacknetNode(i, "upgradeCache");
|
||||||
if (!(node instanceof HacknetServer)) {
|
if (!(node instanceof HacknetServer)) {
|
||||||
workerScript.log("getCacheUpgradeCost", () => "Can only be called on hacknet servers");
|
workerScript.log("hacknet.getCacheUpgradeCost", () => "Can only be called on hacknet servers");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return node.calculateCacheUpgradeCost(n);
|
return node.calculateCacheUpgradeCost(n);
|
||||||
|
@ -2,10 +2,11 @@ import { INetscriptHelper } from "./INetscriptHelper";
|
|||||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { getRamCost } from "../Netscript/RamCostGenerator";
|
import { getRamCost } from "../Netscript/RamCostGenerator";
|
||||||
import { UserInterface as IUserInterface, UserInterfaceTheme } from "../ScriptEditor/NetscriptDefinitions";
|
import { IStyleSettings, UserInterface as IUserInterface, UserInterfaceTheme } from "../ScriptEditor/NetscriptDefinitions";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
import { ThemeEvents } from "../ui/React/Theme";
|
import { ThemeEvents } from "../ui/React/Theme";
|
||||||
import { defaultTheme } from "../Settings/Themes";
|
import { defaultTheme } from "../Settings/Themes";
|
||||||
|
import { defaultStyles } from "../Settings/Styles";
|
||||||
|
|
||||||
export function NetscriptUserInterface(
|
export function NetscriptUserInterface(
|
||||||
player: IPlayer,
|
player: IPlayer,
|
||||||
@ -18,6 +19,11 @@ export function NetscriptUserInterface(
|
|||||||
return { ...Settings.theme };
|
return { ...Settings.theme };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getStyles: function (): IStyleSettings {
|
||||||
|
helper.updateDynamicRam("getStyles", getRamCost(player, "ui", "getStyles"));
|
||||||
|
return { ...Settings.styles };
|
||||||
|
},
|
||||||
|
|
||||||
setTheme: function (newTheme: UserInterfaceTheme): void {
|
setTheme: function (newTheme: UserInterfaceTheme): void {
|
||||||
helper.updateDynamicRam("setTheme", getRamCost(player, "ui", "setTheme"));
|
helper.updateDynamicRam("setTheme", getRamCost(player, "ui", "setTheme"));
|
||||||
const hex = /^(#)((?:[A-Fa-f0-9]{3}){1,2})$/;
|
const hex = /^(#)((?:[A-Fa-f0-9]{3}){1,2})$/;
|
||||||
@ -43,11 +49,41 @@ export function NetscriptUserInterface(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setStyles: function (newStyles: IStyleSettings): void {
|
||||||
|
helper.updateDynamicRam("setStyles", getRamCost(player, "ui", "setStyles"));
|
||||||
|
|
||||||
|
const currentStyles = {...Settings.styles}
|
||||||
|
const errors: string[] = [];
|
||||||
|
for (const key of Object.keys(newStyles)) {
|
||||||
|
if (!((currentStyles as any)[key])) {
|
||||||
|
// Invalid key
|
||||||
|
errors.push(`Invalid key "${key}"`);
|
||||||
|
} else {
|
||||||
|
(currentStyles as any)[key] = (newStyles as any)[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length === 0) {
|
||||||
|
Object.assign(Settings.styles, currentStyles);
|
||||||
|
ThemeEvents.emit();
|
||||||
|
workerScript.log("ui.setStyles", () => `Successfully set styles`);
|
||||||
|
} else {
|
||||||
|
workerScript.log("ui.setStyles", () => `Failed to set styles. Errors: ${errors.join(', ')}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
resetTheme: function (): void {
|
resetTheme: function (): void {
|
||||||
helper.updateDynamicRam("resetTheme", getRamCost(player, "ui", "resetTheme"));
|
helper.updateDynamicRam("resetTheme", getRamCost(player, "ui", "resetTheme"));
|
||||||
Settings.theme = defaultTheme;
|
Settings.theme = { ...defaultTheme };
|
||||||
ThemeEvents.emit();
|
ThemeEvents.emit();
|
||||||
workerScript.log("ui.resetTheme", () => `Reinitialized theme to default`);
|
workerScript.log("ui.resetTheme", () => `Reinitialized theme to default`);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetStyles: function (): void {
|
||||||
|
helper.updateDynamicRam("resetStyles", getRamCost(player, "ui", "resetStyles"));
|
||||||
|
Settings.styles = { ...defaultStyles };
|
||||||
|
ThemeEvents.emit();
|
||||||
|
workerScript.log("ui.resetStyles", () => `Reinitialized styles to default`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -946,11 +946,6 @@ export function workForFaction(this: IPlayer, numCycles: number): boolean {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let favorMult = 1 + faction.favor / 100;
|
|
||||||
if (isNaN(favorMult)) {
|
|
||||||
favorMult = 1;
|
|
||||||
}
|
|
||||||
this.workRepGainRate *= favorMult;
|
|
||||||
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
|
||||||
|
|
||||||
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
||||||
|
@ -161,8 +161,6 @@ export function prestigeAugmentation(): void {
|
|||||||
resetPidCounter();
|
resetPidCounter();
|
||||||
ProgramsSeen.splice(0, ProgramsSeen.length);
|
ProgramsSeen.splice(0, ProgramsSeen.length);
|
||||||
InvitationsSeen.splice(0, InvitationsSeen.length);
|
InvitationsSeen.splice(0, InvitationsSeen.length);
|
||||||
|
|
||||||
Router.clearHistory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prestige by destroying Bit Node and gaining a Source File
|
// Prestige by destroying Bit Node and gaining a Source File
|
||||||
@ -308,7 +306,5 @@ export function prestigeSourceFile(flume: boolean): void {
|
|||||||
// Gain int exp
|
// Gain int exp
|
||||||
if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300);
|
if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300);
|
||||||
|
|
||||||
Router.clearHistory();
|
|
||||||
|
|
||||||
resetPidCounter();
|
resetPidCounter();
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ export class Script {
|
|||||||
*/
|
*/
|
||||||
saveScript(player: IPlayer, filename: string, code: string, hostname: string, otherScripts: Script[]): void {
|
saveScript(player: IPlayer, filename: string, code: string, hostname: string, otherScripts: Script[]): void {
|
||||||
// Update code and filename
|
// Update code and filename
|
||||||
this.code = code.replace(/^\s+|\s+$/g, "");
|
this.code = Script.formatCode(this.code);
|
||||||
|
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.server = hostname;
|
this.server = hostname;
|
||||||
@ -158,6 +158,15 @@ export class Script {
|
|||||||
s.rehash();
|
s.rehash();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats code: Removes the starting & trailing whitespace
|
||||||
|
* @param {string} code - The code to format
|
||||||
|
* @returns The formatted code
|
||||||
|
*/
|
||||||
|
static formatCode(code: string): string {
|
||||||
|
return code.replace(/^\s+|\s+$/g, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reviver.constructors.Script = Script;
|
Reviver.constructors.Script = Script;
|
||||||
|
39
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
39
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -3880,6 +3880,36 @@ interface UserInterface {
|
|||||||
* RAM cost: cost: 0 GB
|
* RAM cost: cost: 0 GB
|
||||||
*/
|
*/
|
||||||
resetTheme(): void;
|
resetTheme(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current styles
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: cost: 0 GB
|
||||||
|
*
|
||||||
|
* @returns An object containing the player's styles
|
||||||
|
*/
|
||||||
|
getStyles(): IStyleSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current styles
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: cost: 0 GB
|
||||||
|
* @example
|
||||||
|
* Usage example (NS2)
|
||||||
|
* ```ts
|
||||||
|
* const styles = ns.ui.getStyles();
|
||||||
|
* styles.fontFamily = 'Comic Sans Ms';
|
||||||
|
* ns.ui.setStyles(styles);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
setStyles(newStyles: IStyleSettings): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the player's styles to the default values
|
||||||
|
* @remarks
|
||||||
|
* RAM cost: cost: 0 GB
|
||||||
|
*/
|
||||||
|
resetStyles(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6354,3 +6384,12 @@ interface UserInterfaceTheme {
|
|||||||
backgroundsecondary: string;
|
backgroundsecondary: string;
|
||||||
button: string;
|
button: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface Styles
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface IStyleSettings {
|
||||||
|
fontFamily: string;
|
||||||
|
lineHeight: number;
|
||||||
|
}
|
||||||
|
@ -686,7 +686,9 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
const serverScript = server.scripts.find((s) => s.filename === openScript.fileName);
|
const serverScript = server.scripts.find((s) => s.filename === openScript.fileName);
|
||||||
if (serverScript === undefined) return " *";
|
if (serverScript === undefined) return " *";
|
||||||
|
|
||||||
return serverScript.code !== openScript.code ? " *" : "";
|
// The server code is stored with its starting & trailing whitespace removed
|
||||||
|
const openScriptFormatted = Script.formatCode(openScript.code);
|
||||||
|
return serverScript.code !== openScriptFormatted ? " *" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toolbars are roughly 112px:
|
// Toolbars are roughly 112px:
|
||||||
@ -846,7 +848,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
<span style={{ color: Settings.theme.primary, fontSize: "20px", textAlign: "center" }}>
|
<span style={{ color: Settings.theme.primary, fontSize: "20px", textAlign: "center" }}>
|
||||||
<Typography variant="h4">No open files</Typography>
|
<Typography variant="h4">No open files</Typography>
|
||||||
<Typography variant="h5">
|
<Typography variant="h5">
|
||||||
Use `nano FILENAME` in
|
Use <code>nano FILENAME</code> in
|
||||||
<br />
|
<br />
|
||||||
the terminal to open files
|
the terminal to open files
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ISelfInitializer, ISelfLoading } from "../types";
|
import { ISelfInitializer, ISelfLoading } from "../types";
|
||||||
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
|
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
|
||||||
import { defaultTheme, ITheme } from "./Themes";
|
import { defaultTheme, ITheme } from "./Themes";
|
||||||
import { defaultStyles, IStyleSettings } from "./Styles";
|
import { defaultStyles } from "./Styles";
|
||||||
import { WordWrapOptions } from "../ScriptEditor/ui/Options";
|
import { WordWrapOptions } from "../ScriptEditor/ui/Options";
|
||||||
import { OverviewSettings } from "../ui/React/Overview";
|
import { OverviewSettings } from "../ui/React/Overview";
|
||||||
|
import { IStyleSettings } from "../ScriptEditor/NetscriptDefinitions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the default settings the player could customize.
|
* Represents the default settings the player could customize.
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
import React from "react";
|
import { IStyleSettings } from "../ScriptEditor/NetscriptDefinitions";
|
||||||
|
|
||||||
export interface IStyleSettings {
|
|
||||||
fontFamily: React.CSSProperties["fontFamily"];
|
|
||||||
lineHeight: React.CSSProperties["lineHeight"];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultStyles: IStyleSettings = {
|
export const defaultStyles: IStyleSettings = {
|
||||||
lineHeight: 1.5,
|
lineHeight: 1.5,
|
||||||
|
@ -3,73 +3,74 @@ import { IMap } from "../types";
|
|||||||
|
|
||||||
export const TerminalHelpText: string[] = [
|
export const TerminalHelpText: string[] = [
|
||||||
"Type 'help name' to learn more about the command ",
|
"Type 'help name' to learn more about the command ",
|
||||||
"",
|
" ",
|
||||||
'alias [-g] [name="value"] Create or display Terminal aliases',
|
' alias [-g] [name="value"] Create or display Terminal aliases',
|
||||||
"analyze Get information about the current machine ",
|
" analyze Get information about the current machine ",
|
||||||
"backdoor Install a backdoor on the current machine ",
|
" backdoor Install a backdoor on the current machine ",
|
||||||
"buy [-l/program] Purchase a program through the Dark Web",
|
" buy [-l/-a/program] Purchase a program through the Dark Web",
|
||||||
"cat [file] Display a .msg, .lit, or .txt file",
|
" cat [file] Display a .msg, .lit, or .txt file",
|
||||||
"cd [dir] Change to a new directory",
|
" cd [dir] Change to a new directory",
|
||||||
"check [script] [args...] Print a script's logs to Terminal",
|
" check [script] [args...] Print a script's logs to Terminal",
|
||||||
"clear Clear all text on the terminal ",
|
" clear Clear all text on the terminal ",
|
||||||
"cls See 'clear' command ",
|
" cls See 'clear' command ",
|
||||||
"connect [hostname] Connects to a remote server",
|
" connect [hostname] Connects to a remote server",
|
||||||
"cp [src] [dst] Copy a file",
|
" cp [src] [dst] Copy a file",
|
||||||
"download [script/text file] Downloads scripts or text files to your computer",
|
" download [script/text file] Downloads scripts or text files to your computer",
|
||||||
"expr [math expression] Evaluate a mathematical expression",
|
" expr [math expression] Evaluate a mathematical expression",
|
||||||
"free Check the machine's memory (RAM) usage",
|
" free Check the machine's memory (RAM) usage",
|
||||||
"grow Spoof money in a servers bank account, increasing the amount available.",
|
" grow Spoof money in a servers bank account, increasing the amount available.",
|
||||||
"hack Hack the current machine",
|
" hack Hack the current machine",
|
||||||
"help [command] Display this help text, or the help text for a command",
|
" help [command] Display this help text, or the help text for a command",
|
||||||
"home Connect to home computer",
|
" home Connect to home computer",
|
||||||
"hostname Displays the hostname of the machine",
|
" hostname Displays the hostname of the machine",
|
||||||
"kill [script/pid] [args...] Stops the specified script on the current server ",
|
" kill [script/pid] [args...] Stops the specified script on the current server ",
|
||||||
"killall Stops all running scripts on the current machine",
|
" killall Stops all running scripts on the current machine",
|
||||||
"ls [dir] [| grep pattern] Displays all files on the machine",
|
" ls [dir] [| grep pattern] Displays all files on the machine",
|
||||||
"lscpu Displays the number of CPU cores on the machine",
|
" lscpu Displays the number of CPU cores on the machine",
|
||||||
"mem [script] [-t n] Displays the amount of RAM required to run the script",
|
" mem [script] [-t n] Displays the amount of RAM required to run the script",
|
||||||
"mv [src] [dest] Move/rename a text or script file",
|
" mv [src] [dest] Move/rename a text or script file",
|
||||||
"nano [file ...] Text editor - Open up and edit one or more scripts or text files",
|
" nano [file ...] Text editor - Open up and edit one or more scripts or text files",
|
||||||
"ps Display all scripts that are currently running",
|
" ps Display all scripts that are currently running",
|
||||||
"rm [file] Delete a file from the server",
|
" rm [file] Delete a file from the server",
|
||||||
"run [name] [-t n] [--tail] [args...] Execute a program or script",
|
" run [name] [-t n] [--tail] [args...] Execute a program or script",
|
||||||
"scan Prints all immediately-available network connections",
|
" scan Prints all immediately-available network connections",
|
||||||
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
" scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
||||||
"scp [file ...] [server] Copies a file to a destination server",
|
" scp [file ...] [server] Copies a file to a destination server",
|
||||||
"sudov Shows whether you have root access on this computer",
|
" sudov Shows whether you have root access on this computer",
|
||||||
"tail [script] [args...] Displays dynamic logs for the specified script",
|
" tail [script] [args...] Displays dynamic logs for the specified script",
|
||||||
"top Displays all running scripts and their RAM usage",
|
" top Displays all running scripts and their RAM usage",
|
||||||
"unalias [alias name] Deletes the specified alias",
|
" unalias [alias name] Deletes the specified alias",
|
||||||
"vim [file ...] Text editor - Open up and edit one or more scripts or text files in vim mode",
|
" vim [file ...] Text editor - Open up and edit one or more scripts or text files in vim mode",
|
||||||
"weaken Reduce the security of the current machine",
|
" weaken Reduce the security of the current machine",
|
||||||
"wget [url] [target file] Retrieves code/text from a web server",
|
" wget [url] [target file] Retrieves code/text from a web server",
|
||||||
|
" ",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const HelpTexts: IMap<string[]> = {
|
export const HelpTexts: IMap<string[]> = {
|
||||||
alias: [
|
alias: [
|
||||||
'alias [-g] [name="value"] ',
|
'Usage: alias [-g] [name="value"] ',
|
||||||
" ",
|
" ",
|
||||||
"Create or display aliases. An alias enables a replacement of a word with another string. ",
|
"Create or display aliases. An alias enables a replacement of a word with another string. ",
|
||||||
"It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME ",
|
"It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME ",
|
||||||
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, ",
|
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, ",
|
||||||
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: ",
|
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: ",
|
||||||
" ",
|
" ",
|
||||||
'alias nuke="run NUKE.exe"',
|
' alias nuke="run NUKE.exe"',
|
||||||
" ",
|
" ",
|
||||||
"Then, to run the NUKE.exe program you would just have to enter 'nuke' in Terminal rather than the full command. ",
|
"Then, to run the NUKE.exe program you would just have to enter 'nuke' in Terminal rather than the full command. ",
|
||||||
"It is important to note that 'default' aliases will only be substituted for the first word of a Terminal command. For ",
|
"It is important to note that 'default' aliases will only be substituted for the first word of a Terminal command. For ",
|
||||||
"example, if the following alias was set: ",
|
"example, if the following alias was set: ",
|
||||||
" ",
|
" ",
|
||||||
'alias worm="HTTPWorm.exe"',
|
' alias worm="HTTPWorm.exe"',
|
||||||
" ",
|
" ",
|
||||||
"and then you tried to run the following terminal command: ",
|
"and then you tried to run the following terminal command: ",
|
||||||
" ",
|
" ",
|
||||||
"run worm",
|
" run worm",
|
||||||
" ",
|
" ",
|
||||||
"This would fail because the worm alias is not the first word of a Terminal command. To allow an alias to be substituted ",
|
"This would fail because the worm alias is not the first word of a Terminal command. To allow an alias to be substituted ",
|
||||||
"anywhere in a Terminal command, rather than just the first word, you must set it to be a global alias using the -g flag: ",
|
"anywhere in a Terminal command, rather than just the first word, you must set it to be a global alias using the -g flag: ",
|
||||||
" ",
|
" ",
|
||||||
'alias -g worm="HTTPWorm.exe"',
|
' alias -g worm="HTTPWorm.exe"',
|
||||||
" ",
|
" ",
|
||||||
"Now, the 'worm' alias will be substituted anytime it shows up as an individual word in a Terminal command. ",
|
"Now, the 'worm' alias will be substituted anytime it shows up as an individual word in a Terminal command. ",
|
||||||
" ",
|
" ",
|
||||||
@ -80,15 +81,16 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
analyze: [
|
analyze: [
|
||||||
"analyze",
|
"Usage: analyze",
|
||||||
" ",
|
" ",
|
||||||
"Prints details and statistics about the current server. The information that is printed includes basic ",
|
"Prints details and statistics about the current server. The information that is printed includes basic ",
|
||||||
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also ",
|
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also ",
|
||||||
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is ",
|
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is ",
|
||||||
"available on the server, etc.",
|
"available on the server, etc.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
backdoor: [
|
backdoor: [
|
||||||
"backdoor",
|
"Usage: backdoor",
|
||||||
" ",
|
" ",
|
||||||
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.",
|
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.",
|
||||||
" ",
|
" ",
|
||||||
@ -96,7 +98,7 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
buy: [
|
buy: [
|
||||||
"buy [-l / -a / program]",
|
"Usage: buy [-l / -a / program]",
|
||||||
" ",
|
" ",
|
||||||
"Purchase a program through the Dark Web. Requires a TOR router to use.",
|
"Purchase a program through the Dark Web. Requires a TOR router to use.",
|
||||||
" ",
|
" ",
|
||||||
@ -106,65 +108,72 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
"If this command is ran with the '-a' flag, it will attempt to purchase all unowned programs.",
|
"If this command is ran with the '-a' flag, it will attempt to purchase all unowned programs.",
|
||||||
" ",
|
" ",
|
||||||
"Otherwise, the name of the program must be passed in as a parameter. This name is NOT case-sensitive.",
|
"Otherwise, the name of the program must be passed in as a parameter. This name is NOT case-sensitive.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
cat: [
|
cat: [
|
||||||
"cat [file]",
|
"Usage: cat [file]",
|
||||||
" ",
|
" ",
|
||||||
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:",
|
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:",
|
||||||
" ",
|
" ",
|
||||||
"cat j1.msg",
|
" cat j1.msg",
|
||||||
" ",
|
" ",
|
||||||
"cat foo.lit",
|
" cat foo.lit",
|
||||||
|
" ",
|
||||||
|
" cat servers.txt",
|
||||||
" ",
|
" ",
|
||||||
"cat servers.txt",
|
|
||||||
],
|
],
|
||||||
cd: [
|
cd: [
|
||||||
"cd [dir]",
|
"Usage: cd [dir]",
|
||||||
" ",
|
" ",
|
||||||
"Change to the specified directory. Note that this works even for directories that don't exist. If you ",
|
"Change to the specified directory. Note that this works even for directories that don't exist. If you ",
|
||||||
"change to a directory that does not exist, it will not be 'created'. Examples:",
|
"change to a directory that does not exist, it will not be 'created'. Examples:",
|
||||||
" ",
|
" ",
|
||||||
"cd scripts/hacking",
|
" cd scripts/hacking",
|
||||||
" ",
|
" ",
|
||||||
"cd /logs",
|
" cd /logs",
|
||||||
|
" ",
|
||||||
|
" cd ../",
|
||||||
" ",
|
" ",
|
||||||
"cd ../",
|
|
||||||
],
|
],
|
||||||
check: [
|
check: [
|
||||||
"check [script name] [args...]",
|
"Usage: check [script name] [args...]",
|
||||||
" ",
|
" ",
|
||||||
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by ",
|
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by ",
|
||||||
"a space. Remember that a running script is uniquely ",
|
"a space. Remember that a running script is uniquely ",
|
||||||
"identified both by its name and the arguments that are used to start it. So, if a script was ran with the following arguments: ",
|
"identified both by its name and the arguments that are used to start it. So, if a script was ran with the following arguments: ",
|
||||||
" ",
|
" ",
|
||||||
"run foo.script 1 2 foodnstuff",
|
" run foo.script 1 2 foodnstuff",
|
||||||
" ",
|
" ",
|
||||||
"Then to run the 'check' command on this script you would have to pass the same arguments in: ",
|
"Then to run the 'check' command on this script you would have to pass the same arguments in: ",
|
||||||
" ",
|
" ",
|
||||||
"check foo.script 1 2 foodnstuff",
|
" check foo.script 1 2 foodnstuff",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
clear: [
|
clear: [
|
||||||
"clear",
|
"Usage: clear",
|
||||||
" ",
|
" ",
|
||||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
||||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'cls' command",
|
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'cls' command",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
cls: [
|
cls: [
|
||||||
"cls",
|
"Usage: cls",
|
||||||
" ",
|
" ",
|
||||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
||||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'clear' command",
|
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'clear' command",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
connect: [
|
connect: [
|
||||||
"connect [hostname]",
|
"Usage: connect [hostname]",
|
||||||
" ",
|
" ",
|
||||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument ",
|
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument ",
|
||||||
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To ",
|
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To ",
|
||||||
"see which servers can be connected to, use the 'scan' command.",
|
"see which servers can be connected to, use the 'scan' command.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
cp: ["cp [src] [dst]", " ", "Copy a file on this server. To copy a file to another server use scp."],
|
cp: ["Usage: cp [src] [dst]", " ", "Copy a file on this server. To copy a file to another server use scp.", " "],
|
||||||
download: [
|
download: [
|
||||||
"download [script/text file]",
|
"Usage: download [script/text file]",
|
||||||
" ",
|
" ",
|
||||||
"Downloads a script or text file to your computer (like your real life computer).",
|
"Downloads a script or text file to your computer (like your real life computer).",
|
||||||
" ",
|
" ",
|
||||||
@ -178,7 +187,7 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
expr: [
|
expr: [
|
||||||
"expr [mathematical expression]",
|
"Usage: expr [mathematical expression]",
|
||||||
" ",
|
" ",
|
||||||
"Evaluate a simple mathematical expression. Supports native JavaScript operators:",
|
"Evaluate a simple mathematical expression. Supports native JavaScript operators:",
|
||||||
" ",
|
" ",
|
||||||
@ -186,47 +195,49 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
"Example:",
|
"Example:",
|
||||||
" ",
|
" ",
|
||||||
"expr 25 * 2 ** 10",
|
" expr 25 * 2 ** 10",
|
||||||
" ",
|
" ",
|
||||||
"Note that letters (non-digits) are not allowed and will be removed from the input.",
|
"Note that letters (non-digits) are not allowed and will be removed from the input.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
free: [
|
free: [
|
||||||
"free",
|
"Usage: free",
|
||||||
" ",
|
" ",
|
||||||
"Displays the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as ",
|
"Displays the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as ",
|
||||||
"how much of it is being used.",
|
"how much of it is being used.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
grow: [
|
grow: [
|
||||||
"grow",
|
"Usage: grow",
|
||||||
"",
|
" ",
|
||||||
"Spoof transactions in the current server. Increasing the money available by hacking. Requires root access.",
|
"Spoof transactions in the current server. Increasing the money available by hacking. Requires root access.",
|
||||||
"See the wiki page for hacking mechanics.",
|
"See the wiki page for hacking mechanics.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
hack: [
|
hack: [
|
||||||
"hack",
|
"Usage: hack",
|
||||||
" ",
|
" ",
|
||||||
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics",
|
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics",
|
||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
help: [
|
help: [
|
||||||
"help [command]",
|
"Usage: help [command]",
|
||||||
" ",
|
" ",
|
||||||
"Display Terminal help information. Without arguments, 'help' prints a list of all valid Terminal commands and a brief ",
|
"Display Terminal help information. Without arguments, 'help' prints a list of all valid Terminal commands and a brief ",
|
||||||
"description of their functionality. You can also pass the name of a Terminal command as an argument to 'help' to print ",
|
"description of their functionality. You can also pass the name of a Terminal command as an argument to 'help' to print ",
|
||||||
"more detailed information about the Terminal command. Examples: ",
|
"more detailed information about the Terminal command. Examples: ",
|
||||||
" ",
|
" ",
|
||||||
"help alias",
|
" help alias",
|
||||||
|
" ",
|
||||||
|
" help scan-analyze",
|
||||||
" ",
|
" ",
|
||||||
"help scan-analyze",
|
|
||||||
],
|
],
|
||||||
home: [
|
home: [
|
||||||
"home" + "Connect to your home computer. This will work no matter what server you are currently connected to.",
|
"Usage: home", " ", "Connect to your home computer. This will work no matter what server you are currently connected to.", " ",
|
||||||
],
|
],
|
||||||
hostname: ["hostname", " ", "Prints the hostname of the current server"],
|
hostname: ["Usage: hostname", " ", "Prints the hostname of the current server", " "],
|
||||||
kill: [
|
kill: [
|
||||||
"kill [script name] [args...]",
|
"Usage: kill [script name] [args...] or kill [pid",
|
||||||
" ",
|
|
||||||
"kill [pid]",
|
|
||||||
" ",
|
" ",
|
||||||
"Kill the script specified by the script name and arguments OR by its PID.",
|
"Kill the script specified by the script name and arguments OR by its PID.",
|
||||||
" ",
|
" ",
|
||||||
@ -235,24 +246,26 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
"uniquely identified by both its name and the arguments that are used to start ",
|
"uniquely identified by both its name and the arguments that are used to start ",
|
||||||
"it. So, if a script was ran with the following arguments:",
|
"it. So, if a script was ran with the following arguments:",
|
||||||
" ",
|
" ",
|
||||||
"run foo.script 1 sigma-cosmetics",
|
" run foo.script 1 sigma-cosmetics",
|
||||||
" ",
|
" ",
|
||||||
"Then to kill this script the same arguments would have to be used:",
|
"Then to kill this script the same arguments would have to be used:",
|
||||||
" ",
|
" ",
|
||||||
"kill foo.script 1 sigma-cosmetics",
|
" kill foo.script 1 sigma-cosmetics",
|
||||||
" ",
|
" ",
|
||||||
"If you are killing the script using its PID, then the PID argument must be numeric",
|
"If you are killing the script using its PID, then the PID argument must be numeric",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
killall: [
|
killall: [
|
||||||
"killall",
|
"Usage: killall",
|
||||||
" ",
|
" ",
|
||||||
"Kills all scripts on the current server. ",
|
"Kills all scripts on the current server. ",
|
||||||
"Note that after the 'kill' command is issued for a script, it may take a while for the script to actually stop running. ",
|
"Note that after the 'kill' command is issued for a script, it may take a while for the script to actually stop running. ",
|
||||||
"This will happen if the script is in the middle of a command such as grow() or weaken() that takes time to execute. ",
|
"This will happen if the script is in the middle of a command such as grow() or weaken() that takes time to execute. ",
|
||||||
"The script will not be stopped/killed until after that time has elapsed.",
|
"The script will not be stopped/killed until after that time has elapsed.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
ls: [
|
ls: [
|
||||||
"ls [dir] [| grep pattern]",
|
"Usage: ls [dir] [| grep pattern]",
|
||||||
" ",
|
" ",
|
||||||
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. ",
|
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. ",
|
||||||
"The files will be displayed in alphabetical order. ",
|
"The files will be displayed in alphabetical order. ",
|
||||||
@ -265,34 +278,36 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
"List all files with the '.script' extension in the current directory:",
|
"List all files with the '.script' extension in the current directory:",
|
||||||
" ",
|
" ",
|
||||||
"ls | grep .script",
|
" ls | grep .script",
|
||||||
" ",
|
" ",
|
||||||
"List all files with the '.js' extension in the root directory:",
|
"List all files with the '.js' extension in the root directory:",
|
||||||
" ",
|
" ",
|
||||||
"ls / | grep .js",
|
" ls / | grep .js",
|
||||||
" ",
|
" ",
|
||||||
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:",
|
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:",
|
||||||
" ",
|
" ",
|
||||||
"ls scripts | grep purchase",
|
" ls scripts | grep purchase",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
lscpu: ["lscpu", " ", "Prints the number of CPU Cores the current server has"],
|
lscpu: ["Usage: lscpu", " ", "Prints the number of CPU Cores the current server has", " "],
|
||||||
|
|
||||||
mem: [
|
mem: [
|
||||||
"mem [script name] [-t num_threads]",
|
"Usage: mem [script name] [-t num_threads]",
|
||||||
" ",
|
" ",
|
||||||
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
||||||
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
||||||
"an argument for the number of threads must be passed in afterwards. Examples:",
|
"an argument for the number of threads must be passed in afterwards. Examples:",
|
||||||
" ",
|
" ",
|
||||||
"mem foo.script",
|
" mem foo.script",
|
||||||
" ",
|
" ",
|
||||||
"mem foo.script -t 50",
|
" mem foo.script -t 50",
|
||||||
" ",
|
" ",
|
||||||
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example ",
|
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example ",
|
||||||
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
|
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
mv: [
|
mv: [
|
||||||
"mv [src] [dest]",
|
"Usage: mv [src] [dest]",
|
||||||
" ",
|
" ",
|
||||||
"Move the source file to the specified destination. This can also be used to rename files. ",
|
"Move the source file to the specified destination. This can also be used to rename files. ",
|
||||||
"This command only works for scripts and text files (.txt). This command CANNOT be used to ",
|
"This command only works for scripts and text files (.txt). This command CANNOT be used to ",
|
||||||
@ -302,28 +317,31 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
"full filepath. ",
|
"full filepath. ",
|
||||||
"Examples: ",
|
"Examples: ",
|
||||||
" ",
|
" ",
|
||||||
"mv hacking-controller.script scripts/hacking-controller.script",
|
" mv hacking-controller.script scripts/hacking-controller.script",
|
||||||
|
" ",
|
||||||
|
" mv myScript.js myOldScript.js",
|
||||||
" ",
|
" ",
|
||||||
"mv myScript.js myOldScript.js",
|
|
||||||
],
|
],
|
||||||
nano: [
|
nano: [
|
||||||
"nano [file ...]",
|
"Usage: nano [file ...]",
|
||||||
" ",
|
" ",
|
||||||
"Opens up the specified file(s) in the Text Editor. Only scripts (.script) or text files (.txt) can be ",
|
"Opens up the specified file(s) in the Text Editor. Only scripts (.script) or text files (.txt) can be ",
|
||||||
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
|
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
|
||||||
"will be created",
|
"will be created",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
ps: ["ps", " ", "Prints all scripts that are running on the current server"],
|
ps: ["Usage: ps", " ", "Prints all scripts that are running on the current server", " "],
|
||||||
|
|
||||||
rm: [
|
rm: [
|
||||||
"rm [file]",
|
"Usage: rm [file]",
|
||||||
" ",
|
" ",
|
||||||
"Removes the specified file from the current server. A file can be a script, a program, or a message file. ",
|
"Removes the specified file from the current server. A file can be a script, a program, or a message file. ",
|
||||||
" ",
|
" ",
|
||||||
"WARNING: This is permanent and cannot be undone",
|
"WARNING: This is permanent and cannot be undone",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
run: [
|
run: [
|
||||||
"run [file name] [-t] [num threads] [args...]",
|
"Usage: run [file name] [-t] [num threads] [args...]",
|
||||||
" ",
|
" ",
|
||||||
"Execute a program, script or coding contract.",
|
"Execute a program, script or coding contract.",
|
||||||
" ",
|
" ",
|
||||||
@ -338,13 +356,14 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
scan: [
|
scan: [
|
||||||
"scan",
|
"Usage: scan",
|
||||||
" ",
|
" ",
|
||||||
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect ",
|
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect ",
|
||||||
"to using the 'connect' Terminal command.",
|
"to using the 'connect' Terminal command.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
"scan-analyze": [
|
"scan-analyze": [
|
||||||
"scan-analyze [depth] [-a]",
|
"Usage: scan-analyze [depth] [-a]",
|
||||||
" ",
|
" ",
|
||||||
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling ",
|
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling ",
|
||||||
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal ",
|
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal ",
|
||||||
@ -360,71 +379,77 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
" ",
|
" ",
|
||||||
"By default, this command will not display servers that you have purchased. However, you can pass in the ",
|
"By default, this command will not display servers that you have purchased. However, you can pass in the ",
|
||||||
"-a flag at the end of the command if you would like to enable that.",
|
"-a flag at the end of the command if you would like to enable that.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
scp: [
|
scp: [
|
||||||
"scp [filename ...] [target server]",
|
"Usage: scp [filename ...] [target server]",
|
||||||
" ",
|
" ",
|
||||||
"Copies the specified file(s) from the current server to the target server. ",
|
"Copies the specified file(s) from the current server to the target server. ",
|
||||||
"This command only works for script files (.script or .js extension), literature files (.lit extension), ",
|
"This command only works for script files (.script or .js extension), literature files (.lit extension), ",
|
||||||
"and text files (.txt extension). ",
|
"and text files (.txt extension). ",
|
||||||
"The second argument passed in must be the hostname or IP of the target server. Examples:",
|
"The second argument passed in must be the hostname or IP of the target server. Examples:",
|
||||||
" ",
|
" ",
|
||||||
"scp foo.script n00dles",
|
" scp foo.script n00dles",
|
||||||
" ",
|
" ",
|
||||||
"scp foo.script bar.script n00dles",
|
" scp foo.script bar.script n00dles",
|
||||||
" ",
|
" ",
|
||||||
],
|
],
|
||||||
sudov: ["sudov", " ", "Prints whether or not you have root access to the current machine"],
|
sudov: ["Usage: sudov", " ", "Prints whether or not you have root access to the current machine", " "],
|
||||||
|
|
||||||
tail: [
|
tail: [
|
||||||
"tail [script name] [args...]",
|
"Usage: tail [script name] [args...]",
|
||||||
" ",
|
" ",
|
||||||
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated ",
|
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated ",
|
||||||
"by a space. Remember that a running script is uniquely identified by both its name and the arguments that were used ",
|
"by a space. Remember that a running script is uniquely identified by both its name and the arguments that were used ",
|
||||||
"to run it. So, if a script was ran with the following arguments: ",
|
"to run it. So, if a script was ran with the following arguments: ",
|
||||||
" ",
|
" ",
|
||||||
"run foo.script 10 50000",
|
" run foo.script 10 50000",
|
||||||
" ",
|
" ",
|
||||||
"Then in order to check its logs with 'tail' the same arguments must be used: ",
|
"Then in order to check its logs with 'tail' the same arguments must be used: ",
|
||||||
" ",
|
" ",
|
||||||
"tail foo.script 10 50000",
|
" tail foo.script 10 50000",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
top: [
|
top: [
|
||||||
"top",
|
"Usage: top",
|
||||||
" ",
|
" ",
|
||||||
"Prints a list of all scripts running on the current server as well as their thread count and how much ",
|
"Prints a list of all scripts running on the current server as well as their thread count and how much ",
|
||||||
"RAM they are using in total.",
|
"RAM they are using in total.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
unalias: [
|
unalias: [
|
||||||
"unalias [alias name]",
|
"Usage: unalias [alias name]",
|
||||||
" ",
|
" ",
|
||||||
"Deletes the specified alias. Note that the double quotation marks are required. ",
|
"Deletes the specified alias. Note that the double quotation marks are required. ",
|
||||||
" ",
|
" ",
|
||||||
"As an example, if an alias was declared using:",
|
"As an example, if an alias was declared using:",
|
||||||
" ",
|
" ",
|
||||||
'alias r="run"',
|
' alias r="run"',
|
||||||
" ",
|
" ",
|
||||||
"Then it could be removed using:",
|
"Then it could be removed using:",
|
||||||
" ",
|
" ",
|
||||||
"unalias r",
|
" unalias r",
|
||||||
" ",
|
" ",
|
||||||
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
vim: [
|
vim: [
|
||||||
"vim [file ...]",
|
"Usage: vim [file ...]",
|
||||||
" ",
|
" ",
|
||||||
"Opens up the specified file(s) in the Text Editor in vim mode. Only scripts (.script) or text files (.txt) can be ",
|
"Opens up the specified file(s) in the Text Editor in vim mode. Only scripts (.script) or text files (.txt) can be ",
|
||||||
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
|
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
|
||||||
"will be created",
|
"will be created",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
weaken: [
|
weaken: [
|
||||||
"weaken",
|
"Usage: weaken",
|
||||||
"",
|
" ",
|
||||||
"Reduces the security level of the current server. Decreasing the time it takes for all operations on this server.",
|
"Reduces the security level of the current server. Decreasing the time it takes for all operations on this server.",
|
||||||
"Requires root access. See the wiki page for hacking mechanics.",
|
"Requires root access. See the wiki page for hacking mechanics.",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
wget: [
|
wget: [
|
||||||
"wget [url] [target file]",
|
"Usage: wget [url] [target file]",
|
||||||
" ",
|
" ",
|
||||||
"Retrieves data from a URL and downloads it to a file on the current server. The data can only ",
|
"Retrieves data from a URL and downloads it to a file on the current server. The data can only ",
|
||||||
"be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, ",
|
"be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, ",
|
||||||
@ -433,6 +458,7 @@ export const HelpTexts: IMap<string[]> = {
|
|||||||
"Note that it will not be possible to download data from many websites because they do not allow ",
|
"Note that it will not be possible to download data from many websites because they do not allow ",
|
||||||
"cross-origin resource sharing (CORS). Example:",
|
"cross-origin resource sharing (CORS). Example:",
|
||||||
" ",
|
" ",
|
||||||
"wget https://raw.githubusercontent.com/danielyxie/bitburner/master/README.md game_readme.txt",
|
" wget https://raw.githubusercontent.com/danielyxie/bitburner/master/README.md game_readme.txt",
|
||||||
|
" ",
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -95,20 +95,42 @@ export function TerminalRoot({ terminal, router, player }: IProps): React.ReactE
|
|||||||
setKey((key) => key + 1);
|
setKey((key) => key + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => TerminalEvents.subscribe(_.debounce(async () => rerender(), 25, { maxWait: 50 })), []);
|
useEffect(() => {
|
||||||
useEffect(() => TerminalClearEvents.subscribe(_.debounce(async () => clear(), 25, { maxWait: 50 })), []);
|
const debounced = _.debounce(async () => rerender(), 25, { maxWait: 50 });
|
||||||
|
const unsubscribe = TerminalEvents.subscribe(debounced);
|
||||||
|
return () => {
|
||||||
|
debounced.cancel();
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
function doScroll(): void {
|
useEffect(() => {
|
||||||
|
const debounced = _.debounce(async () => clear(), 25, { maxWait: 50 });
|
||||||
|
const unsubscribe = TerminalClearEvents.subscribe(debounced);
|
||||||
|
return () => {
|
||||||
|
debounced.cancel();
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function doScroll(): number | undefined {
|
||||||
const hook = scrollHook.current;
|
const hook = scrollHook.current;
|
||||||
if (hook !== null) {
|
if (hook !== null) {
|
||||||
setTimeout(() => hook.scrollIntoView(true), 50);
|
return window.setTimeout(() => hook.scrollIntoView(true), 50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doScroll();
|
doScroll();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(doScroll, 50);
|
let scrollId: number;
|
||||||
|
const id = setTimeout(() => {
|
||||||
|
scrollId = doScroll() ?? 0;
|
||||||
|
}, 50);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(id);
|
||||||
|
clearTimeout(scrollId);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function lineClass(s: string): string {
|
function lineClass(s: string): string {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { cloneDeep, isEqual } from "lodash";
|
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
import { IEngine } from "../IEngine";
|
import { IEngine } from "../IEngine";
|
||||||
import { ITerminal } from "../Terminal/ITerminal";
|
import { ITerminal } from "../Terminal/ITerminal";
|
||||||
@ -86,11 +86,6 @@ interface IProps {
|
|||||||
engine: IEngine;
|
engine: IEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PageHistoryEntry {
|
|
||||||
page: Page;
|
|
||||||
args: any[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
@ -110,15 +105,6 @@ export let Router: IRouter = {
|
|||||||
page: () => {
|
page: () => {
|
||||||
throw new Error("Router called before initialization");
|
throw new Error("Router called before initialization");
|
||||||
},
|
},
|
||||||
previousPage: () => {
|
|
||||||
throw new Error("Router called before initialization");
|
|
||||||
},
|
|
||||||
clearHistory: () => {
|
|
||||||
throw new Error("Router called before initialization");
|
|
||||||
},
|
|
||||||
toPreviousPage: (): boolean => {
|
|
||||||
throw new Error("Router called before initialization");
|
|
||||||
},
|
|
||||||
toActiveScripts: () => {
|
toActiveScripts: () => {
|
||||||
throw new Error("Router called before initialization");
|
throw new Error("Router called before initialization");
|
||||||
},
|
},
|
||||||
@ -217,9 +203,7 @@ function determineStartPage(player: IPlayer): Page {
|
|||||||
export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement {
|
export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [{ files, vim }, setEditorOptions] = useState({ files: {}, vim: false });
|
const [{ files, vim }, setEditorOptions] = useState({ files: {}, vim: false });
|
||||||
const startPage = determineStartPage(player);
|
const [page, setPage] = useState(determineStartPage(player));
|
||||||
const [page, setPage] = useState(startPage);
|
|
||||||
const [pageHistory, setPageHistory] = useState<PageHistoryEntry[]>([{ page: startPage, args: [] }]);
|
|
||||||
const setRerender = useState(0)[1];
|
const setRerender = useState(0)[1];
|
||||||
const [faction, setFaction] = useState<Faction>(
|
const [faction, setFaction] = useState<Faction>(
|
||||||
player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : (undefined as unknown as Faction),
|
player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : (undefined as unknown as Faction),
|
||||||
@ -250,136 +234,70 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
setTimeout(() => htmlLocation.reload(), 2000);
|
setTimeout(() => htmlLocation.reload(), 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCurrentPage(page: Page, ...args: any): void {
|
|
||||||
const newPage = { page, args: cloneDeep(args) };
|
|
||||||
const previousPage = pageHistory[0];
|
|
||||||
const isDifferentThenPrevious = page !== previousPage?.page || !isEqual([...args], previousPage?.args);
|
|
||||||
if (isDifferentThenPrevious) {
|
|
||||||
const history = [
|
|
||||||
newPage,
|
|
||||||
...pageHistory
|
|
||||||
].slice(0, 20);
|
|
||||||
setPageHistory(history)
|
|
||||||
}
|
|
||||||
setPage(page)
|
|
||||||
}
|
|
||||||
|
|
||||||
function goBack(fallback: (...args: any[]) => void): void {
|
|
||||||
const [ , previousPage ] = pageHistory;
|
|
||||||
if (previousPage) {
|
|
||||||
const handler = pageToRouterMap[previousPage?.page];
|
|
||||||
handler(...previousPage.args);
|
|
||||||
} else {
|
|
||||||
if (fallback) fallback();
|
|
||||||
}
|
|
||||||
const [ , ...history] = pageHistory;
|
|
||||||
setPageHistory(cloneDeep(history));
|
|
||||||
}
|
|
||||||
|
|
||||||
const pageToRouterMap: { [key: number] : (...args: any[]) => void } = {
|
|
||||||
[Page.ActiveScripts]: Router.toActiveScripts,
|
|
||||||
[Page.Augmentations]: Router.toAugmentations,
|
|
||||||
[Page.Bladeburner]: Router.toBladeburner,
|
|
||||||
[Page.Stats]: Router.toStats,
|
|
||||||
[Page.Corporation]: Router.toCorporation,
|
|
||||||
[Page.CreateProgram]: Router.toCreateProgram,
|
|
||||||
[Page.DevMenu]: Router.toDevMenu,
|
|
||||||
[Page.Faction]: Router.toFaction,
|
|
||||||
[Page.Factions]: Router.toFactions,
|
|
||||||
[Page.Options]: Router.toGameOptions,
|
|
||||||
[Page.Gang]: Router.toGang,
|
|
||||||
[Page.Hacknet]: Router.toHacknetNodes,
|
|
||||||
[Page.Milestones]: Router.toMilestones,
|
|
||||||
[Page.Resleeves]: Router.toResleeves,
|
|
||||||
[Page.ScriptEditor]: Router.toScriptEditor,
|
|
||||||
[Page.Sleeves]: Router.toSleeves,
|
|
||||||
[Page.StockMarket]: Router.toStockMarket,
|
|
||||||
[Page.Terminal]: Router.toTerminal,
|
|
||||||
[Page.Tutorial]: Router.toTutorial,
|
|
||||||
[Page.Job]: Router.toJob,
|
|
||||||
[Page.City]: Router.toCity,
|
|
||||||
[Page.Travel]: Router.toTravel,
|
|
||||||
[Page.BitVerse]: Router.toBitVerse,
|
|
||||||
[Page.Infiltration]: Router.toInfiltration,
|
|
||||||
[Page.Work]: Router.toWork,
|
|
||||||
[Page.BladeburnerCinematic]: Router.toBladeburnerCinematic,
|
|
||||||
[Page.Location]: Router.toLocation,
|
|
||||||
[Page.StaneksGift]: Router.toStaneksGift,
|
|
||||||
[Page.Achievements]: Router.toAchievements,
|
|
||||||
}
|
|
||||||
|
|
||||||
Router = {
|
Router = {
|
||||||
page: () => page,
|
page: () => page,
|
||||||
previousPage: () => {
|
toActiveScripts: () => setPage(Page.ActiveScripts),
|
||||||
const [ , previousPage] = pageHistory;
|
toAugmentations: () => setPage(Page.Augmentations),
|
||||||
return previousPage?.page ?? -1;
|
toBladeburner: () => setPage(Page.Bladeburner),
|
||||||
},
|
toStats: () => setPage(Page.Stats),
|
||||||
clearHistory: () => setPageHistory([]),
|
toCorporation: () => setPage(Page.Corporation),
|
||||||
toPreviousPage: goBack,
|
toCreateProgram: () => setPage(Page.CreateProgram),
|
||||||
toActiveScripts: () => setCurrentPage(Page.ActiveScripts),
|
toDevMenu: () => setPage(Page.DevMenu),
|
||||||
toAugmentations: () => setCurrentPage(Page.Augmentations),
|
|
||||||
toBladeburner: () => setCurrentPage(Page.Bladeburner),
|
|
||||||
toStats: () => setCurrentPage(Page.Stats),
|
|
||||||
toCorporation: () => setCurrentPage(Page.Corporation),
|
|
||||||
toCreateProgram: () => setCurrentPage(Page.CreateProgram),
|
|
||||||
toDevMenu: () => setCurrentPage(Page.DevMenu),
|
|
||||||
toFaction: (faction?: Faction) => {
|
toFaction: (faction?: Faction) => {
|
||||||
setCurrentPage(Page.Faction, faction);
|
setPage(Page.Faction);
|
||||||
if (faction) setFaction(faction);
|
if (faction) setFaction(faction);
|
||||||
},
|
},
|
||||||
toFactions: () => setCurrentPage(Page.Factions),
|
toFactions: () => setPage(Page.Factions),
|
||||||
toGameOptions: () => setCurrentPage(Page.Options),
|
toGameOptions: () => setPage(Page.Options),
|
||||||
toGang: () => setCurrentPage(Page.Gang),
|
toGang: () => setPage(Page.Gang),
|
||||||
toHacknetNodes: () => setCurrentPage(Page.Hacknet),
|
toHacknetNodes: () => setPage(Page.Hacknet),
|
||||||
toMilestones: () => setCurrentPage(Page.Milestones),
|
toMilestones: () => setPage(Page.Milestones),
|
||||||
toResleeves: () => setCurrentPage(Page.Resleeves),
|
toResleeves: () => setPage(Page.Resleeves),
|
||||||
toScriptEditor: (files: Record<string, string>, options?: ScriptEditorRouteOptions) => {
|
toScriptEditor: (files: Record<string, string>, options?: ScriptEditorRouteOptions) => {
|
||||||
setEditorOptions({
|
setEditorOptions({
|
||||||
files,
|
files,
|
||||||
vim: !!options?.vim,
|
vim: !!options?.vim,
|
||||||
});
|
});
|
||||||
setCurrentPage(Page.ScriptEditor, files, options);
|
setPage(Page.ScriptEditor);
|
||||||
},
|
},
|
||||||
toSleeves: () => setCurrentPage(Page.Sleeves),
|
toSleeves: () => setPage(Page.Sleeves),
|
||||||
toStockMarket: () => setCurrentPage(Page.StockMarket),
|
toStockMarket: () => setPage(Page.StockMarket),
|
||||||
toTerminal: () => setCurrentPage(Page.Terminal),
|
toTerminal: () => setPage(Page.Terminal),
|
||||||
toTutorial: () => setCurrentPage(Page.Tutorial),
|
toTutorial: () => setPage(Page.Tutorial),
|
||||||
toJob: () => {
|
toJob: () => {
|
||||||
setLocation(Locations[player.companyName]);
|
setLocation(Locations[player.companyName]);
|
||||||
setCurrentPage(Page.Job);
|
setPage(Page.Job);
|
||||||
},
|
},
|
||||||
toCity: () => {
|
toCity: () => {
|
||||||
setCurrentPage(Page.City);
|
setPage(Page.City);
|
||||||
},
|
},
|
||||||
toTravel: () => {
|
toTravel: () => {
|
||||||
player.gotoLocation(LocationName.TravelAgency);
|
player.gotoLocation(LocationName.TravelAgency);
|
||||||
setCurrentPage(Page.Travel);
|
setPage(Page.Travel);
|
||||||
},
|
},
|
||||||
toBitVerse: (flume: boolean, quick: boolean) => {
|
toBitVerse: (flume: boolean, quick: boolean) => {
|
||||||
setFlume(flume);
|
setFlume(flume);
|
||||||
setQuick(quick);
|
setQuick(quick);
|
||||||
setCurrentPage(Page.BitVerse, flume, quick);
|
setPage(Page.BitVerse);
|
||||||
},
|
},
|
||||||
toInfiltration: (location: Location) => {
|
toInfiltration: (location: Location) => {
|
||||||
setLocation(location);
|
setLocation(location);
|
||||||
setCurrentPage(Page.Infiltration, location);
|
setPage(Page.Infiltration);
|
||||||
},
|
|
||||||
toWork: () => {
|
|
||||||
setCurrentPage(Page.Work);
|
|
||||||
},
|
},
|
||||||
|
toWork: () => setPage(Page.Work),
|
||||||
toBladeburnerCinematic: () => {
|
toBladeburnerCinematic: () => {
|
||||||
setCurrentPage(Page.BladeburnerCinematic);
|
setPage(Page.BladeburnerCinematic);
|
||||||
setCinematicText(cinematicText);
|
setCinematicText(cinematicText);
|
||||||
},
|
},
|
||||||
toLocation: (location: Location) => {
|
toLocation: (location: Location) => {
|
||||||
setLocation(location);
|
setLocation(location);
|
||||||
setCurrentPage(Page.Location, location);
|
setPage(Page.Location);
|
||||||
},
|
},
|
||||||
toStaneksGift: () => {
|
toStaneksGift: () => {
|
||||||
setCurrentPage(Page.StaneksGift);
|
setPage(Page.StaneksGift);
|
||||||
},
|
},
|
||||||
toAchievements: () => {
|
toAchievements: () => {
|
||||||
setCurrentPage(Page.Achievements);
|
setPage(Page.Achievements);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -582,11 +500,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
|||||||
<SnackbarProvider>
|
<SnackbarProvider>
|
||||||
<Overview mode={ITutorial.isRunning ? "tutorial" : "overview"}>
|
<Overview mode={ITutorial.isRunning ? "tutorial" : "overview"}>
|
||||||
{!ITutorial.isRunning ? (
|
{!ITutorial.isRunning ? (
|
||||||
<CharacterOverview
|
<CharacterOverview save={() => saveObject.saveGame()} killScripts={killAllScripts} />
|
||||||
save={() => saveObject.saveGame()}
|
|
||||||
killScripts={killAllScripts}
|
|
||||||
router={Router}
|
|
||||||
allowBackButton={withSidebar} />
|
|
||||||
) : (
|
) : (
|
||||||
<InteractiveTutorialRoot />
|
<InteractiveTutorialRoot />
|
||||||
)}
|
)}
|
||||||
|
@ -17,22 +17,19 @@ import Typography from "@mui/material/Typography";
|
|||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import SaveIcon from "@mui/icons-material/Save";
|
import SaveIcon from "@mui/icons-material/Save";
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
|
||||||
import ClearAllIcon from "@mui/icons-material/ClearAll";
|
import ClearAllIcon from "@mui/icons-material/ClearAll";
|
||||||
|
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { use } from "../Context";
|
import { use } from "../Context";
|
||||||
import { StatsProgressOverviewCell } from "./StatsProgressBar";
|
import { StatsProgressOverviewCell } from "./StatsProgressBar";
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { IRouter, Page } from "../Router";
|
|
||||||
import { Box, Tooltip } from "@mui/material";
|
import { Box, Tooltip } from "@mui/material";
|
||||||
import { CONSTANTS } from "../../Constants";
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
save: () => void;
|
save: () => void;
|
||||||
killScripts: () => void;
|
killScripts: () => void;
|
||||||
router: IRouter;
|
|
||||||
allowBackButton: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Intelligence(): React.ReactElement {
|
function Intelligence(): React.ReactElement {
|
||||||
@ -239,7 +236,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
|
|
||||||
export { useStyles as characterOverviewStyles };
|
export { useStyles as characterOverviewStyles };
|
||||||
|
|
||||||
export function CharacterOverview({ save, killScripts, router, allowBackButton }: IProps): React.ReactElement {
|
export function CharacterOverview({ save, killScripts }: IProps): React.ReactElement {
|
||||||
const [killOpen, setKillOpen] = useState(false);
|
const [killOpen, setKillOpen] = useState(false);
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
|
|
||||||
@ -278,9 +275,6 @@ export function CharacterOverview({ save, killScripts, router, allowBackButton }
|
|||||||
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||||
);
|
);
|
||||||
|
|
||||||
const previousPageName =
|
|
||||||
router.previousPage() < 0 ? "" : Page[router.previousPage() ?? 0].replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Table sx={{ display: "block", m: 1 }}>
|
<Table sx={{ display: "block", m: 1 }}>
|
||||||
@ -464,13 +458,6 @@ export function CharacterOverview({ save, killScripts, router, allowBackButton }
|
|||||||
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
|
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{allowBackButton && (
|
|
||||||
<IconButton disabled={!previousPageName} onClick={() => router.toPreviousPage()}>
|
|
||||||
<Tooltip title={previousPageName ? `Go back to "${previousPageName}"` : ""}>
|
|
||||||
<ArrowBackIcon />
|
|
||||||
</Tooltip>
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: "flex", flex: 1, justifyContent: "flex-end", alignItems: "center" }}>
|
<Box sx={{ display: "flex", flex: 1, justifyContent: "flex-end", alignItems: "center" }}>
|
||||||
<IconButton onClick={() => setKillOpen(true)}>
|
<IconButton onClick={() => setKillOpen(true)}>
|
||||||
|
@ -25,20 +25,22 @@ export function CorruptableText(props: IProps): JSX.Element {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let counter = 5;
|
let counter = 5;
|
||||||
const id = setInterval(() => {
|
const timers: number[] = [];
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
counter--;
|
counter--;
|
||||||
if (counter > 0) return;
|
if (counter > 0) return;
|
||||||
counter = Math.random() * 5;
|
counter = Math.random() * 5;
|
||||||
const index = Math.random() * content.length;
|
const index = Math.random() * content.length;
|
||||||
const letter = content.charAt(index);
|
const letter = content.charAt(index);
|
||||||
setContent((content) => replace(content, index, randomize(letter)));
|
setContent((content) => replace(content, index, randomize(letter)));
|
||||||
setTimeout(() => {
|
timers.push(window.setTimeout(() => {
|
||||||
setContent((content) => replace(content, index, letter));
|
setContent((content) => replace(content, index, letter));
|
||||||
}, 500);
|
}, 500));
|
||||||
}, 20);
|
}, 20);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(id);
|
clearInterval(intervalId);
|
||||||
|
timers.forEach((timerId) => clearTimeout(timerId));
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -7,12 +7,13 @@ import Typography from "@mui/material/Typography";
|
|||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import ReplyIcon from "@mui/icons-material/Reply";
|
import ReplyIcon from "@mui/icons-material/Reply";
|
||||||
import SaveIcon from '@mui/icons-material/Save';
|
import SaveIcon from "@mui/icons-material/Save";
|
||||||
|
|
||||||
import { ThemeEvents } from "./Theme";
|
import { ThemeEvents } from "./Theme";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { IStyleSettings, defaultStyles } from "../../Settings/Styles";
|
import { defaultStyles } from "../../Settings/Styles";
|
||||||
import { Tooltip } from "@mui/material";
|
import { Tooltip } from "@mui/material";
|
||||||
|
import { IStyleSettings } from "../../ScriptEditor/NetscriptDefinitions";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -25,16 +26,16 @@ interface FontFamilyProps {
|
|||||||
refreshId: number;
|
refreshId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FontFamilyField({ value, onChange, refreshId } : FontFamilyProps): React.ReactElement {
|
function FontFamilyField({ value, onChange, refreshId }: FontFamilyProps): React.ReactElement {
|
||||||
const [errorText, setErrorText] = useState<string | undefined>();
|
const [errorText, setErrorText] = useState<string | undefined>();
|
||||||
const [fontFamily, setFontFamily] = useState<React.CSSProperties["fontFamily"]>(value);
|
const [fontFamily, setFontFamily] = useState<React.CSSProperties["fontFamily"]>(value);
|
||||||
|
|
||||||
function update(newValue: React.CSSProperties["fontFamily"]): void {
|
function update(newValue: React.CSSProperties["fontFamily"]): void {
|
||||||
setFontFamily(newValue);
|
setFontFamily(newValue);
|
||||||
if (!newValue) {
|
if (!newValue) {
|
||||||
setErrorText('Must have a value');
|
setErrorText("Must have a value");
|
||||||
} else {
|
} else {
|
||||||
setErrorText('');
|
setErrorText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ function FontFamilyField({ value, onChange, refreshId } : FontFamilyProps): Reac
|
|||||||
onChange={onTextChange}
|
onChange={onTextChange}
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LineHeightProps {
|
interface LineHeightProps {
|
||||||
@ -64,18 +65,18 @@ interface LineHeightProps {
|
|||||||
refreshId: number;
|
refreshId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function LineHeightField({ value, onChange, refreshId } : LineHeightProps): React.ReactElement {
|
function LineHeightField({ value, onChange, refreshId }: LineHeightProps): React.ReactElement {
|
||||||
const [errorText, setErrorText] = useState<string | undefined>();
|
const [errorText, setErrorText] = useState<string | undefined>();
|
||||||
const [lineHeight, setLineHeight] = useState<React.CSSProperties["lineHeight"]>(value);
|
const [lineHeight, setLineHeight] = useState<React.CSSProperties["lineHeight"]>(value);
|
||||||
|
|
||||||
function update(newValue: React.CSSProperties["lineHeight"]): void {
|
function update(newValue: React.CSSProperties["lineHeight"]): void {
|
||||||
setLineHeight(newValue);
|
setLineHeight(newValue);
|
||||||
if (!newValue) {
|
if (!newValue) {
|
||||||
setErrorText('Must have a value');
|
setErrorText("Must have a value");
|
||||||
} else if (isNaN(Number(newValue))) {
|
} else if (isNaN(Number(newValue))) {
|
||||||
setErrorText('Must be a number');
|
setErrorText("Must be a number");
|
||||||
} else {
|
} else {
|
||||||
setErrorText('');
|
setErrorText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ function LineHeightField({ value, onChange, refreshId } : LineHeightProps): Reac
|
|||||||
helperText={errorText}
|
helperText={errorText}
|
||||||
onChange={onTextChange}
|
onChange={onTextChange}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StyleEditorModal(props: IProps): React.ReactElement {
|
export function StyleEditorModal(props: IProps): React.ReactElement {
|
||||||
@ -115,7 +116,7 @@ export function StyleEditorModal(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setDefaults(): void {
|
function setDefaults(): void {
|
||||||
const styles = {...defaultStyles}
|
const styles = { ...defaultStyles };
|
||||||
setCustomStyle(styles);
|
setCustomStyle(styles);
|
||||||
persistToSettings(styles);
|
persistToSettings(styles);
|
||||||
setRefreshId(refreshId + 1);
|
setRefreshId(refreshId + 1);
|
||||||
@ -132,16 +133,23 @@ export function StyleEditorModal(props: IProps): React.ReactElement {
|
|||||||
<Modal open={props.open} onClose={props.onClose}>
|
<Modal open={props.open} onClose={props.onClose}>
|
||||||
<Typography variant="h6">Styles Editor</Typography>
|
<Typography variant="h6">Styles Editor</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
WARNING: Changing styles <strong>may mess up</strong> the interface. Drastic changes are <strong>NOT recommended</strong>.
|
WARNING: Changing styles <strong>may mess up</strong> the interface. Drastic changes are{" "}
|
||||||
|
<strong>NOT recommended</strong>.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Paper sx={{ p: 2, my: 2 }}>
|
<Paper sx={{ p: 2, my: 2 }}>
|
||||||
<FontFamilyField value={customStyle.fontFamily} refreshId={refreshId}
|
<FontFamilyField
|
||||||
onChange={(value, error) => update({ ...customStyle, fontFamily: value }, error)} />
|
value={customStyle.fontFamily}
|
||||||
|
refreshId={refreshId}
|
||||||
|
onChange={(value, error) => update({ ...customStyle, fontFamily: value as any }, error)}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<LineHeightField value={customStyle.lineHeight} refreshId={refreshId}
|
<LineHeightField
|
||||||
onChange={(value, error) => update({ ...customStyle, lineHeight: value }, error)} />
|
value={customStyle.lineHeight}
|
||||||
|
refreshId={refreshId}
|
||||||
|
onChange={(value, error) => update({ ...customStyle, lineHeight: value as any }, error)}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<ButtonGroup sx={{ my: 1}}>
|
<ButtonGroup sx={{ my: 1 }}>
|
||||||
<Button onClick={setDefaults} startIcon={<ReplyIcon />} color="secondary" variant="outlined">
|
<Button onClick={setDefaults} startIcon={<ReplyIcon />} color="secondary" variant="outlined">
|
||||||
Revert to Defaults
|
Revert to Defaults
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -53,9 +53,6 @@ export interface IRouter {
|
|||||||
// toRedPill(): void;
|
// toRedPill(): void;
|
||||||
// toworkInProgress(): void;
|
// toworkInProgress(): void;
|
||||||
page(): Page;
|
page(): Page;
|
||||||
previousPage(): Page;
|
|
||||||
clearHistory(): void;
|
|
||||||
toPreviousPage(fallback?: (...args: any[]) => void): void;
|
|
||||||
toActiveScripts(): void;
|
toActiveScripts(): void;
|
||||||
toAugmentations(): void;
|
toAugmentations(): void;
|
||||||
toBitVerse(flume: boolean, quick: boolean): void;
|
toBitVerse(flume: boolean, quick: boolean): void;
|
||||||
|
@ -36,12 +36,12 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
const faction = Factions[player.currentWorkFactionName];
|
const faction = Factions[player.currentWorkFactionName];
|
||||||
if (player.workType == CONSTANTS.WorkTypeFaction) {
|
if (player.workType == CONSTANTS.WorkTypeFaction) {
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
|
router.toFaction(faction);
|
||||||
player.finishFactionWork(true);
|
player.finishFactionWork(true);
|
||||||
router.toPreviousPage(() => router.toFaction(faction));
|
|
||||||
}
|
}
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
|
router.toFaction(faction);
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
router.toPreviousPage(() => router.toFaction(faction));
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
|
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
|
||||||
@ -120,12 +120,13 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
if (player.className !== "") {
|
if (player.className !== "") {
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
player.finishClass(true);
|
player.finishClass(true);
|
||||||
router.toPreviousPage(() => router.toCity());
|
router.toCity();
|
||||||
}
|
}
|
||||||
|
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
|
router.toFaction(faction);
|
||||||
|
router.toCity();
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
router.toPreviousPage(() => router.toCity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let stopText = "";
|
let stopText = "";
|
||||||
@ -211,11 +212,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
|
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
player.finishWork(true);
|
player.finishWork(true);
|
||||||
router.toPreviousPage(() => router.toJob());
|
router.toJob();
|
||||||
}
|
}
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
router.toPreviousPage(() => router.toJob());
|
router.toJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
const position = player.jobs[player.companyName];
|
const position = player.jobs[player.companyName];
|
||||||
@ -303,11 +304,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
player.finishWorkPartTime(true);
|
player.finishWorkPartTime(true);
|
||||||
router.toPreviousPage(() => router.toJob());
|
router.toJob();
|
||||||
}
|
}
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
router.toPreviousPage(() => router.toJob());
|
router.toJob();
|
||||||
}
|
}
|
||||||
const comp = Companies[player.companyName];
|
const comp = Companies[player.companyName];
|
||||||
let companyRep = 0;
|
let companyRep = 0;
|
||||||
@ -439,11 +440,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
|||||||
if (player.createProgramName !== "") {
|
if (player.createProgramName !== "") {
|
||||||
function cancel(): void {
|
function cancel(): void {
|
||||||
player.finishCreateProgramWork(true);
|
player.finishCreateProgramWork(true);
|
||||||
router.toPreviousPage(() => router.toTerminal());
|
router.toTerminal();
|
||||||
}
|
}
|
||||||
function unfocus(): void {
|
function unfocus(): void {
|
||||||
|
router.toTerminal();
|
||||||
player.stopFocusing();
|
player.stopFocusing();
|
||||||
router.toPreviousPage(() => router.toTerminal());
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
|
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
|
||||||
|
Loading…
Reference in New Issue
Block a user