mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-02-17 02:22:23 +01:00
More work on terminal.
This commit is contained in:
@ -12,6 +12,7 @@ import MenuItem from "@material-ui/core/MenuItem";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import ReplyAllIcon from "@material-ui/icons/ReplyAll";
|
||||
import ReplyIcon from "@material-ui/icons/Reply";
|
||||
import ClearIcon from "@material-ui/icons/Clear";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
@ -33,6 +34,11 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
props.player.queueAugmentation(augName);
|
||||
}
|
||||
}
|
||||
|
||||
function clearAugs(): void {
|
||||
props.player.augmentations = [];
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
@ -61,6 +67,13 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
endAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={clearAugs}>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{Object.values(AugmentationNames).map((aug) => (
|
||||
<MenuItem key={aug} value={aug}>
|
||||
|
@ -1,54 +1,5 @@
|
||||
import { determineAllPossibilitiesForTabCompletion } from "./Terminal/determineAllPossibilitiesForTabCompletion";
|
||||
import { tabCompletion } from "./Terminal/tabCompletion";
|
||||
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import { Player } from "./Player";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { KEY } from "../utils/helpers/keyCodes";
|
||||
import { getTimestamp } from "../utils/helpers/getTimestamp";
|
||||
|
||||
import { Terminal as TTerminal } from "./Terminal/Terminal";
|
||||
|
||||
const Terminal = new TTerminal();
|
||||
|
||||
// Defines key commands in terminal
|
||||
$(document).keydown(function (event) {
|
||||
// Terminal
|
||||
|
||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||
if (Engine._actionInProgress) {
|
||||
// Cancel action
|
||||
// post("Cancelling...");
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction(true);
|
||||
} else if (FconfSettings.ENABLE_BASH_HOTKEYS) {
|
||||
// Dont prevent default so it still copies
|
||||
Terminal.clear(); // Clear Terminal
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).keydown(function (e) {
|
||||
if (routing.isOn(Page.Terminal)) {
|
||||
if (e.which == KEY.CTRL) {
|
||||
terminalCtrlPressed = true;
|
||||
} else if (e.shiftKey) {
|
||||
shiftKeyPressed = true;
|
||||
} else if (terminalCtrlPressed || shiftKeyPressed || Terminal.contractOpen) {
|
||||
// Don't focus
|
||||
} else {
|
||||
var inputTextBox = document.getElementById("terminal-input-text-box");
|
||||
if (inputTextBox != null) {
|
||||
inputTextBox.focus();
|
||||
}
|
||||
|
||||
terminalCtrlPressed = false;
|
||||
shiftKeyPressed = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export { Terminal };
|
||||
|
@ -3,23 +3,44 @@ import { Script } from "../Script/Script";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../IEngine";
|
||||
|
||||
export interface IOutput {
|
||||
export class Output {
|
||||
text: string;
|
||||
color: "inherit" | "initial" | "primary" | "secondary" | "error" | "textPrimary" | "textSecondary" | undefined;
|
||||
constructor(
|
||||
text: string,
|
||||
color: "inherit" | "initial" | "primary" | "secondary" | "error" | "textPrimary" | "textSecondary" | undefined,
|
||||
) {
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
export class Link {
|
||||
hostname: string;
|
||||
constructor(hostname: string) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
}
|
||||
|
||||
export class TTimer {
|
||||
time: number;
|
||||
timeLeft: number;
|
||||
action: "h" | "b" | "a";
|
||||
|
||||
constructor(time: number, action: "h" | "b" | "a") {
|
||||
this.time = time;
|
||||
this.timeLeft = time;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITerminal {
|
||||
// Flags to determine whether the player is currently running a hack or an analyze
|
||||
hackFlag: boolean;
|
||||
backdoorFlag: boolean;
|
||||
analyzeFlag: boolean;
|
||||
actionStarted: boolean;
|
||||
actionTime: number;
|
||||
action: TTimer | null;
|
||||
|
||||
commandHistory: string[];
|
||||
commandHistoryIndex: number;
|
||||
|
||||
outputHistory: IOutput[];
|
||||
outputHistory: (Output | Link)[];
|
||||
|
||||
// True if a Coding Contract prompt is opened
|
||||
contractOpen: boolean;
|
||||
@ -53,4 +74,7 @@ export interface ITerminal {
|
||||
executeCommands(engine: IEngine, player: IPlayer, commands: string): void;
|
||||
// If there was any changes, will return true, once.
|
||||
pollChanges(): boolean;
|
||||
process(player: IPlayer, cycles: number): void;
|
||||
prestige(): void;
|
||||
getProgressText(): string;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { postContent, hackProgressBarPost, hackProgressPost } from "../ui/postToTerminal";
|
||||
import { ITerminal, IOutput } from "./ITerminal";
|
||||
import { ITerminal, Output, Link, TTimer } from "./ITerminal";
|
||||
import { IEngine } from "../IEngine";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
@ -8,7 +8,6 @@ import { hackWorldDaemon } from "../RedPill";
|
||||
import { Programs } from "../Programs/Programs";
|
||||
import { CodingContractResult } from "../CodingContracts";
|
||||
|
||||
import { Terminal as OldTerminal } from "../Terminal";
|
||||
import { TextFile } from "../TextFile";
|
||||
import { Script } from "../Script/Script";
|
||||
import { isScriptFilename } from "../Script/ScriptHelpersTS";
|
||||
@ -24,6 +23,7 @@ import { TerminalHelpText } from "./HelpText";
|
||||
import { GetServerByHostname, getServer, getServerOnNetwork } from "../Server/ServerHelpers";
|
||||
import { ParseCommand, ParseCommands } from "./Parser";
|
||||
import { SpecialServerIps, SpecialServerNames } from "../Server/SpecialServerIps";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
import {
|
||||
calculateHackingChance,
|
||||
calculateHackingExpGain,
|
||||
@ -72,16 +72,12 @@ import { wget } from "./commands/wget";
|
||||
export class Terminal implements ITerminal {
|
||||
hasChanges = false;
|
||||
// Flags to determine whether the player is currently running a hack or an analyze
|
||||
hackFlag = false;
|
||||
backdoorFlag = false;
|
||||
analyzeFlag = false;
|
||||
actionStarted = false;
|
||||
actionTime = 0;
|
||||
action: TTimer | null = null;
|
||||
|
||||
commandHistory: string[] = [];
|
||||
commandHistoryIndex = 0;
|
||||
|
||||
outputHistory: IOutput[] = [{ text: `Bitburner v${CONSTANTS.Version}`, color: "primary" }];
|
||||
outputHistory: (Output | Link)[] = [{ text: `Bitburner v${CONSTANTS.Version}`, color: "primary" }];
|
||||
|
||||
// True if a Coding Contract prompt is opened
|
||||
contractOpen = false;
|
||||
@ -90,6 +86,13 @@ export class Terminal implements ITerminal {
|
||||
// Excludes the trailing forward slash
|
||||
currDir = "/";
|
||||
|
||||
process(player: IPlayer, cycles: number): void {
|
||||
if (this.action === null) return;
|
||||
this.action.timeLeft -= (CONSTANTS._idleSpeed * cycles) / 1000;
|
||||
this.hasChanges = true;
|
||||
if (this.action.timeLeft < 0) this.finishAction(player, false);
|
||||
}
|
||||
|
||||
pollChanges(): boolean {
|
||||
if (this.hasChanges) {
|
||||
this.hasChanges = false;
|
||||
@ -99,105 +102,85 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
|
||||
print(s: string, config?: any): void {
|
||||
this.outputHistory.push({ text: s, color: "primary" });
|
||||
this.outputHistory.push(new Output(s, "primary"));
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
error(s: string): void {
|
||||
this.outputHistory.push({ text: s, color: "error" });
|
||||
this.outputHistory.push(new Output(s, "error"));
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
startHack(player: IPlayer): void {
|
||||
this.hackFlag = true;
|
||||
|
||||
// Hacking through Terminal should be faster than hacking through a script
|
||||
this.actionTime = calculateHackingTime(player.getCurrentServer(), player) / 4;
|
||||
this.startAction();
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "h");
|
||||
}
|
||||
|
||||
startBackdoor(player: IPlayer): void {
|
||||
this.backdoorFlag = true;
|
||||
|
||||
// Backdoor should take the same amount of time as hack
|
||||
this.actionTime = calculateHackingTime(player.getCurrentServer(), player) / 4;
|
||||
this.startAction();
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "b");
|
||||
}
|
||||
|
||||
startAnalyze(): void {
|
||||
this.analyzeFlag = true;
|
||||
this.actionTime = 1;
|
||||
this.print("Analyzing system...");
|
||||
this.startAction();
|
||||
this.startAction(1, "a");
|
||||
}
|
||||
|
||||
startAction(): void {
|
||||
this.actionStarted = true;
|
||||
|
||||
hackProgressPost("Time left:");
|
||||
hackProgressBarPost("[");
|
||||
|
||||
// Disable terminal
|
||||
const elem = document.getElementById("terminal-input-td");
|
||||
if (!elem) throw new Error("terminal-input-td should not be null");
|
||||
elem.innerHTML = '<input type="text" class="terminal-input"/>';
|
||||
$("input[class=terminal-input]").prop("disabled", true);
|
||||
startAction(n: number, action: "h" | "b" | "a"): void {
|
||||
this.action = new TTimer(n, action);
|
||||
}
|
||||
|
||||
// Complete the hack/analyze command
|
||||
finishHack(player: IPlayer, cancelled = false): void {
|
||||
if (!cancelled) {
|
||||
const server = player.getCurrentServer();
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
|
||||
// Calculate whether hack was successful
|
||||
const hackChance = calculateHackingChance(server, player);
|
||||
const rand = Math.random();
|
||||
const expGainedOnSuccess = calculateHackingExpGain(server, player);
|
||||
const expGainedOnFailure = expGainedOnSuccess / 4;
|
||||
if (rand < hackChance) {
|
||||
// Success!
|
||||
if (
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
|
||||
) {
|
||||
if (player.bitNodeN == null) {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
this.hackFlag = false;
|
||||
return;
|
||||
// Calculate whether hack was successful
|
||||
const hackChance = calculateHackingChance(server, player);
|
||||
const rand = Math.random();
|
||||
const expGainedOnSuccess = calculateHackingExpGain(server, player);
|
||||
const expGainedOnFailure = expGainedOnSuccess / 4;
|
||||
if (rand < hackChance) {
|
||||
// Success!
|
||||
if (
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
|
||||
) {
|
||||
if (player.bitNodeN == null) {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
let moneyGained = calculatePercentMoneyHacked(server, player);
|
||||
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
||||
|
||||
if (moneyGained <= 0) {
|
||||
moneyGained = 0;
|
||||
} // Safety check
|
||||
|
||||
server.moneyAvailable -= moneyGained;
|
||||
player.gainMoney(moneyGained);
|
||||
player.recordMoneySource(moneyGained, "hacking");
|
||||
player.gainHackingExp(expGainedOnSuccess);
|
||||
player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
||||
|
||||
server.fortify(CONSTANTS.ServerFortifyAmount);
|
||||
|
||||
this.print(
|
||||
`Hack successful! Gained ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(
|
||||
expGainedOnSuccess,
|
||||
)} hacking exp`,
|
||||
);
|
||||
} else {
|
||||
// Failure
|
||||
// player only gains 25% exp for failure? TODO Can change this later to balance
|
||||
player.gainHackingExp(expGainedOnFailure);
|
||||
this.print(
|
||||
`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`,
|
||||
);
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
let moneyGained = calculatePercentMoneyHacked(server, player);
|
||||
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
|
||||
|
||||
if (moneyGained <= 0) {
|
||||
moneyGained = 0;
|
||||
} // Safety check
|
||||
|
||||
server.moneyAvailable -= moneyGained;
|
||||
player.gainMoney(moneyGained);
|
||||
player.recordMoneySource(moneyGained, "hacking");
|
||||
player.gainHackingExp(expGainedOnSuccess);
|
||||
player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
|
||||
|
||||
server.fortify(CONSTANTS.ServerFortifyAmount);
|
||||
|
||||
this.print(
|
||||
`Hack successful! Gained ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(
|
||||
expGainedOnSuccess,
|
||||
)} hacking exp`,
|
||||
);
|
||||
} else {
|
||||
// Failure
|
||||
// player only gains 25% exp for failure? TODO Can change this later to balance
|
||||
player.gainHackingExp(expGainedOnFailure);
|
||||
this.print(
|
||||
`Failed to hack ${server.hostname}. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} hacking exp`,
|
||||
);
|
||||
}
|
||||
this.hackFlag = false;
|
||||
}
|
||||
|
||||
finishBackdoor(player: IPlayer, cancelled = false): void {
|
||||
@ -211,13 +194,11 @@ export class Terminal implements ITerminal {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
this.backdoorFlag = false;
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
this.print("Backdoor successful!");
|
||||
}
|
||||
this.backdoorFlag = false;
|
||||
}
|
||||
|
||||
finishAnalyze(player: IPlayer, cancelled = false): void {
|
||||
@ -248,22 +229,25 @@ export class Terminal implements ITerminal {
|
||||
this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed"));
|
||||
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed"));
|
||||
}
|
||||
this.analyzeFlag = false;
|
||||
}
|
||||
|
||||
finishAction(player: IPlayer, cancelled = false): void {
|
||||
if (this.hackFlag) {
|
||||
if (this.action === null) {
|
||||
if (!cancelled) throw new Error("Finish action called when there was no action");
|
||||
return;
|
||||
}
|
||||
this.print(this.getProgressText());
|
||||
if (this.action.action === "h") {
|
||||
this.finishHack(player, cancelled);
|
||||
} else if (this.backdoorFlag) {
|
||||
} else if (this.action.action === "b") {
|
||||
this.finishBackdoor(player, cancelled);
|
||||
} else if (this.analyzeFlag) {
|
||||
} else if (this.action.action === "a") {
|
||||
this.finishAnalyze(player, cancelled);
|
||||
}
|
||||
|
||||
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
||||
$("#hack-progress-bar").attr("id", "old-hack-progress-bar");
|
||||
$("#hack-progress").attr("id", "old-hack-progress");
|
||||
$("input[class=terminal-input]").prop("disabled", false);
|
||||
if (cancelled) {
|
||||
this.print("Cancelled");
|
||||
}
|
||||
this.action = null;
|
||||
}
|
||||
|
||||
getFile(player: IPlayer, filename: string): Script | TextFile | string | null {
|
||||
@ -427,7 +411,7 @@ export class Terminal implements ITerminal {
|
||||
} // Don't print current server
|
||||
const titleDashes = Array((d - 1) * 4 + 1).join("-");
|
||||
if (player.hasProgram(Programs.AutoLink.name)) {
|
||||
this.print(s.hostname);
|
||||
this.outputHistory.push(new Link(s.hostname));
|
||||
} else {
|
||||
this.print(s.hostname);
|
||||
}
|
||||
@ -452,7 +436,7 @@ export class Terminal implements ITerminal {
|
||||
(() => {
|
||||
const hostname = links[i].innerHTML.toString();
|
||||
links[i].addEventListener("onclick", () => {
|
||||
if (this.analyzeFlag || this.hackFlag || this.backdoorFlag) {
|
||||
if (this.action !== null) {
|
||||
return;
|
||||
}
|
||||
this.connectToServer(player, hostname);
|
||||
@ -498,12 +482,17 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.outputHistory = [{ text: `Bitburner v${CONSTANTS.Version}`, color: "primary" }];
|
||||
this.outputHistory = [new Output(`Bitburner v${CONSTANTS.Version}`, "primary")];
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
prestige(): void {
|
||||
this.action = null;
|
||||
this.clear();
|
||||
}
|
||||
|
||||
executeCommand(engine: IEngine, player: IPlayer, command: string): void {
|
||||
if (this.hackFlag || this.backdoorFlag || this.analyzeFlag) {
|
||||
if (this.action !== null) {
|
||||
this.error(`Cannot execute command (${command}) while an action is in progress`);
|
||||
return;
|
||||
}
|
||||
@ -718,4 +707,12 @@ export class Terminal implements ITerminal {
|
||||
|
||||
f(this, engine, player, s, commandArray.slice(1));
|
||||
}
|
||||
|
||||
getProgressText(): string {
|
||||
if (this.action === null) throw new Error("trying to get the progress text when there's no action");
|
||||
return createProgressBarText({
|
||||
progress: (this.action.time - this.action.timeLeft) / this.action.time,
|
||||
totalTicks: 50,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,30 @@ import React, { useState, useEffect, useRef } from "react";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import { Link as MuiLink } from "@material-ui/core";
|
||||
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { ITerminal } from "../ITerminal";
|
||||
import { ITerminal, Output, Link, TTimer } from "../ITerminal";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { determineAllPossibilitiesForTabCompletion } from "../determineAllPossibilitiesForTabCompletion";
|
||||
import { tabCompletion } from "../tabCompletion";
|
||||
import { FconfSettings } from "../../Fconf/FconfSettings";
|
||||
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
|
||||
|
||||
interface IActionTimerProps {
|
||||
terminal: ITerminal;
|
||||
}
|
||||
|
||||
function ActionTimer({ terminal }: IActionTimerProps): React.ReactElement {
|
||||
return (
|
||||
<Typography color={"primary"} paragraph={false}>
|
||||
{terminal.getProgressText()}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@ -150,6 +164,11 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE
|
||||
if (terminal.contractOpen) return;
|
||||
const ref = terminalInput.current;
|
||||
if (ref) ref.focus();
|
||||
|
||||
// Cancel action
|
||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||
terminal.finishAction(player, true);
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", keyDown);
|
||||
return () => document.removeEventListener("keydown", keyDown);
|
||||
@ -328,15 +347,31 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE
|
||||
}
|
||||
|
||||
return (
|
||||
<Box position="fixed" bottom="0" width="100%">
|
||||
<Box position="fixed" bottom="0" width="100%" px={1}>
|
||||
<List classes={{ root: classes.nopadding }}>
|
||||
{terminal.outputHistory.map((output, i) => (
|
||||
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
||||
<Typography classes={{ root: classes.preformatted }} color={output.color} paragraph={false}>
|
||||
{output.text}
|
||||
</Typography>
|
||||
</ListItem>
|
||||
))}
|
||||
{terminal.outputHistory.map((item, i) => {
|
||||
if (item instanceof Output)
|
||||
return (
|
||||
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
||||
<Typography classes={{ root: classes.preformatted }} color={item.color} paragraph={false}>
|
||||
{item.text}
|
||||
</Typography>
|
||||
</ListItem>
|
||||
);
|
||||
if (item instanceof Link)
|
||||
return (
|
||||
<ListItem key={i} classes={{ root: classes.nopadding }}>
|
||||
<MuiLink
|
||||
classes={{ root: classes.preformatted }}
|
||||
color={"secondary"}
|
||||
paragraph={false}
|
||||
onClick={() => terminal.connectToServer(player, item.hostname)}
|
||||
>
|
||||
> {item.hostname}
|
||||
</MuiLink>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
{possibilities.length > 0 && (
|
||||
<>
|
||||
@ -348,17 +383,23 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
{terminal.action !== null && <ActionTimer terminal={terminal} />}
|
||||
<TextField
|
||||
color={terminal.action === null ? "primary" : "secondary"}
|
||||
autoFocus
|
||||
disabled={terminal.action !== null}
|
||||
autoComplete="off"
|
||||
classes={{ root: classes.textfield }}
|
||||
value={value}
|
||||
onChange={handleValueChange}
|
||||
inputRef={terminalInput}
|
||||
InputProps={{
|
||||
// for players to hook in
|
||||
id: "terminal-input",
|
||||
className: classes.input,
|
||||
startAdornment: (
|
||||
<>
|
||||
<Typography color="primary">
|
||||
<Typography color={terminal.action === null ? "primary" : "secondary"}>
|
||||
[{player.getCurrentServer().hostname} ~{terminal.cwd()}]>
|
||||
</Typography>
|
||||
</>
|
||||
|
@ -444,16 +444,7 @@ const Engine = {
|
||||
Player.playtimeSinceLastAug += time;
|
||||
Player.playtimeSinceLastBitnode += time;
|
||||
|
||||
// Start Manual hack
|
||||
if (Terminal.actionStarted === true) {
|
||||
Engine._totalActionTime = Terminal.actionTime;
|
||||
Engine._actionTimeLeft = Terminal.actionTime;
|
||||
Engine._actionInProgress = true;
|
||||
Engine._actionProgressBarCount = 1;
|
||||
Engine._actionProgressStr = "[ ]";
|
||||
Engine._actionTimeStr = "Time left: ";
|
||||
Terminal.actionStarted = false;
|
||||
}
|
||||
Terminal.process(Player, numCycles);
|
||||
|
||||
// Working
|
||||
if (Player.isWorking) {
|
||||
@ -519,11 +510,6 @@ const Engine = {
|
||||
Engine.decrementAllCounters(numCycles);
|
||||
Engine.checkCounters();
|
||||
|
||||
// Manual hacks
|
||||
if (Engine._actionInProgress == true) {
|
||||
Engine.updateHackProgress(numCycles);
|
||||
}
|
||||
|
||||
// Update the running time of all active scripts
|
||||
updateOnlineScriptTimes(numCycles);
|
||||
|
||||
@ -623,42 +609,6 @@ const Engine = {
|
||||
}
|
||||
},
|
||||
|
||||
// Calculates the hack progress for a manual (non-scripted) hack and updates the progress bar/time accordingly
|
||||
// TODO Refactor this into Terminal module
|
||||
_totalActionTime: 0,
|
||||
_actionTimeLeft: 0,
|
||||
_actionTimeStr: "Time left: ",
|
||||
_actionProgressStr: "[ ]",
|
||||
_actionProgressBarCount: 1,
|
||||
_actionInProgress: false,
|
||||
updateHackProgress: function (numCycles = 1) {
|
||||
var timeElapsedMilli = numCycles * Engine._idleSpeed;
|
||||
Engine._actionTimeLeft -= timeElapsedMilli / 1000; // Substract idle speed (ms)
|
||||
Engine._actionTimeLeft = Math.max(Engine._actionTimeLeft, 0);
|
||||
|
||||
// Calculate percent filled
|
||||
var percent = Math.round((1 - Engine._actionTimeLeft / Engine._totalActionTime) * 100);
|
||||
|
||||
// Update progress bar
|
||||
while (Engine._actionProgressBarCount * 2 <= percent) {
|
||||
Engine._actionProgressStr = replaceAt(Engine._actionProgressStr, Engine._actionProgressBarCount, "|");
|
||||
Engine._actionProgressBarCount += 1;
|
||||
}
|
||||
|
||||
// Update hack time remaining
|
||||
Engine._actionTimeStr = "Time left: " + Math.max(0, Math.round(Engine._actionTimeLeft)).toString() + "s";
|
||||
document.getElementById("hack-progress").innerHTML = Engine._actionTimeStr;
|
||||
|
||||
// Dynamically update progress bar
|
||||
document.getElementById("hack-progress-bar").innerHTML = Engine._actionProgressStr.replace(/ /g, " ");
|
||||
|
||||
// Once percent is 100, the hack is completed
|
||||
if (percent >= 100) {
|
||||
Engine._actionInProgress = false;
|
||||
Terminal.finishAction();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used in game when clicking on a main menu header (NOT used for initialization)
|
||||
* @param open {boolean} Whether header is being opened or closed
|
||||
|
Reference in New Issue
Block a user