most terminal converted to ts

This commit is contained in:
Olivier Gagnon 2021-09-15 19:50:44 -04:00
parent 8097364242
commit 2922e42055
60 changed files with 2998 additions and 2259 deletions

13
package-lock.json generated

@ -61,6 +61,7 @@
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.15.0",
"@testing-library/cypress": "^8.0.1",
"@types/file-saver": "^2.0.3",
"@types/jest": "^27.0.1",
"@types/lodash": "^4.14.168",
"@types/node": "^16.9.1",
@ -3689,6 +3690,12 @@
"@babel/types": "^7.3.0"
}
},
"node_modules/@types/file-saver": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.3.tgz",
"integrity": "sha512-MBIou8pd/41jkff7s97B47bc9+p0BszqqDJsO51yDm49uUxeKzrfuNl5fSLC6BpLEWKA8zlwyqALVmXrFwoBHQ==",
"dev": true
},
"node_modules/@types/glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz",
@ -30122,6 +30129,12 @@
"@babel/types": "^7.3.0"
}
},
"@types/file-saver": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.3.tgz",
"integrity": "sha512-MBIou8pd/41jkff7s97B47bc9+p0BszqqDJsO51yDm49uUxeKzrfuNl5fSLC6BpLEWKA8zlwyqALVmXrFwoBHQ==",
"dev": true
},
"@types/glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz",

@ -1,154 +1,308 @@
{
"name": "bitburner",
"license": "SEE LICENSE IN license.txt",
"version": "0.53.0",
"main": "electron-main.js",
"author": {
"name": "Daniel Xie"
},
"bugs": {
"url": "https://github.com/danielyxie/bitburner/issues"
},
"dependencies": {
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@monaco-editor/react": "^4.2.2",
"@types/js-beautify": "^1.13.2",
"@types/numeral": "0.0.25",
"@types/react": "^16.8.6",
"@types/react-dom": "^16.8.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"ajv": "^5.1.5",
"ajv-keywords": "^2.0.0",
"arg": "^5.0.0",
"async": "^2.6.1",
"autosize": "^4.0.2",
"brace": "^0.11.1",
"codemirror": "^5.58.2",
"decimal.js": "7.2.3",
"enhanced-resolve": "^4.0.0",
"escodegen": "^1.11.0",
"escope": "^3.6.0",
"file-saver": "^1.3.8",
"interpret": "^1.0.0",
"jquery": "^3.5.0",
"jshint": "^2.10.2",
"json-loader": "^0.5.4",
"jsplumb": "^2.6.8",
"jszip": "^3.7.0",
"loader-runner": "^2.3.0",
"loader-utils": "^1.1.0",
"mathjax-full": "^3.2.0",
"mathjax-react": "^1.0.6",
"memory-fs": "~0.4.1",
"monaco-editor": "^0.27.0",
"node-sass": "^6.0.1",
"normalize.css": "^8.0.0",
"numeral": "2.0.6",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react-modal": "^3.12.1",
"sprintf-js": "^1.1.1",
"tapable": "^1.0.0",
"treant-js": "^1.0.1",
"unused-webpack-plugin": "^2.4.0",
"uuid": "^3.2.1",
"w3c-blob": "0.0.1"
},
"description": "A cyberpunk-themed incremental game",
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.15.0",
"@testing-library/cypress": "^8.0.1",
"@types/file-saver": "^2.0.3",
"@types/jest": "^27.0.1",
"@types/lodash": "^4.14.168",
"@types/node": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.0.5",
"beautify-lint": "^1.0.3",
"benchmark": "^2.1.1",
"bundle-loader": "~0.5.0",
"css-loader": "^0.28.11",
"cypress": "^8.3.1",
"es6-promise-polyfill": "^1.1.1",
"eslint": "^7.24.0",
"eslint-plugin-node": "^11.1.0",
"file-loader": "^1.1.11",
"fork-ts-checker-webpack-plugin": "^6.3.3",
"html-webpack-plugin": "^3.2.0",
"http-server": "^13.0.1",
"i18n-webpack-plugin": "^1.0.0",
"istanbul": "^0.4.5",
"jest": "^27.1.0",
"js-beautify": "^1.5.10",
"jsdom": "^15.0.0",
"jsdom-global": "^3.0.2",
"json5": "^1.0.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1",
"null-loader": "^1.0.0",
"prettier": "^2.3.2",
"raw-loader": "~0.5.0",
"regenerator-runtime": "^0.13.9",
"sass-loader": "^7.0.3",
"script-loader": "~0.7.0",
"should": "^11.1.1",
"simple-git": "^1.96.0",
"sinon": "^2.3.2",
"source-map": "^0.7.3",
"start-server-and-test": "^1.14.0",
"style-loader": "^0.21.0",
"stylelint": "^9.2.1",
"stylelint-declaration-use-variable": "^1.6.1",
"stylelint-order": "^0.8.1",
"typescript": "^4.2.4",
"uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.0.1",
"watchpack": "^1.6.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.11.2",
"worker-loader": "^2.0.0",
"electron": "^14.0.1",
"electron-packager": "^15.4.0"
"electron-packager": "^15.4.0",
"es6-promise-polyfill": "^1.1.1",
"eslint": "^7.24.0",
"eslint-plugin-node": "^11.1.0",
"file-loader": "^1.1.11",
"fork-ts-checker-webpack-plugin": "^6.3.3",
"html-webpack-plugin": "^3.2.0",
"http-server": "^13.0.1",
"i18n-webpack-plugin": "^1.0.0",
"istanbul": "^0.4.5",
"jest": "^27.1.0",
"js-beautify": "^1.5.10",
"jsdom": "^15.0.0",
"jsdom-global": "^3.0.2",
"json5": "^1.0.1",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1",
"null-loader": "^1.0.0",
"prettier": "^2.3.2",
"raw-loader": "~0.5.0",
"regenerator-runtime": "^0.13.9",
"sass-loader": "^7.0.3",
"script-loader": "~0.7.0",
"should": "^11.1.1",
"simple-git": "^1.96.0",
"sinon": "^2.3.2",
"source-map": "^0.7.3",
"start-server-and-test": "^1.14.0",
"style-loader": "^0.21.0",
"stylelint": "^9.2.1",
"stylelint-declaration-use-variable": "^1.6.1",
"stylelint-order": "^0.8.1",
"typescript": "^4.2.4",
"uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.0.1",
"watchpack": "^1.6.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.11.2",
"worker-loader": "^2.0.0"
},
"engines": {
"node": ">=8 || <=9"
},
"homepage": "https://github.com/danielyxie/bitburner",
"repository": {
"type": "git",
"url": "git+https://github.com/danielyxie/bitburner.git"
},
"scripts": {
"cy:test": "start-server-and-test start http://localhost:8000 cy:run",
"cy:dev": "start-server-and-test start:dev http://localhost:8000 cy:open",
"cy:open": "cypress open",
"cy:run": "cypress run",
"format": "prettier --write .",
"start": "http-server -p 8000",
"start:dev": "webpack-dev-server --progress --env.devServer --mode development",
"start:container": "webpack-dev-server --progress --env.devServer --mode development --env.runInContainer",
"build:dev": "webpack --mode development",
"lint": "npm run lint:jsts & npm run lint:style",
"lint:jsts": "eslint --fix . --ext js,jsx,ts,tsx",
"lint:style": "stylelint --fix ./css/*",
"preinstall": "node ./scripts/engines-check.js",
"test": "jest",
"test:watch": "jest --watch",
"watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development",
"package-electron": "electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png"
}
}

@ -179,7 +179,6 @@ export class CodingContract {
removePopup(popupId);
},
onAttempt: (val: string) => {
console.error("attempting");
if (this.isSolution(val)) {
resolve(CodingContractResult.Success);
} else {

@ -54,7 +54,7 @@ export function executeDarkwebTerminalCommand(commandArray: string[]): void {
}
}
function listAllDarkwebItems(): void {
export function listAllDarkwebItems(): void {
for (const key in DarkWebItems) {
const item = DarkWebItems[key];
postElement(
@ -65,7 +65,7 @@ function listAllDarkwebItems(): void {
}
}
function buyDarkwebItem(itemName: string): void {
export function buyDarkwebItem(itemName: string): void {
itemName = itemName.toLowerCase();
// find the program that matches, if any

@ -1 +1,2 @@
export declare function parseFconfSettings(config: string): void;
export declare function createFconf(): string;

@ -7,7 +7,7 @@ export interface IEngine {
_lastUpdate: number;
hideAllContent: () => void;
loadTerminalContent: () => void;
loadScriptEditorContent: () => void;
loadScriptEditorContent: (filename?: string, code?: string) => void;
loadActiveScriptsContent: () => void;
loadCreateProgramContent: () => void;
loadCharacterContent: () => void;

1
src/Message/MessageHelpers.d.ts vendored Normal file

@ -0,0 +1 @@
export declare function showMessage(msg: Message): void;

1
src/NetscriptWorker.d.ts vendored Normal file

@ -0,0 +1 @@
export declare function startWorkerScript(script: RunningScript, server: BaseServer): boolean;

@ -24,6 +24,7 @@ import { Exploit } from "../Exploits/Exploit";
import { ICorporation } from "../Corporation/ICorporation";
import { IGang } from "../Gang/IGang";
import { IBladeburner } from "../Bladeburner/IBladeburner";
import { ICodingContractReward } from "../CodingContracts";
export interface IPlayer {
// Class members
@ -207,4 +208,5 @@ export interface IPlayer {
queueAugmentation(augmentationName: string): void;
receiveInvite(factionName: string): void;
updateSkillLevels(): void;
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
}

@ -1,7 +1,6 @@
export interface IPlayer {
hacking_skill: number;
sourceFiles: any[];
}
import { BaseServer } from "../Server/BaseServer";
import { ITerminal } from "../Terminal/ITerminal";
import { IPlayer } from "../PersonObjects/IPlayer";
export interface IProgramCreate {
level: number;
@ -13,10 +12,16 @@ export interface IProgramCreate {
export class Program {
name = "";
create: IProgramCreate | null;
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
constructor(name: string, create: IProgramCreate | null) {
constructor(
name: string,
create: IProgramCreate | null,
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void,
) {
this.name = name;
this.create = create;
this.run = run;
}
htmlID(): string {

@ -5,5 +5,5 @@ import { IMap } from "../types";
export const Programs: IMap<Program> = {};
for (const params of programsMetadata) {
Programs[params.key] = new Program(params.name, params.create);
Programs[params.key] = new Program(params.name, params.create, params.run);
}

@ -1,5 +1,18 @@
import { IPlayer, IProgramCreate } from "../Program";
import { IProgramCreate } from "../Program";
import { CONSTANTS } from "../../Constants";
import { BaseServer } from "../../Server/BaseServer";
import { Server } from "../../Server/Server";
import { ITerminal } from "../../Terminal/ITerminal";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { HacknetServer } from "../../Hacknet/HacknetServer";
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
import { getServer } from "../../Server/ServerHelpers";
import { numeralWrapper } from "../../ui/numeralFormat";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { createPopup } from "../../ui/React/createPopup";
import { BitFlumePopup } from "../../BitNode/ui/BitFlumePopup";
import { calculateHackingTime, calculateGrowTime, calculateWeakenTime } from "../../Hacking";
function requireHackingLevel(lvl: number) {
return function (p: IPlayer) {
@ -17,6 +30,7 @@ export interface IProgramCreationParams {
key: string;
name: string;
create: IProgramCreate | null;
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
}
export const programsMetadata: IProgramCreationParams[] = [
@ -29,6 +43,25 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(1),
time: CONSTANTS.MillisecondsPerFiveMinutes,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot nuke this kind of server.");
return;
}
if (server.hasAdminRights) {
terminal.print("You already have root access to this computer. There is no reason to run NUKE.exe");
return;
}
if (server.openPortCount >= player.getCurrentServer().numOpenPortsRequired) {
server.hasAdminRights = true;
terminal.print("NUKE successful! Gained root access to " + player.getCurrentServer().hostname);
// TODO: Make this take time rather than be instant
return;
}
terminal.print("NUKE unsuccessful. Not enough ports have been opened");
},
},
{
key: "BruteSSHProgram",
@ -39,6 +72,20 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(50),
time: CONSTANTS.MillisecondsPerFiveMinutes * 2,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot run BruteSSH.exe on this kind of server.");
return;
}
if (server.sshPortOpen) {
terminal.print("SSH Port (22) is already open!");
return;
}
server.sshPortOpen = true;
terminal.print("Opened SSH Port(22)!");
server.openPortCount++;
},
},
{
key: "FTPCrackProgram",
@ -49,6 +96,20 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(100),
time: CONSTANTS.MillisecondsPerHalfHour,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot run FTPCrack.exe on this kind of server.");
return;
}
if (server.ftpPortOpen) {
terminal.print("FTP Port (21) is already open!");
return;
}
server.ftpPortOpen = true;
terminal.print("Opened FTP Port (21)!");
server.openPortCount++;
},
},
{
key: "RelaySMTPProgram",
@ -59,6 +120,20 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(250),
time: CONSTANTS.MillisecondsPer2Hours,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot run relaySMTP.exe on this kind of server.");
return;
}
if (server.smtpPortOpen) {
terminal.print("SMTP Port (25) is already open!");
return;
}
server.smtpPortOpen = true;
terminal.print("Opened SMTP Port (25)!");
server.openPortCount++;
},
},
{
key: "HTTPWormProgram",
@ -69,6 +144,20 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(500),
time: CONSTANTS.MillisecondsPer4Hours,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot run HTTPWorm.exe on this kind of server.");
return;
}
if (server.httpPortOpen) {
terminal.print("HTTP Port (80) is already open!");
return;
}
server.httpPortOpen = true;
terminal.print("Opened HTTP Port (80)!");
server.openPortCount++;
},
},
{
key: "SQLInjectProgram",
@ -79,6 +168,20 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(750),
time: CONSTANTS.MillisecondsPer8Hours,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
if (!(server instanceof Server)) {
terminal.error("Cannot run SQLInject.exe on this kind of server.");
return;
}
if (server.sqlPortOpen) {
terminal.print("SQL Port (1433) is already open!");
return;
}
server.sqlPortOpen = true;
terminal.print("Opened SQL Port (1433)!");
server.openPortCount++;
},
},
{
key: "DeepscanV1",
@ -89,6 +192,10 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(75),
time: CONSTANTS.MillisecondsPerQuarterHour,
},
run: (terminal: ITerminal): void => {
terminal.print("This executable cannot be run.");
terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5.");
},
},
{
key: "DeepscanV2",
@ -99,6 +206,10 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(400),
time: CONSTANTS.MillisecondsPer2Hours,
},
run: (terminal: ITerminal): void => {
terminal.print("This executable cannot be run.");
terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
},
},
{
key: "ServerProfiler",
@ -109,6 +220,46 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(75),
time: CONSTANTS.MillisecondsPerHalfHour,
},
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]): void => {
if (args.length !== 1) {
terminal.print("Must pass a server hostname or IP as an argument for ServerProfiler.exe");
return;
}
const targetServer = getServer(args[0]);
if (targetServer == null) {
terminal.print("Invalid server IP/hostname");
return;
}
if (targetServer instanceof HacknetServer) {
terminal.print(`ServerProfiler.exe cannot be run on a Hacknet Server.`);
return;
}
terminal.print(targetServer.hostname + ":");
terminal.print("Server base security level: " + targetServer.baseDifficulty);
terminal.print("Server current security level: " + targetServer.hackDifficulty);
terminal.print("Server growth rate: " + targetServer.serverGrowth);
terminal.print(
`Netscript hack() execution time: ${convertTimeMsToTimeElapsedString(
calculateHackingTime(targetServer, player) * 1000,
true,
)}`,
);
terminal.print(
`Netscript grow() execution time: ${convertTimeMsToTimeElapsedString(
calculateGrowTime(targetServer, player) * 1000,
true,
)}`,
);
terminal.print(
`Netscript weaken() execution time: ${convertTimeMsToTimeElapsedString(
calculateWeakenTime(targetServer, player) * 1000,
true,
)}`,
);
},
},
{
key: "AutoLink",
@ -119,6 +270,11 @@ export const programsMetadata: IProgramCreationParams[] = [
req: requireHackingLevel(25),
time: CONSTANTS.MillisecondsPerQuarterHour,
},
run: (terminal: ITerminal): void => {
terminal.print("This executable cannot be run.");
terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'.");
terminal.print("When using scan-analyze, click on a server's hostname to connect to it.");
},
},
{
key: "BitFlume",
@ -129,10 +285,31 @@ export const programsMetadata: IProgramCreationParams[] = [
req: bitFlumeRequirements(),
time: CONSTANTS.MillisecondsPerFiveMinutes / 20,
},
run: (terminal: ITerminal, player: IPlayer): void => {
const popupId = "bitflume-popup";
createPopup(popupId, BitFlumePopup, {
player: player,
popupId: popupId,
});
},
},
{
key: "Flight",
name: "fl1ght.exe",
create: null,
run: (terminal: ITerminal, player: IPlayer): void => {
const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement * 30);
const fulfilled =
player.augmentations.length >= numAugReq && player.money.gt(1e11) && player.hacking_skill >= 2500;
if (!fulfilled) {
terminal.print(`Augmentations: ${player.augmentations.length} / ${numAugReq}`);
terminal.print(`Money: ${numeralWrapper.formatMoney(player.money.toNumber())} / $100b`);
terminal.print(`Hacking skill: ${player.hacking_skill} / 2500`);
return;
}
terminal.print("We will contact you.");
terminal.print("-- Daedalus --");
},
},
];

6
src/Script/ScriptHelpers.d.ts vendored Normal file

@ -0,0 +1,6 @@
export declare function findRunningScript(
filename: string,
args: (string | number)[],
server: BaseServer,
): RunningScript | null;
export declare function findRunningScriptByPid(pid: number, server: BaseServer): RunningScript | null;

@ -1,5 +1,6 @@
import { AllServers, createUniqueRandomIp, ipExists } from "./AllServers";
import { Server, IConstructorParams } from "./Server";
import { BaseServer } from "./BaseServer";
import { calculateServerGrowth } from "./formulas/grow";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
@ -141,7 +142,7 @@ export function getServer(s: string): Server | HacknetServer | null {
// Returns the i-th server on the specified server's network
// A Server's serverOnNetwork property holds only the IPs. This function returns
// the actual Server object
export function getServerOnNetwork(server: Server, i: number): Server | HacknetServer | null {
export function getServerOnNetwork(server: BaseServer, i: number): Server | HacknetServer | null {
if (i > server.serversOnNetwork.length) {
console.error("Tried to get server on network that was out of range");
return null;

@ -1,20 +1,16 @@
import React, { useState, useEffect } from "react";
import clsx from "clsx";
import { createStyles, makeStyles, useTheme, Theme } from "@material-ui/core/styles";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import ListItem from "@material-ui/core/ListItem";
import ListSubheader from "@material-ui/core/ListSubheader";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Typography from "@material-ui/core/Typography";
import Collapse from "@material-ui/core/Collapse";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import MailIcon from "@material-ui/icons/Mail";
import { Theme as BBTheme, colors } from "../../ui/React/Theme";
@ -341,7 +337,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
const classes = useStyles();
const [open, setOpen] = useState(true);
const toggleDrawer = () => setOpen((old) => !old);
const toggleDrawer = (): void => setOpen((old) => !old);
return (
<BBTheme>
<Drawer

1
src/Terminal.d.ts vendored Normal file

@ -0,0 +1 @@
export declare const Terminal: any;

File diff suppressed because it is too large Load Diff

30
src/Terminal/ITerminal.ts Normal file

@ -0,0 +1,30 @@
import { TextFile } from "../TextFile";
import { Script } from "../Script/Script";
import { IPlayer } from "../PersonObjects/IPlayer";
import { IEngine } from "../IEngine";
export interface ITerminal {
print(s: string, config?: any): void;
error(s: string): void;
startAnalyze(): void;
startBackdoor(player: IPlayer): void;
startHack(player: IPlayer): void;
finishHack(player: IPlayer, cancelled?: boolean): void;
finishBackdoor(player: IPlayer, cancelled?: boolean): void;
finishAnalyze(player: IPlayer, cancelled?: boolean): void;
finishAction(player: IPlayer, cancelled?: boolean): void;
getFilepath(filename: string): string;
getFile(player: IPlayer, filename: string): Script | TextFile | string | null;
getScript(player: IPlayer, filename: string): Script | null;
getTextFile(player: IPlayer, filename: string): TextFile | null;
getLitFile(player: IPlayer, filename: string): string | null;
resetTerminalInput(): void;
cwd(): string;
setcwd(dir: string): void;
runContract(player: IPlayer, name: string): void;
executeScanAnalyzeCommand(player: IPlayer, depth?: number, all?: boolean): void;
connectToServer(player: IPlayer, server: string): void;
executeCommand(engine: IEngine, player: IPlayer, command: string): void;
executeCommands(engine: IEngine, player: IPlayer, commands: string): void;
}

127
src/Terminal/Parser.ts Normal file

@ -0,0 +1,127 @@
import { substituteAliases } from "../Alias";
// Helper function that checks if an argument (which is a string) is a valid number
function isNumber(str: string): boolean {
if (typeof str != "string") {
return false;
} // Only process strings
return !isNaN(parseFloat(str));
}
export function ParseCommands(commands: string): string[] {
// Sanitize input
commands = commands.trim();
// Replace all extra whitespace in command with a single space
commands = commands.replace(/\s\s+/g, " ");
const match = commands.match(/(?:'[^']*'|"[^"]*"|[^;"])*/g);
if (!match) return [];
// Split commands and execute sequentially
const allCommands = match
.map(substituteAliases)
.map((c) => c.match(/(?:'[^']*'|"[^"]*"|[^;"])*/g))
.flat();
const out: string[] = [];
for (const c of allCommands) {
if (c === null) continue;
if (c.match(/^\s*$/)) {
continue;
} // Don't run commands that only have whitespace
out.push(c.trim());
}
return out;
}
export function ParseCommand(command: string): (string | number)[] {
// This will be used to keep track of whether we're in a quote. This is for situations
// like the alias command:
// alias run="run NUKE.exe"
// We want the run="run NUKE.exe" to be parsed as a single command, so this flag
// will keep track of whether we have a quote in
let inQuote = ``;
// Returns an array with the command and its arguments in each index
// Properly handles quotation marks (e.g. `run foo.script "the sun"` will return [run, foo.script, the sun])
const args = [];
let start = 0,
i = 0;
let prevChar = ""; // Previous character
while (i < command.length) {
let escaped = false; // Check for escaped quotation marks
if (i >= 1) {
prevChar = command.charAt(i - 1);
if (prevChar === "\\") {
escaped = true;
}
}
const c = command.charAt(i);
if (c === '"') {
// Double quotes
if (!escaped && prevChar === " ") {
const endQuote = command.indexOf('"', i + 1);
if (endQuote !== -1 && (endQuote === command.length - 1 || command.charAt(endQuote + 1) === " ")) {
args.push(command.substr(i + 1, endQuote - i - 1));
if (endQuote === command.length - 1) {
start = i = endQuote + 1;
} else {
start = i = endQuote + 2; // Skip the space
}
continue;
}
} else {
if (inQuote === ``) {
inQuote = `"`;
} else if (inQuote === `"`) {
inQuote = ``;
}
}
} else if (c === "'") {
// Single quotes, same thing as above
if (!escaped && prevChar === " ") {
const endQuote = command.indexOf("'", i + 1);
if (endQuote !== -1 && (endQuote === command.length - 1 || command.charAt(endQuote + 1) === " ")) {
args.push(command.substr(i + 1, endQuote - i - 1));
if (endQuote === command.length - 1) {
start = i = endQuote + 1;
} else {
start = i = endQuote + 2; // Skip the space
}
continue;
}
} else {
if (inQuote === ``) {
inQuote = `'`;
} else if (inQuote === `'`) {
inQuote = ``;
}
}
} else if (c === " " && inQuote === ``) {
const arg = command.substr(start, i - start);
// If this is a number, convert it from a string to number
if (isNumber(arg)) {
args.push(parseFloat(arg));
} else {
args.push(arg);
}
start = i + 1;
}
++i;
}
// Add the last argument
if (start !== i) {
const arg = command.substr(start, i - start);
// If this is a number, convert it from string to number
if (isNumber(arg)) {
args.push(parseFloat(arg));
} else {
args.push(arg);
}
}
return args;
}

692
src/Terminal/Terminal.ts Normal file

@ -0,0 +1,692 @@
import { postContent, hackProgressBarPost, hackProgressPost } from "../ui/postToTerminal";
import { ITerminal } from "./ITerminal";
import { IEngine } from "../IEngine";
import { IPlayer } from "../PersonObjects/IPlayer";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { BaseServer } from "../Server/BaseServer";
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";
import { CONSTANTS } from "../Constants";
import { AllServers } from "../Server/AllServers";
import { removeLeadingSlash, isInRootDirectory, evaluateFilePath } from "./DirectoryHelpers";
import { checkIfConnectedToDarkweb } from "../DarkWeb/DarkWeb";
import { logBoxCreate } from "../../utils/LogBox";
import { iTutorialNextStep, iTutorialSteps, ITutorial } from "../InteractiveTutorial";
import { findRunningScript } from "../Script/ScriptHelpers";
import { TerminalHelpText } from "./HelpText";
import { GetServerByHostname, getServer, getServerOnNetwork } from "../Server/ServerHelpers";
import { ParseCommand, ParseCommands } from "./Parser";
import { SpecialServerIps, SpecialServerNames } from "../Server/SpecialServerIps";
import {
calculateHackingChance,
calculateHackingExpGain,
calculatePercentMoneyHacked,
calculateHackingTime,
} from "../Hacking";
import { numeralWrapper } from "../ui/numeralFormat";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { alias } from "./commands/alias";
import { analyze } from "./commands/analyze";
import { backdoor } from "./commands/backdoor";
import { buy } from "./commands/buy";
import { cat } from "./commands/cat";
import { cd } from "./commands/cd";
import { check } from "./commands/check";
import { connect } from "./commands/connect";
import { download } from "./commands/download";
import { expr } from "./commands/expr";
import { free } from "./commands/free";
import { hack } from "./commands/hack";
import { help } from "./commands/help";
import { home } from "./commands/home";
import { hostname } from "./commands/hostname";
import { ifconfig } from "./commands/ifconfig";
import { kill } from "./commands/kill";
import { killall } from "./commands/killall";
import { ls } from "./commands/ls";
import { lscpu } from "./commands/lscpu";
import { mem } from "./commands/mem";
import { mv } from "./commands/mv";
import { nano } from "./commands/nano";
import { ps } from "./commands/ps";
import { rm } from "./commands/rm";
import { run } from "./commands/run";
import { scan } from "./commands/scan";
import { scananalyze } from "./commands/scananalyze";
import { scp } from "./commands/scp";
import { sudov } from "./commands/sudov";
import { tail } from "./commands/tail";
import { theme } from "./commands/theme";
import { top } from "./commands/top";
import { unalias } from "./commands/unalias";
import { wget } from "./commands/wget";
import { clear } from "./commands/clear";
export class Terminal implements ITerminal {
print(s: string, config?: any): void {
postContent(s, config);
}
error(s: string): void {
postContent(`ERROR: ${s}`, { color: "#ff2929" });
}
startHack(player: IPlayer): void {
OldTerminal.hackFlag = true;
// Hacking through Terminal should be faster than hacking through a script
OldTerminal.actionTime = calculateHackingTime(player.getCurrentServer(), player) / 4;
this.startAction();
}
startBackdoor(player: IPlayer): void {
OldTerminal.backdoorFlag = true;
// Backdoor should take the same amount of time as hack
OldTerminal.actionTime = calculateHackingTime(player.getCurrentServer(), player) / 4;
this.startAction();
}
startAnalyze(): void {
OldTerminal.analyzeFlag = true;
OldTerminal.actionTime = 1;
this.print("Analyzing system...");
this.startAction();
}
startAction(): void {
OldTerminal.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);
}
// Complete the hack/analyze command
finishHack(player: IPlayer, cancelled = false): void {
if (!cancelled) {
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);
OldTerminal.hackFlag = false;
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`,
);
}
}
OldTerminal.hackFlag = false;
}
finishBackdoor(player: IPlayer, cancelled = false): void {
if (!cancelled) {
const server = player.getCurrentServer();
if (
SpecialServerIps[SpecialServerNames.WorldDaemon] &&
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
) {
if (player.bitNodeN == null) {
player.bitNodeN = 1;
}
hackWorldDaemon(player.bitNodeN);
OldTerminal.backdoorFlag = false;
return;
}
server.backdoorInstalled = true;
this.print("Backdoor successful!");
}
OldTerminal.backdoorFlag = false;
}
finishAnalyze(player: IPlayer, cancelled = false): void {
if (!cancelled) {
const currServ = player.getCurrentServer();
const isHacknet = currServ instanceof HacknetServer;
this.print(currServ.hostname + ": ");
const org = currServ.organizationName;
this.print("Organization name: " + (!isHacknet ? org : "player"));
const hasAdminRights = (!isHacknet && currServ.hasAdminRights) || isHacknet;
this.print("Root Access: " + (hasAdminRights ? "YES" : "NO"));
const hackingSkill = currServ.requiredHackingSkill;
this.print("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
const security = currServ.hackDifficulty;
this.print("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
const hackingChance = calculateHackingChance(currServ, player);
this.print("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
const hackingTime = calculateHackingTime(currServ, player) * 1000;
this.print("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
this.print(
`Total money available on server: ${!isHacknet ? numeralWrapper.formatMoney(currServ.moneyAvailable) : "N/A"}`,
);
const numPort = currServ.numOpenPortsRequired;
this.print("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
this.print("SSH port: " + (currServ.sshPortOpen ? "Open" : "Closed"));
this.print("FTP port: " + (currServ.ftpPortOpen ? "Open" : "Closed"));
this.print("SMTP port: " + (currServ.smtpPortOpen ? "Open" : "Closed"));
this.print("HTTP port: " + (currServ.httpPortOpen ? "Open" : "Closed"));
this.print("SQL port: " + (currServ.sqlPortOpen ? "Open" : "Closed"));
}
OldTerminal.analyzeFlag = false;
}
finishAction(player: IPlayer, cancelled = false): void {
if (OldTerminal.hackFlag) {
this.finishHack(player, cancelled);
} else if (OldTerminal.backdoorFlag) {
this.finishBackdoor(player, cancelled);
} else if (OldTerminal.analyzeFlag) {
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");
OldTerminal.resetTerminalInput();
$("input[class=terminal-input]").prop("disabled", false);
}
getFile(player: IPlayer, filename: string): Script | TextFile | string | null {
if (isScriptFilename(filename)) {
return this.getScript(player, filename);
}
if (filename.endsWith(".lit")) {
return this.getLitFile(player, filename);
}
if (filename.endsWith(".txt")) {
return this.getTextFile(player, filename);
}
return null;
}
getFilepath(filename: string): string {
const path = evaluateFilePath(filename, this.cwd());
if (path == null) {
throw new Error(`Invalid file path specified: ${filename}`);
}
if (isInRootDirectory(path)) {
return removeLeadingSlash(path);
}
return path;
}
getScript(player: IPlayer, filename: string): Script | null {
const s = player.getCurrentServer();
const filepath = this.getFilepath(filename);
for (const script of s.scripts) {
if (filepath === script.filename) {
return script;
}
}
return null;
}
getTextFile(player: IPlayer, filename: string): TextFile | null {
const s = player.getCurrentServer();
const filepath = this.getFilepath(filename);
for (const txt of s.textFiles) {
if (filepath === txt.fn) {
return txt;
}
}
return null;
}
getLitFile(player: IPlayer, filename: string): string | null {
const s = player.getCurrentServer();
const filepath = this.getFilepath(filename);
for (const lit of s.messages) {
if (typeof lit === "string" && filepath === lit) {
return lit;
}
}
return null;
}
resetTerminalInput(): void {
OldTerminal.resetTerminalInput();
}
cwd(): string {
return OldTerminal.currDir;
}
setcwd(dir: string): void {
OldTerminal.currDir = dir;
}
async runContract(player: IPlayer, contractName: string): Promise<void> {
// There's already an opened contract
if (OldTerminal.contractOpen) {
return this.error("There's already a Coding Contract in Progress");
}
const serv = player.getCurrentServer();
const contract = serv.getContract(contractName);
if (contract == null) {
return this.error("No such contract");
}
OldTerminal.contractOpen = true;
const res = await contract.prompt();
switch (res) {
case CodingContractResult.Success:
if (contract.reward !== null) {
const reward = player.gainCodingContractReward(contract.reward, contract.getDifficulty());
this.print(`Contract SUCCESS - ${reward}`);
}
serv.removeContract(contract);
break;
case CodingContractResult.Failure:
++contract.tries;
if (contract.tries >= contract.getMaxNumTries()) {
this.print("Contract <p style='color:red;display:inline'>FAILED</p> - Contract is now self-destructing");
serv.removeContract(contract);
} else {
this.print(
`Contract <p style='color:red;display:inline'>FAILED</p> - ${
contract.getMaxNumTries() - contract.tries
} tries remaining`,
);
}
break;
case CodingContractResult.Cancelled:
default:
this.print("Contract cancelled");
break;
}
OldTerminal.contractOpen = false;
}
executeScanAnalyzeCommand(player: IPlayer, depth = 1, all = false): void {
// TODO Using array as stack for now, can make more efficient
this.print("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~");
this.print(" ");
// Map of all servers to keep track of which have been visited
const visited: {
[key: string]: number | undefined;
} = {};
for (const ip in AllServers) {
visited[ip] = 0;
}
const stack: BaseServer[] = [];
const depthQueue: number[] = [0];
const currServ = player.getCurrentServer();
stack.push(currServ);
while (stack.length != 0) {
const s = stack.pop();
if (!s) continue;
const d = depthQueue.pop();
if (d === undefined) continue;
const isHacknet = s instanceof HacknetServer;
if (!all && (s as any).purchasedByPlayer && s.hostname != "home") {
continue; // Purchased server
} else if (visited[s.ip] || d > depth) {
continue; // Already visited or out-of-depth
} else if (!all && isHacknet) {
continue; // Hacknet Server
} else {
visited[s.ip] = 1;
}
for (let i = s.serversOnNetwork.length - 1; i >= 0; --i) {
const newS = getServerOnNetwork(s, i);
if (newS === null) continue;
stack.push(newS);
depthQueue.push(d + 1);
}
if (d == 0) {
continue;
} // Don't print current server
const titleDashes = Array((d - 1) * 4 + 1).join("-");
if (player.hasProgram(Programs.AutoLink.name)) {
this.print("<strong>" + titleDashes + "> <a class='scan-analyze-link'>" + s.hostname + "</a></strong>", false);
} else {
this.print("<strong>" + titleDashes + ">" + s.hostname + "</strong>");
}
const dashes = titleDashes + "--";
let c = "NO";
if (s.hasAdminRights) {
c = "YES";
}
this.print(
`${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + (s as any).requiredHackingSkill : ""}`,
);
if (s.hasOwnProperty("numOpenPortsRequired")) {
this.print(dashes + "Number of open ports required to NUKE: " + (s as any).numOpenPortsRequired);
}
this.print(dashes + "RAM: " + numeralWrapper.formatRAM(s.maxRam));
this.print(" ");
}
const links = document.getElementsByClassName("scan-analyze-link");
for (let i = 0; i < links.length; ++i) {
(() => {
const hostname = links[i].innerHTML.toString();
links[i].addEventListener("onclick", () => {
if (OldTerminal.analyzeFlag || OldTerminal.hackFlag || OldTerminal.backdoorFlag) {
return;
}
this.connectToServer(player, hostname);
});
})(); // Immediate invocation
}
}
connectToServer(player: IPlayer, server: string): void {
const serv = getServer(server);
if (serv == null) {
this.error("Invalid server. Connection failed.");
return;
}
player.getCurrentServer().isConnectedTo = false;
player.currentServer = serv.ip;
player.getCurrentServer().isConnectedTo = true;
this.print("Connected to " + serv.hostname);
this.setcwd("/");
if (player.getCurrentServer().hostname == "darkweb") {
checkIfConnectedToDarkweb(); // Posts a 'help' message if connecting to dark web
}
this.resetTerminalInput();
}
executeCommands(engine: IEngine, player: IPlayer, commands: string): void {
// Sanitize input
commands = commands.trim();
commands = commands.replace(/\s\s+/g, " "); // Replace all extra whitespace in command with a single space
// Handle Terminal History - multiple commands should be saved as one
if (OldTerminal.commandHistory[OldTerminal.commandHistory.length - 1] != commands) {
OldTerminal.commandHistory.push(commands);
if (OldTerminal.commandHistory.length > 50) {
OldTerminal.commandHistory.splice(0, 1);
}
}
OldTerminal.commandHistoryIndex = OldTerminal.commandHistory.length;
const allCommands = ParseCommands(commands);
for (let i = 0; i < allCommands.length; i++) {
this.executeCommand(engine, player, allCommands[i]);
}
}
executeCommand(engine: IEngine, player: IPlayer, command: string): void {
if (OldTerminal.hackFlag || OldTerminal.backdoorFlag || OldTerminal.analyzeFlag) {
this.error(`Cannot execute command (${command}) while an action is in progress`);
return;
}
// Allow usage of ./
if (command.startsWith("./")) {
command = "run " + command.slice(2);
}
// Only split the first space
const commandArray = ParseCommand(command);
if (commandArray.length == 0) {
return;
}
const s = player.getCurrentServer();
/****************** Interactive Tutorial Terminal Commands ******************/
if (ITutorial.isRunning) {
const n00dlesServ = GetServerByHostname("n00dles");
if (n00dlesServ == null) {
throw new Error("Could not get n00dles server");
return;
}
switch (ITutorial.currStep) {
case iTutorialSteps.TerminalHelp:
if (commandArray.length === 1 && commandArray[0] == "help") {
this.print(TerminalHelpText);
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalLs:
if (commandArray.length === 1 && commandArray[0] == "ls") {
ls(this, engine, player, s, commandArray.slice(1));
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalScan:
if (commandArray.length === 1 && commandArray[0] == "scan") {
scan(this, engine, player, s, commandArray.slice(1));
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalScanAnalyze1:
if (commandArray.length == 1 && commandArray[0] == "scan-analyze") {
this.executeScanAnalyzeCommand(player, 1);
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalScanAnalyze2:
if (commandArray.length == 2 && commandArray[0] == "scan-analyze" && commandArray[1] === 2) {
this.executeScanAnalyzeCommand(player, 2);
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalConnect:
if (commandArray.length == 2) {
if (commandArray[0] == "connect" && (commandArray[1] == "n00dles" || commandArray[1] == n00dlesServ.ip)) {
player.getCurrentServer().isConnectedTo = false;
player.currentServer = n00dlesServ.ip;
player.getCurrentServer().isConnectedTo = true;
this.print("Connected to n00dles");
iTutorialNextStep();
} else {
this.print("Wrong command! Try again!");
return;
}
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalAnalyze:
if (commandArray.length === 1 && commandArray[0] === "analyze") {
if (commandArray.length !== 1) {
this.print("Incorrect usage of analyze command. Usage: analyze");
return;
}
this.startAnalyze();
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalNuke:
if (commandArray.length == 2 && commandArray[0] == "run" && commandArray[1] == "NUKE.exe") {
n00dlesServ.hasAdminRights = true;
this.print("NUKE successful! Gained root access to n00dles");
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalManualHack:
if (commandArray.length == 1 && commandArray[0] == "hack") {
this.startHack(player);
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalCreateScript:
if (commandArray.length == 2 && commandArray[0] == "nano" && commandArray[1] == "n00dles.script") {
engine.loadScriptEditorContent("n00dles.script", "");
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalFree:
if (commandArray.length == 1 && commandArray[0] == "free") {
free(this, engine, player, s, commandArray.slice(1));
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.TerminalRunScript:
if (commandArray.length == 2 && commandArray[0] == "run" && commandArray[1] == "n00dles.script") {
run(this, engine, player, s, commandArray.slice(1));
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
case iTutorialSteps.ActiveScriptsToTerminal:
if (commandArray.length == 2 && commandArray[0] == "tail" && commandArray[1] == "n00dles.script") {
// Check that the script exists on this machine
const runningScript = findRunningScript("n00dles.script", [], player.getCurrentServer());
if (runningScript == null) {
this.print("Error: No such script exists");
return;
}
logBoxCreate(runningScript);
iTutorialNextStep();
} else {
this.print("Bad command. Please follow the tutorial");
}
break;
default:
this.print("Please follow the tutorial, or click 'Exit Tutorial' if you'd like to skip it");
return;
}
return;
}
/****************** END INTERACTIVE TUTORIAL ******************/
/* Command parser */
const commandName = commandArray[0];
if (typeof commandName === "number") {
this.error(`Command ${commandArray[0]} not found`);
return;
}
const commands: {
[key: string]: (
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
) => void;
} = {
alias: alias,
analyze: analyze,
backdoor: backdoor,
buy: buy,
cat: cat,
cd: cd,
check: check,
cls: clear,
clear: clear,
connect: connect,
download: download,
expr: expr,
free: free,
hack: hack,
help: help,
home: home,
hostname: hostname,
ifconfig: ifconfig,
kill: kill,
killall: killall,
ls: ls,
lscpu: lscpu,
mem: mem,
mv: mv,
nano: nano,
ps: ps,
rm: rm,
run: run,
scan: scan,
"scan-analyze": scananalyze,
scp: scp,
sudov: sudov,
tail: tail,
theme: theme,
top: top,
unalias: unalias,
wget: wget,
};
const f = commands[commandName.toLowerCase()];
if (!f) {
this.error(`Command ${commandArray[0]} not found`);
return;
}
f(this, engine, player, s, commandArray.slice(1));
}
}

@ -0,0 +1,33 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { parseAliasDeclaration, printAliases } from "../../Alias";
export function alias(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length === 0) {
printAliases();
return;
}
if (args.length === 1) {
if (parseAliasDeclaration(args[0] + "")) {
terminal.print(`Set alias ${args[0]}`);
return;
}
}
if (args.length === 2) {
if (args[0] === "-g") {
if (parseAliasDeclaration(args[1] + "", true)) {
terminal.print(`Set global alias ${args[1]}`);
return;
}
}
}
terminal.error('Incorrect usage of alias command. Usage: alias [-g] [aliasname="value"]');
}

@ -0,0 +1,18 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function analyze(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.print("Incorrect usage of analyze command. Usage: analyze");
return;
}
terminal.startAnalyze();
}

@ -0,0 +1,41 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Server } from "../../Server/Server";
import { HacknetServer } from "../../Hacknet/HacknetServer";
export function backdoor(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.print("Incorrect usage of backdoor command. Usage: backdoor");
return;
}
if (!(server instanceof Server)) {
terminal.error("Can only backdoor normal servers");
}
const normalServer = server as Server;
if (normalServer.purchasedByPlayer) {
terminal.error(
"Cannot use backdoor on your own machines! You are currently connected to your home PC or one of your purchased servers",
);
} else if (!normalServer.hasAdminRights) {
terminal.error("You do not have admin rights for this machine! Cannot backdoor");
} else if (normalServer.requiredHackingSkill > player.hacking_skill) {
terminal.error(
"Your hacking skill is not high enough to use backdoor on this machine. Try analyzing the machine to determine the required hacking skill",
);
} else if (normalServer instanceof HacknetServer) {
terminal.error("Cannot use backdoor on this type of Server");
} else {
terminal.startBackdoor(player);
}
}

@ -0,0 +1,33 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { listAllDarkwebItems, buyDarkwebItem } from "../../DarkWeb/DarkWeb";
import { SpecialServerIps } from "../../Server/SpecialServerIps";
export function buy(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (!SpecialServerIps.hasOwnProperty("Darkweb Server")) {
terminal.error(
"You need to be able to connect to the Dark Web to use the buy command. (Maybe there's a TOR router you can buy somewhere)",
);
return;
}
if (args.length != 1) {
terminal.print("Incorrect number of arguments. Usage: ");
terminal.print("buy -l");
terminal.print("buy [item name]");
return;
}
const arg = args[0] + "";
if (arg == "-l" || arg == "-1" || arg == "--list") {
listAllDarkwebItems();
} else {
buyDarkwebItem(arg);
}
}

@ -0,0 +1,53 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { showMessage } from "../../Message/MessageHelpers";
import { Message } from "../../Message/Message";
import { showLiterature } from "../../Literature/LiteratureHelpers";
export function cat(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 1) {
terminal.error("Incorrect usage of cat command. Usage: cat [file]");
return;
}
const filename = terminal.getFilepath(args[0] + "");
if (!filename.endsWith(".msg") && !filename.endsWith(".lit") && !filename.endsWith(".txt")) {
terminal.error(
"Only .msg, .txt, and .lit files are viewable with cat (filename must end with .msg, .txt, or .lit)",
);
return;
}
if (filename.endsWith(".msg") || filename.endsWith(".lit")) {
for (let i = 0; i < server.messages.length; ++i) {
if (filename.endsWith(".lit") && server.messages[i] === filename) {
const file = server.messages[i];
if (file instanceof Message) throw new Error(".lit file should not be a .msg");
showLiterature(file);
return;
} else if (filename.endsWith(".msg")) {
const file = server.messages[i];
if (typeof file === "string") throw new Error(".msg file should not be a .lit");
if (file.filename === filename) {
showMessage(file);
return;
}
}
}
} else if (filename.endsWith(".txt")) {
const txt = terminal.getTextFile(player, filename);
if (txt != null) {
txt.show();
return;
}
}
terminal.error(`No such file ${filename}`);
}

@ -0,0 +1,48 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { evaluateDirectoryPath, removeTrailingSlash } from "../DirectoryHelpers";
export function cd(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length > 1) {
terminal.error("Incorrect number of arguments. Usage: cd [dir]");
} else {
let dir = args.length === 1 ? args[0] + "" : "/";
let evaledDir: string | null = "";
if (dir === "/") {
evaledDir = "/";
} else {
// Ignore trailing slashes
dir = removeTrailingSlash(dir);
evaledDir = evaluateDirectoryPath(dir, terminal.cwd());
if (evaledDir === null || evaledDir === "") {
terminal.error("Invalid path. Failed to change directories");
return;
}
const server = player.getCurrentServer();
if (
!server.scripts.some((script) => script.filename.startsWith(evaledDir + "")) &&
!server.textFiles.some((file) => file.fn.startsWith(evaledDir + ""))
) {
terminal.error("Invalid path. Failed to change directories");
return;
}
}
terminal.setcwd(evaledDir);
// Reset input to update current directory on UI
terminal.resetTerminalInput();
}
}

@ -0,0 +1,33 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { findRunningScript } from "../../Script/ScriptHelpers";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
export function check(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length < 1) {
terminal.error("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]...");
} else {
const scriptName = terminal.getFilepath(args[0] + "");
// Can only tail script files
if (!isScriptFilename(scriptName)) {
terminal.error("tail can only be called on .script files (filename must end with .script)");
return;
}
// Check that the script exists on this machine
const runningScript = findRunningScript(scriptName, args.slice(1), server);
if (runningScript == null) {
terminal.error("No such script exists");
return;
}
runningScript.displayLog();
}
}

@ -0,0 +1,18 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function clear(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of clear/cls command. Usage: clear/cls");
return;
}
$("#terminal tr:not(:last)").remove();
}

@ -0,0 +1,32 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { getServerOnNetwork } from "../../Server/ServerHelpers";
export function connect(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
// Disconnect from current server in terminal and connect to new one
if (args.length !== 1) {
terminal.error("Incorrect usage of connect command. Usage: connect [ip/hostname]");
return;
}
const ip = args[0] + "";
for (let i = 0; i < server.serversOnNetwork.length; i++) {
const other = getServerOnNetwork(server, i);
if (other === null) throw new Error(`Server on network should not be null`);
if (other.ip == ip || other.hostname == ip) {
terminal.connectToServer(player, ip);
return;
}
}
terminal.error("Host not found");
}

@ -0,0 +1,79 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import FileSaver from "file-saver";
import JSZip from "jszip";
export function download(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
try {
if (args.length !== 1) {
terminal.error("Incorrect usage of download command. Usage: download [script/text file]");
return;
}
const fn = args[0] + "";
if (fn === "*" || fn === "*.script" || fn === "*.txt") {
// Download all scripts as a zip
const zip = new JSZip();
if (fn === "*" || fn === "*.script") {
for (let i = 0; i < server.scripts.length; ++i) {
const file = new Blob([server.scripts[i].code], {
type: "text/plain",
});
zip.file(server.scripts[i].filename + ".js", file);
}
}
if (fn === "*" || fn === "*.txt") {
for (let i = 0; i < server.textFiles.length; ++i) {
const file = new Blob([server.textFiles[i].text], {
type: "text/plain",
});
zip.file(server.textFiles[i].fn, file);
}
}
let zipFn = "";
switch (fn) {
case "*.script":
zipFn = "bitburnerScripts.zip";
break;
case "*.txt":
zipFn = "bitburnerTexts.zip";
break;
default:
zipFn = "bitburnerFiles.zip";
break;
}
zip.generateAsync({ type: "blob" }).then((content: any) => FileSaver.saveAs(content, zipFn));
return;
} else if (isScriptFilename(fn)) {
// Download a single script
const script = terminal.getScript(player, fn);
if (script != null) {
return script.download();
}
} else if (fn.endsWith(".txt")) {
// Download a single text file
const txt = terminal.getTextFile(player, fn);
if (txt != null) {
return txt.download();
}
} else {
terminal.error(`Cannot download this filetype`);
return;
}
terminal.error(`${fn} does not exist`);
return;
} catch (e) {
terminal.error(e + "");
return;
}
}

@ -0,0 +1,29 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function expr(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length === 0) {
terminal.error("Incorrect usage of expr command. Usage: expr [math expression]");
return;
}
const expr = args.join("");
// Sanitize the math expression
const sanitizedExpr = expr.replace(/s+/g, "").replace(/[^-()\d/*+.]/g, "");
let result;
try {
result = eval(sanitizedExpr);
} catch (e) {
terminal.error(`Could not evaluate expression: ${sanitizedExpr}`);
return;
}
terminal.print(result);
}

@ -0,0 +1,29 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { numeralWrapper } from "../../ui/numeralFormat";
export function free(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of free command. Usage: free");
return;
}
const ram = numeralWrapper.formatRAM(player.getCurrentServer().maxRam);
const used = numeralWrapper.formatRAM(player.getCurrentServer().ramUsed);
const avail = numeralWrapper.formatRAM(player.getCurrentServer().maxRam - player.getCurrentServer().ramUsed);
const maxLength = Math.max(ram.length, Math.max(used.length, avail.length));
const usedPercent = numeralWrapper.formatPercentage(
player.getCurrentServer().ramUsed / player.getCurrentServer().maxRam,
);
terminal.print(`Total: ${" ".repeat(maxLength - ram.length)}${ram}`);
terminal.print(`Used: ${" ".repeat(maxLength - used.length)}${used} (${usedPercent})`);
terminal.print(`Available: ${" ".repeat(maxLength - avail.length)}${avail}`);
}

@ -0,0 +1,44 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Server } from "../../Server/Server";
export function hack(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of hack command. Usage: hack");
return;
}
if (!(server instanceof Server)) {
terminal.error(
"Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers",
);
}
const normalServer = server as Server;
// Hack the current PC (usually for money)
// You can't hack your home pc or servers you purchased
if (normalServer.purchasedByPlayer) {
terminal.error(
"Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers",
);
return;
}
if (!normalServer.hasAdminRights) {
terminal.error("You do not have admin rights for this machine! Cannot hack");
return;
}
if (normalServer.requiredHackingSkill > player.hacking_skill) {
terminal.error(
"Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill",
);
return;
}
terminal.startHack(player);
}

@ -0,0 +1,29 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { TerminalHelpText, HelpTexts } from "../HelpText";
export function help(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0 && args.length !== 1) {
terminal.error("Incorrect usage of help command. Usage: help");
return;
}
if (args.length === 0) {
terminal.print(TerminalHelpText);
} else {
const cmd = args[0];
const txt = HelpTexts[cmd];
if (txt == null) {
terminal.error("No help topics match '" + cmd + "'");
return;
}
terminal.print(txt);
}
}

@ -0,0 +1,23 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function home(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of home command. Usage: home");
return;
}
player.getCurrentServer().isConnectedTo = false;
player.currentServer = player.getHomeComputer().ip;
player.getCurrentServer().isConnectedTo = true;
terminal.print("Connected to home");
terminal.setcwd("/");
terminal.resetTerminalInput();
}

@ -0,0 +1,18 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function hostname(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of hostname command. Usage: hostname");
return;
}
terminal.print(player.getCurrentServer().hostname);
}

@ -0,0 +1,18 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function ifconfig(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of ifconfig command. Usage: ifconfig");
return;
}
terminal.print(player.getCurrentServer().ip);
}

@ -0,0 +1,44 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { killWorkerScript } from "../../Netscript/killWorkerScript";
export function kill(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
try {
if (args.length < 1) {
terminal.error("Incorrect usage of kill command. Usage: kill [scriptname] [arg1] [arg2]...");
return;
}
// Kill by PID
if (typeof args[0] === "number") {
const pid = args[0];
const res = killWorkerScript(pid);
if (res) {
terminal.print(`Killing script with PID ${pid}`);
} else {
terminal.print(`Failed to kill script with PID ${pid}. No such script exists`);
}
return;
}
const scriptName = terminal.getFilepath(args[0]);
const runningScript = server.getRunningScript(scriptName, args.slice(1));
if (runningScript == null) {
terminal.error("No such script is running. Nothing to kill");
return;
}
killWorkerScript(runningScript, server.ip, false);
terminal.print(`Killing ${scriptName}`);
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,14 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { killWorkerScript } from "../../Netscript/killWorkerScript";
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
export function killall(terminal: ITerminal, engine: IEngine, player: IPlayer, server: BaseServer): void {
for (let i = server.runningScripts.length - 1; i >= 0; --i) {
killWorkerScript(server.runningScripts[i], server.ip, false);
}
WorkerScriptStartStopEventEmitter.emitEvent();
terminal.print("Killing all running scripts");
}

@ -0,0 +1,149 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Message } from "../../Message/Message";
import { getFirstParentDirectory, isValidDirectoryPath, evaluateDirectoryPath } from "../../Terminal/DirectoryHelpers";
export function ls(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
const numArgs = args.length;
function incorrectUsage(): void {
terminal.error("Incorrect usage of ls command. Usage: ls [dir] [| grep pattern]");
}
if (numArgs > 5 || numArgs === 3) {
return incorrectUsage();
}
// Grep
let filter = ""; // Grep
// Directory path
let prefix = terminal.cwd();
if (!prefix.endsWith("/")) {
prefix += "/";
}
// If there are 4+ arguments, then the last 3 must be for grep
if (numArgs >= 4) {
if (args[numArgs - 1] !== "grep" || args[numArgs - 2] !== "|") {
return incorrectUsage();
}
filter = args[numArgs] + "";
}
// If the second argument is not a pipe, then it must be for listing a directory
if (numArgs >= 2 && args[0] !== "|") {
const newPath = evaluateDirectoryPath(args[0] + "", terminal.cwd());
prefix = newPath ? newPath : "";
if (prefix != null) {
if (!prefix.endsWith("/")) {
prefix += "/";
}
if (!isValidDirectoryPath(prefix)) {
return incorrectUsage();
}
}
}
// Root directory, which is the same as no 'prefix' at all
if (prefix === "/") {
prefix = "";
}
// Display all programs and scripts
const allPrograms: string[] = [];
const allScripts: string[] = [];
const allTextFiles: string[] = [];
const allContracts: string[] = [];
const allMessages: string[] = [];
const folders: string[] = [];
function handleFn(fn: string, dest: string[]): void {
let parsedFn = fn;
if (prefix) {
if (!fn.startsWith(prefix)) {
return;
} else {
parsedFn = fn.slice(prefix.length, fn.length);
}
}
if (filter && !parsedFn.includes(filter)) {
return;
}
// If the fn includes a forward slash, it must be in a subdirectory.
// Therefore, we only list the "first" directory in its path
if (parsedFn.includes("/")) {
const firstParentDir = getFirstParentDirectory(parsedFn);
if (filter && !firstParentDir.includes(filter)) {
return;
}
if (!folders.includes(firstParentDir)) {
folders.push(firstParentDir);
}
return;
}
dest.push(parsedFn);
}
// Get all of the programs and scripts on the machine into one temporary array
const s = player.getCurrentServer();
for (const program of s.programs) handleFn(program, allPrograms);
for (const script of s.scripts) handleFn(script.filename, allScripts);
for (const txt of s.textFiles) handleFn(txt.fn, allTextFiles);
for (const contract of s.contracts) handleFn(contract.fn, allContracts);
for (const msgOrLit of s.messages)
msgOrLit instanceof Message ? handleFn(msgOrLit.filename, allMessages) : handleFn(msgOrLit, allMessages);
// Sort the files/folders alphabetically then print each
allPrograms.sort();
allScripts.sort();
allTextFiles.sort();
allContracts.sort();
allMessages.sort();
folders.sort();
function postSegments(segments: string[], config: any): void {
const maxLength = Math.max(...segments.map((s) => s.length)) + 1;
const filesPerRow = Math.floor(80 / maxLength);
for (let i = 0; i < segments.length; i++) {
let row = "";
for (let col = 0; col < filesPerRow; col++) {
if (!(i < segments.length)) break;
row += segments[i];
row += " ".repeat(maxLength * (col + 1) - row.length);
i++;
}
i--;
terminal.print(row, config);
}
}
const config = { color: "#0000FF" };
const groups = [
{ segments: folders, config: config },
{ segments: allMessages },
{ segments: allTextFiles },
{ segments: allPrograms },
{ segments: allContracts },
{ segments: allScripts },
].filter((g) => g.segments.length > 0);
for (let i = 0; i < groups.length; i++) {
if (i !== 0) {
terminal.print("");
terminal.print("");
}
postSegments(groups[i].segments, groups[i].config);
}
}

@ -0,0 +1,7 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
export function lscpu(terminal: ITerminal, engine: IEngine, player: IPlayer): void {
terminal.print(player.getCurrentServer().cpuCores + " Core(s)");
}

@ -0,0 +1,44 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { numeralWrapper } from "../../ui/numeralFormat";
export function mem(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
try {
if (args.length !== 1 && args.length !== 3) {
terminal.error("Incorrect usage of mem command. usage: mem [scriptname] [-t] [number threads]");
return;
}
const scriptName = args[0] + "";
let numThreads = 1;
if (args.length === 3 && args[1] === "-t") {
numThreads = Math.round(parseInt(args[2] + ""));
if (isNaN(numThreads) || numThreads < 1) {
terminal.error("Invalid number of threads specified. Number of threads must be greater than 1");
return;
}
}
const script = terminal.getScript(player, scriptName);
if (script == null) {
terminal.error("No such script exists!");
return;
}
const ramUsage = script.ramUsage * numThreads;
terminal.print(
`This script requires ${numeralWrapper.formatRAM(ramUsage)} of RAM to run for ${numThreads} thread(s)`,
);
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,91 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import { TextFile } from "../../TextFile";
import { Script } from "../../Script/Script";
export function mv(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 2) {
terminal.error(`Incorrect number of arguments. Usage: mv [src] [dest]`);
return;
}
try {
const source = args[0] + "";
const dest = args[1] + "";
if (!isScriptFilename(source) && !source.endsWith(".txt")) {
terminal.error(`'mv' can only be used on scripts and text files (.txt)`);
return;
}
const srcFile = terminal.getFile(player, source);
if (srcFile == null) {
terminal.error(`Source file ${source} does not exist`);
return;
}
const sourcePath = terminal.getFilepath(source);
const destPath = terminal.getFilepath(dest);
const destFile = terminal.getFile(player, dest);
// 'mv' command only works on scripts and txt files.
// Also, you can't convert between different file types
if (isScriptFilename(source)) {
const script = srcFile as Script;
if (!isScriptFilename(dest)) {
terminal.error(`Source and destination files must have the same type`);
return;
}
// Command doesnt work if script is running
if (server.isRunning(sourcePath)) {
terminal.error(`Cannot use 'mv' on a script that is running`);
return;
}
if (destFile != null) {
// Already exists, will be overwritten, so we'll delete it
const status = server.removeFile(destPath);
if (!status.res) {
terminal.error(`Something went wrong...please contact game dev (probably a bug)`);
return;
} else {
terminal.print("Warning: The destination file was overwritten");
}
}
script.filename = destPath;
} else if (srcFile instanceof TextFile) {
const textFile = srcFile as TextFile;
if (!dest.endsWith(".txt")) {
terminal.error(`Source and destination files must have the same type`);
return;
}
if (destFile != null) {
// Already exists, will be overwritten, so we'll delete it
const status = server.removeFile(destPath);
if (!status.res) {
terminal.error(`Something went wrong...please contact game dev (probably a bug)`);
return;
} else {
terminal.print("Warning: The destination file was overwritten");
}
}
textFile.fn = destPath;
}
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,57 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import { createFconf } from "../../Fconf/Fconf";
export function nano(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 1) {
terminal.error("Incorrect usage of nano command. Usage: nano [scriptname]");
return;
}
try {
const filename = args[0] + "";
if (filename === ".fconf") {
const text = createFconf();
engine.loadScriptEditorContent(filename, text);
return;
} else if (isScriptFilename(filename)) {
const filepath = terminal.getFilepath(filename);
const script = terminal.getScript(player, filename);
if (script == null) {
let code = "";
if (filename.endsWith(".ns") || filename.endsWith(".js")) {
code = `export async function main(ns) {
}`;
}
engine.loadScriptEditorContent(filepath, code);
} else {
engine.loadScriptEditorContent(filepath, script.code);
}
} else if (filename.endsWith(".txt")) {
const filepath = terminal.getFilepath(filename);
const txt = terminal.getTextFile(player, filename);
if (txt == null) {
engine.loadScriptEditorContent(filepath);
} else {
engine.loadScriptEditorContent(filepath, txt.text);
}
} else {
terminal.error(
"Invalid file. Only scripts (.script, .ns, .js), text files (.txt), or .fconf can be edited with nano",
);
return;
}
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,25 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function ps(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of ps command. Usage: ps");
return;
}
for (let i = 0; i < server.runningScripts.length; i++) {
const rsObj = server.runningScripts[i];
let res = `(PID - ${rsObj.pid}) ${rsObj.filename}`;
for (let j = 0; j < rsObj.args.length; ++j) {
res += " " + rsObj.args[j].toString();
}
terminal.print(res);
}
}

@ -0,0 +1,38 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { IReturnStatus } from "../../types";
export function rm(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 1) {
terminal.error("Incorrect number of arguments. Usage: rm [program/script]");
return;
}
// Check programs
let delTarget;
let status: IReturnStatus = {
res: true,
msg: "",
};
try {
delTarget = terminal.getFilepath(args[0] + "");
status = server.removeFile(delTarget);
} catch (err) {
status = {
res: false,
msg: "No such file exists",
};
}
if (!status.res && status.msg) {
terminal.error(status.msg);
}
}

@ -0,0 +1,40 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
import { runScript } from "./runScript";
import { runProgram } from "./runProgram";
export function run(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
// Run a program or a script
if (args.length < 1) {
terminal.error("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
} else {
const executableName = args[0] + "";
// Secret Music player!
// if (executableName === "musicplayer") {
// post(
// '<iframe src="https://open.spotify.com/embed/user/danielyxie/playlist/1ORnnL6YNvXOracUaUV2kh" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>',
// false,
// );
// return;
// }
// Check if its a script or just a program/executable
if (isScriptFilename(executableName)) {
runScript(terminal, engine, player, server, args);
} else if (executableName.endsWith(".cct")) {
terminal.runContract(player, executableName);
} else {
runProgram(terminal, engine, player, server, args);
}
}
}

@ -0,0 +1,44 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Programs } from "../../Programs/Programs";
export function runProgram(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length < 1) {
return;
}
// Check if you have the program on your computer. If you do, execute it, otherwise
// display an error message
const programName = args[0] + "";
if (!player.hasProgram(programName)) {
terminal.error("No such executable on home computer (Only programs that exist on your home computer can be run)");
return;
}
if (args.length < 1) {
return;
}
for (const program of Object.values(Programs)) {
if (program.name === programName) {
program.run(
terminal,
player,
server,
args.slice(1).map((arg) => arg + ""),
);
return;
}
}
terminal.print("Invalid executable. Cannot be run");
}

@ -0,0 +1,93 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { logBoxCreate } from "../../../utils/LogBox";
import { startWorkerScript } from "../../NetscriptWorker";
import { RunningScript } from "../../Script/RunningScript";
import { findRunningScript } from "../../Script/ScriptHelpers";
import * as libarg from "arg";
export function runScript(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
commandArgs: (string | number)[],
): void {
if (commandArgs.length < 1) {
terminal.error(
`Bug encountered with Terminal.runScript(). Command array has a length of less than 1: ${commandArgs}`,
);
return;
}
const scriptName = terminal.getFilepath(commandArgs[0] + "");
const runArgs = { "--tail": Boolean, "-t": Number };
const flags = libarg(runArgs, {
permissive: true,
argv: commandArgs.slice(1),
});
const threadFlag = Math.round(parseFloat(flags["-t"]));
const tailFlag = flags["--tail"] === true;
if (flags["-t"] !== undefined && (threadFlag < 0 || isNaN(threadFlag))) {
terminal.error("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
const numThreads = !isNaN(threadFlag) && threadFlag > 0 ? threadFlag : 1;
const args = flags["_"];
// Check if this script is already running
if (findRunningScript(scriptName, args, server) != null) {
terminal.print("ERROR: This script is already running. Cannot run multiple instances");
return;
}
// Check if the script exists and if it does run it
for (let i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename !== scriptName) {
continue;
}
// Check for admin rights and that there is enough RAM availble to run
const script = server.scripts[i];
const ramUsage = script.ramUsage * numThreads;
const ramAvailable = server.maxRam - server.ramUsed;
if (!server.hasAdminRights) {
terminal.print("Need root access to run script");
return;
}
if (ramUsage > ramAvailable) {
terminal.print(
"This machine does not have enough RAM to run this script with " +
numThreads +
" threads. Script requires " +
ramUsage +
"GB of RAM",
);
return;
}
// Able to run script
const runningScript = new RunningScript(script, args);
runningScript.threads = numThreads;
const success = startWorkerScript(runningScript, server);
if (!success) {
terminal.error(`Failed to start script`);
return;
}
terminal.print(
`Running script with ${numThreads} thread(s), pid ${runningScript.pid} and args: ${JSON.stringify(args)}.`,
);
if (tailFlag) {
logBoxCreate(runningScript);
}
return;
}
terminal.print("ERROR: No such script");
}

@ -0,0 +1,46 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { getServerOnNetwork } from "../../Server/ServerHelpers";
export function scan(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of netstat/scan command. Usage: netstat/scan");
return;
}
// Displays available network connections using TCP
const currServ = player.getCurrentServer();
const servers = currServ.serversOnNetwork.map((_, i) => {
const server = getServerOnNetwork(currServ, i);
if (server === null) throw new Error("Server should not be null");
return {
hostname: server.hostname,
ip: server.ip,
hasRoot: server.hasAdminRights ? "Y" : "N",
};
});
servers.unshift({
hostname: "Hostname",
ip: "IP",
hasRoot: "Root Access",
});
const maxHostname = Math.max(...servers.map((s) => s.hostname.length));
const maxIP = Math.max(...servers.map((s) => s.ip.length));
for (const server of servers) {
if (!server) continue;
let entry = server.hostname;
entry += " ".repeat(maxHostname - server.hostname.length + 1);
entry += server.ip;
entry += " ".repeat(maxIP - server.ip.length + 1);
entry += server.hasRoot;
terminal.print(entry);
}
}

@ -0,0 +1,45 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Programs } from "../../Programs/Programs";
export function scananalyze(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length === 0) {
terminal.executeScanAnalyzeCommand(player, 1);
} else {
// # of args must be 2 or 3
if (args.length > 2) {
terminal.error("Incorrect usage of scan-analyze command. usage: scan-analyze [depth]");
return;
}
let all = false;
if (args.length === 2 && args[1] === "-a") {
all = true;
}
const depth = parseInt(args[0] + "");
if (isNaN(depth) || depth < 0) {
terminal.error("Incorrect usage of scan-analyze command. depth argument must be positive numeric");
return;
}
if (depth > 3 && !player.hasProgram(Programs.DeepscanV1.name) && !player.hasProgram(Programs.DeepscanV2.name)) {
terminal.error("You cannot scan-analyze with that high of a depth. Maximum depth is 3");
return;
} else if (depth > 5 && !player.hasProgram(Programs.DeepscanV2.name)) {
terminal.error("You cannot scan-analyze with that high of a depth. Maximum depth is 5");
return;
} else if (depth > 10) {
terminal.error("You cannot scan-analyze with that high of a depth. Maximum depth is 10");
return;
}
terminal.executeScanAnalyzeCommand(player, depth, all);
}
}

@ -0,0 +1,112 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { Message } from "../../Message/Message";
import { getServer } from "../../Server/ServerHelpers";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
export function scp(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
try {
if (args.length !== 2) {
terminal.error("Incorrect usage of scp command. Usage: scp [file] [destination hostname/ip]");
return;
}
const scriptname = terminal.getFilepath(args[0] + "");
if (!scriptname.endsWith(".lit") && !isScriptFilename(scriptname) && !scriptname.endsWith(".txt")) {
terminal.error("scp only works for scripts, text files (.txt), and literature files (.lit)");
return;
}
const destServer = getServer(args[1] + "");
if (destServer == null) {
terminal.error(`Invalid destination. ${args[1]} not found`);
return;
}
// Scp for lit files
if (scriptname.endsWith(".lit")) {
let found = false;
for (let i = 0; i < server.messages.length; ++i) {
if (!(server.messages[i] instanceof Message) && server.messages[i] == scriptname) {
found = true;
break;
}
}
if (!found) {
return terminal.error("No such file exists!");
}
for (let i = 0; i < destServer.messages.length; ++i) {
if (destServer.messages[i] === scriptname) {
terminal.print(scriptname + " copied over to " + destServer.hostname);
return; // Already exists
}
}
destServer.messages.push(scriptname);
return terminal.print(scriptname + " copied over to " + destServer.hostname);
}
// Scp for txt files
if (scriptname.endsWith(".txt")) {
let txtFile = null;
for (let i = 0; i < server.textFiles.length; ++i) {
if (server.textFiles[i].fn === scriptname) {
txtFile = server.textFiles[i];
break;
}
}
if (txtFile === null) {
return terminal.error("No such file exists!");
}
const tRes = destServer.writeToTextFile(txtFile.fn, txtFile.text);
if (!tRes.success) {
terminal.error("scp failed");
return;
}
if (tRes.overwritten) {
terminal.print(`WARNING: ${scriptname} already exists on ${destServer.hostname} and will be overwriten`);
terminal.print(`${scriptname} overwritten on ${destServer.hostname}`);
return;
}
terminal.print(`${scriptname} copied over to ${destServer.hostname}`);
return;
}
// Get the current script
let sourceScript = null;
for (let i = 0; i < server.scripts.length; ++i) {
if (scriptname == server.scripts[i].filename) {
sourceScript = server.scripts[i];
break;
}
}
if (sourceScript == null) {
terminal.error("scp() failed. No such script exists");
return;
}
const sRes = destServer.writeToScriptFile(scriptname, sourceScript.code);
if (!sRes.success) {
terminal.error(`scp failed`);
return;
}
if (sRes.overwritten) {
terminal.print(`WARNING: ${scriptname} already exists on ${destServer.hostname} and will be overwritten`);
terminal.print(`${scriptname} overwritten on ${destServer.hostname}`);
return;
}
terminal.print(`${scriptname} copied over to ${destServer.hostname}`);
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,23 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
export function sudov(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect number of arguments. Usage: sudov");
return;
}
if (server.hasAdminRights) {
terminal.print("You have ROOT access to this machine");
} else {
terminal.print("You do NOT have root access to this machine");
}
}

@ -0,0 +1,81 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { logBoxCreate } from "../../../utils/LogBox";
import { findRunningScriptByPid } from "../../Script/ScriptHelpers";
import { compareArrays } from "../../../utils/helpers/compareArrays";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
export function tail(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
commandArray: (string | number)[],
): void {
try {
if (commandArray.length < 1) {
terminal.error("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
} else if (typeof commandArray[0] === "string") {
const scriptName = terminal.getFilepath(commandArray[0]);
if (!isScriptFilename(scriptName)) {
terminal.error("tail can only be called on .script, .ns, .js files, or by pid");
return;
}
// Get script arguments
const args = [];
for (let i = 1; i < commandArray.length; ++i) {
args.push(commandArray[i]);
}
// go over all the running scripts. If there's a perfect
// match, use it!
for (let i = 0; i < server.runningScripts.length; ++i) {
if (server.runningScripts[i].filename === scriptName && compareArrays(server.runningScripts[i].args, args)) {
logBoxCreate(server.runningScripts[i]);
return;
}
}
// Find all scripts that are potential candidates.
const candidates = [];
for (let i = 0; i < server.runningScripts.length; ++i) {
// only scripts that have more arguments (equal arguments is already caught)
if (server.runningScripts[i].args.length < args.length) continue;
// make a smaller copy of the args.
const args2 = server.runningScripts[i].args.slice(0, args.length);
if (server.runningScripts[i].filename === scriptName && compareArrays(args2, args)) {
candidates.push(server.runningScripts[i]);
}
}
// If there's only 1 possible choice, use that.
if (candidates.length === 1) {
logBoxCreate(candidates[0]);
return;
}
// otherwise lists all possible conflicting choices.
if (candidates.length > 1) {
terminal.error("Found several potential candidates:");
for (const candidate of candidates) terminal.error(`${candidate.filename} ${candidate.args.join(" ")}`);
terminal.error("Script arguments need to be specified.");
return;
}
// if there's no candidate then we just don't know.
terminal.error("No such script exists.");
} else {
const runningScript = findRunningScriptByPid(commandArray[0], server);
if (runningScript == null) {
terminal.error("No such script exists");
return;
}
logBoxCreate(runningScript);
}
} catch (e) {
terminal.error(e + "");
}
}

@ -0,0 +1,60 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { FconfSettings } from "../../Fconf/FconfSettings";
export function theme(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 1 && args.length !== 3) {
terminal.error("Incorrect number of arguments.");
terminal.error(
"Usage: theme [default|muted|solarized] | #[background color hex] #[text color hex] #[highlight color hex]",
);
} else if (args.length === 1) {
const themeName = args[0];
if (themeName == "default") {
document.body.style.setProperty("--my-highlight-color", "#ffffff");
document.body.style.setProperty("--my-font-color", "#66ff33");
document.body.style.setProperty("--my-background-color", "#000000");
document.body.style.setProperty("--my-prompt-color", "#f92672");
} else if (themeName == "muted") {
document.body.style.setProperty("--my-highlight-color", "#ffffff");
document.body.style.setProperty("--my-font-color", "#66ff33");
document.body.style.setProperty("--my-background-color", "#252527");
} else if (themeName == "solarized") {
document.body.style.setProperty("--my-highlight-color", "#6c71c4");
document.body.style.setProperty("--my-font-color", "#839496");
document.body.style.setProperty("--my-background-color", "#002b36");
} else {
return terminal.error("Theme not found");
}
FconfSettings.THEME_HIGHLIGHT_COLOR = document.body.style.getPropertyValue("--my-highlight-color");
FconfSettings.THEME_FONT_COLOR = document.body.style.getPropertyValue("--my-font-color");
FconfSettings.THEME_BACKGROUND_COLOR = document.body.style.getPropertyValue("--my-background-color");
FconfSettings.THEME_PROMPT_COLOR = document.body.style.getPropertyValue("--my-prompt-color");
} else {
const inputBackgroundHex = args[0] + "";
const inputTextHex = args[1] + "";
const inputHighlightHex = args[2] + "";
if (
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputBackgroundHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputTextHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputHighlightHex)
) {
document.body.style.setProperty("--my-highlight-color", inputHighlightHex);
document.body.style.setProperty("--my-font-color", inputTextHex);
document.body.style.setProperty("--my-background-color", inputBackgroundHex);
FconfSettings.THEME_HIGHLIGHT_COLOR = document.body.style.getPropertyValue("--my-highlight-color");
FconfSettings.THEME_FONT_COLOR = document.body.style.getPropertyValue("--my-font-color");
FconfSettings.THEME_BACKGROUND_COLOR = document.body.style.getPropertyValue("--my-background-color");
} else {
return terminal.error("Invalid Hex Input for theme");
}
}
}

@ -0,0 +1,63 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { getRamUsageFromRunningScript } from "../../Script/RunningScriptHelpers";
import { numeralWrapper } from "../../ui/numeralFormat";
export function top(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of top command. Usage: top");
return;
}
// Headers
const scriptWidth = 40;
const pidWidth = 10;
const threadsWidth = 16;
const scriptTxt = "Script";
const pidTxt = "PID";
const threadsTxt = "Threads";
const ramTxt = "RAM Usage";
const spacesAfterScriptTxt = " ".repeat(scriptWidth - scriptTxt.length);
const spacesAfterPidTxt = " ".repeat(pidWidth - pidTxt.length);
const spacesAfterThreadsTxt = " ".repeat(threadsWidth - threadsTxt.length);
const headers = `${scriptTxt}${spacesAfterScriptTxt}${pidTxt}${spacesAfterPidTxt}${threadsTxt}${spacesAfterThreadsTxt}${ramTxt}`;
terminal.print(headers);
const currRunningScripts = server.runningScripts;
// Iterate through scripts on current server
for (let i = 0; i < currRunningScripts.length; i++) {
const script = currRunningScripts[i];
// Calculate name padding
const numSpacesScript = Math.max(0, scriptWidth - script.filename.length);
const spacesScript = " ".repeat(numSpacesScript);
// Calculate PID padding
const numSpacesPid = Math.max(0, pidWidth - (script.pid + "").length);
const spacesPid = " ".repeat(numSpacesPid);
// Calculate thread padding
const numSpacesThread = Math.max(0, threadsWidth - (script.threads + "").length);
const spacesThread = " ".repeat(numSpacesThread);
// Calculate and transform RAM usage
const ramUsage = numeralWrapper.formatRAM(getRamUsageFromRunningScript(script) * script.threads);
const entry = [script.filename, spacesScript, script.pid, spacesPid, script.threads, spacesThread, ramUsage].join(
"",
);
terminal.print(entry);
}
}

@ -0,0 +1,24 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { removeAlias } from "../../Alias";
export function unalias(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 1) {
terminal.error("Incorrect usage of unalias name. Usage: unalias [alias]");
return;
} else {
if (removeAlias(args[0] + "")) {
terminal.print(`Removed alias ${args[0]}`);
} else {
terminal.error(`No such alias exists: ${args[0]}`);
}
}
}

@ -0,0 +1,45 @@
import { ITerminal } from "../ITerminal";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/ScriptHelpersTS";
export function wget(
terminal: ITerminal,
engine: IEngine,
player: IPlayer,
server: BaseServer,
args: (string | number)[],
): void {
if (args.length !== 2) {
terminal.error("Incorrect usage of wget command. Usage: wget [url] [target file]");
return;
}
const url = args[0] + "";
const target = terminal.getFilepath(args[1] + "");
if (!isScriptFilename(target) && !target.endsWith(".txt")) {
return terminal.print(`wget failed: Invalid target file. Target file must be script or text file`);
}
$.get(
url,
function (data: any) {
let res;
if (isScriptFilename(target)) {
res = server.writeToScriptFile(target, data);
} else {
res = server.writeToTextFile(target, data);
}
if (!res.success) {
return terminal.print("wget failed");
}
if (res.overwritten) {
return terminal.print(`wget successfully retrieved content and overwrote ${target}`);
}
return terminal.print(`wget successfully retrieved content to new file ${target}`);
},
"text",
).fail(function (e) {
return terminal.error("wget failed: " + JSON.stringify(e));
});
}

1
src/ThirdParty/arg.d.ts vendored Normal file

@ -0,0 +1 @@
declare module "arg";

@ -58,7 +58,6 @@ import { Terminal, postVersion } from "./Terminal";
import { TutorialRoot } from "./Tutorial/ui/TutorialRoot";
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
import { createStatusText } from "./ui/createStatusText";
import { CharacterInfo } from "./ui/CharacterInfo";
import { Page, routing } from "./ui/navigationTracking";
import { Money } from "./ui/React/Money";
@ -68,8 +67,6 @@ import { Reputation } from "./ui/React/Reputation";
import { ActiveScriptsRoot } from "./ui/ActiveScripts/Root";
import { MainMenuLinks } from "./ui/MainMenu/Links";
import { createPopup } from "./ui/React/createPopup";
import { dialogBoxCreate } from "../utils/DialogBox";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";