mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-25 23:47:34 +01:00
commit
2cb762184f
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.DS_Store
|
||||
.vscode
|
||||
Changelog.txt
|
||||
Netburner.txt
|
||||
@ -9,5 +10,9 @@ Netburner.txt
|
||||
/test/*.css
|
||||
.cypress
|
||||
|
||||
# tmp folder for electron
|
||||
.package
|
||||
.build
|
||||
|
||||
# editor files
|
||||
.vscode
|
||||
|
@ -5,120 +5,8 @@
|
||||
* Styling for the Character Overview Panel (top-right panel)
|
||||
*/
|
||||
|
||||
#character-overview-wrapper {
|
||||
#character-overview {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#character-overview-container {
|
||||
display: none;
|
||||
position: absolute; /* Stay in place */
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: auto; /* Full height */
|
||||
padding: 10px 2px;
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
width: auto;
|
||||
max-width: 280px;
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
background-color: rgba(57, 54, 54, 0.9); /* Fallback color */
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#character-overview-text {
|
||||
color: $my-stat-physical;
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.character-stat-text {
|
||||
color: #fff;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.character-stat-cell {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#character-str-wrapper td,
|
||||
#character-cha-wrapper td {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.character-divider td {
|
||||
border-top: 1px #aaa solid;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#character-hp-wrapper {
|
||||
color: $my-stat-hp-color;
|
||||
}
|
||||
.character-hp-cell {
|
||||
color: $my-stat-hp-color;
|
||||
}
|
||||
#character-money-wrapper {
|
||||
color: $my-stat-money-color;
|
||||
}
|
||||
.character-money-cell {
|
||||
color: $my-stat-money-color;
|
||||
}
|
||||
#character-hack-wrapper {
|
||||
color: $my-stat-hack-color;
|
||||
}
|
||||
.character-hack-cell {
|
||||
color: $my-stat-hack-color;
|
||||
}
|
||||
#character-cha-wrapper {
|
||||
color: $my-stat-cha-color;
|
||||
}
|
||||
.character-cha-cell {
|
||||
color: $my-stat-cha-color;
|
||||
}
|
||||
#character-int-wrapper {
|
||||
color: $my-stat-int-color;
|
||||
}
|
||||
.character-int-cell {
|
||||
color: $my-stat-int-color;
|
||||
}
|
||||
.character-combat-cell {
|
||||
color: $my-stat-physical;
|
||||
}
|
||||
#character-work-wrapper {
|
||||
color: $my-stat-hack-color;
|
||||
}
|
||||
.character-work-cell {
|
||||
color: $my-stat-hack-color;
|
||||
}
|
||||
|
||||
.character-overview-btn {
|
||||
@include borderRadius(12px);
|
||||
@include boxShadow(1px 1px 3px #000);
|
||||
color: #cecece;
|
||||
display: inline-block;
|
||||
font-size: $defaultFontSize * 0.875;
|
||||
font-weight: bold;
|
||||
height: 25px;
|
||||
background-color: #000;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.character-quick-options {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.character-overview-btn:hover,
|
||||
.character-overview-btn:focus {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -63,6 +63,8 @@
|
||||
overflow: visible;
|
||||
top: 10px;
|
||||
width: 45%;
|
||||
vertical-align: top;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cmpy-mgmt-industry-overview-panel {
|
||||
|
@ -4,18 +4,12 @@
|
||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||
terminal which has its own page) */
|
||||
|
||||
.generic-menupage-container {
|
||||
padding-left: 2px;
|
||||
#generic-react-container {
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#generic-react-container {
|
||||
padding: 10px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#generic-react-container::-webkit-scrollbar {
|
||||
display: none; /* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
4
dist/engine.bundle.js
vendored
4
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/engineStyle.bundle.js
vendored
2
dist/engineStyle.bundle.js
vendored
@ -1,2 +1,2 @@
|
||||
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],a=0,s=[];a<f.length;a++)i=f[a],Object.prototype.hasOwnProperty.call(r,i)&&r[i]&&s.push(r[i][0]),r[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,l||[]),o()}function o(){for(var n,t=0;t<u.length;t++){for(var o=u[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==r[c]&&(e=!1)}e&&(u.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},r={2:0},u=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var p=c;u.push([1045,0]),o()}({1045:function(n,t,o){"use strict";o.r(t);o(1046),o(1048),o(1050),o(1052),o(1054),o(1056),o(1058),o(1060),o(1062),o(1064),o(1066),o(1068),o(1070),o(1072),o(1074),o(1076),o(1078),o(1080),o(1082),o(1084),o(1086),o(1088),o(1090),o(1092),o(1094),o(1096),o(1098),o(1100),o(1102),o(1104),o(1106)},1048:function(n,t,o){},1050:function(n,t,o){},1052:function(n,t,o){},1054:function(n,t,o){},1056:function(n,t,o){},1058:function(n,t,o){},1060:function(n,t,o){},1062:function(n,t,o){},1064:function(n,t,o){},1066:function(n,t,o){},1068:function(n,t,o){},1070:function(n,t,o){},1072:function(n,t,o){},1074:function(n,t,o){},1076:function(n,t,o){},1078:function(n,t,o){},1080:function(n,t,o){},1082:function(n,t,o){},1084:function(n,t,o){},1086:function(n,t,o){},1088:function(n,t,o){},1090:function(n,t,o){},1092:function(n,t,o){},1094:function(n,t,o){},1096:function(n,t,o){},1098:function(n,t,o){},1100:function(n,t,o){},1102:function(n,t,o){},1104:function(n,t,o){},1106:function(n,t,o){}});
|
||||
!function(n){function t(t){for(var e,i,f=t[0],c=t[1],l=t[2],a=0,s=[];a<f.length;a++)i=f[a],Object.prototype.hasOwnProperty.call(r,i)&&r[i]&&s.push(r[i][0]),r[i]=0;for(e in c)Object.prototype.hasOwnProperty.call(c,e)&&(n[e]=c[e]);for(p&&p(t);s.length;)s.shift()();return u.push.apply(u,l||[]),o()}function o(){for(var n,t=0;t<u.length;t++){for(var o=u[t],e=!0,f=1;f<o.length;f++){var c=o[f];0!==r[c]&&(e=!1)}e&&(u.splice(t--,1),n=i(i.s=o[0]))}return n}var e={},r={2:0},u=[];function i(t){if(e[t])return e[t].exports;var o=e[t]={i:t,l:!1,exports:{}};return n[t].call(o.exports,o,o.exports,i),o.l=!0,o.exports}i.m=n,i.c=e,i.d=function(n,t,o){i.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},i.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},i.t=function(n,t){if(1&t&&(n=i(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var e in n)i.d(o,e,function(t){return n[t]}.bind(null,e));return o},i.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return i.d(t,"a",t),t},i.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},i.p="";var f=window.webpackJsonp=window.webpackJsonp||[],c=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var p=c;u.push([1252,0]),o()}({1252:function(n,t,o){"use strict";o.r(t);o(1253),o(1255),o(1257),o(1259),o(1261),o(1263),o(1265),o(1267),o(1269),o(1271),o(1273),o(1275),o(1277),o(1279),o(1281),o(1283),o(1285),o(1287),o(1289),o(1291),o(1293),o(1295),o(1297),o(1299),o(1301),o(1303),o(1305),o(1307),o(1309),o(1311),o(1313)},1255:function(n,t,o){},1257:function(n,t,o){},1259:function(n,t,o){},1261:function(n,t,o){},1263:function(n,t,o){},1265:function(n,t,o){},1267:function(n,t,o){},1269:function(n,t,o){},1271:function(n,t,o){},1273:function(n,t,o){},1275:function(n,t,o){},1277:function(n,t,o){},1279:function(n,t,o){},1281:function(n,t,o){},1283:function(n,t,o){},1285:function(n,t,o){},1287:function(n,t,o){},1289:function(n,t,o){},1291:function(n,t,o){},1293:function(n,t,o){},1295:function(n,t,o){},1297:function(n,t,o){},1299:function(n,t,o){},1301:function(n,t,o){},1303:function(n,t,o){},1305:function(n,t,o){},1307:function(n,t,o){},1309:function(n,t,o){},1311:function(n,t,o){},1313:function(n,t,o){}});
|
||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
119
dist/engineStyle.css
vendored
119
dist/engineStyle.css
vendored
@ -1226,117 +1226,11 @@ button {
|
||||
/**
|
||||
* Styling for the Character Overview Panel (top-right panel)
|
||||
*/
|
||||
#character-overview-wrapper {
|
||||
#character-overview {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0; }
|
||||
|
||||
#character-overview-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* Stay in place */
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: auto;
|
||||
/* Full height */
|
||||
padding: 10px 2px;
|
||||
border: 2px solid var(--my-highlight-color);
|
||||
width: auto;
|
||||
max-width: 280px;
|
||||
overflow: auto;
|
||||
/* Enable scroll if needed */
|
||||
background-color: rgba(57, 54, 54, 0.9);
|
||||
/* Fallback color */
|
||||
z-index: 1; }
|
||||
|
||||
#character-overview-text {
|
||||
color: #faffdf; }
|
||||
#character-overview-text table {
|
||||
border-collapse: collapse;
|
||||
margin: auto; }
|
||||
#character-overview-text td {
|
||||
padding: 2px;
|
||||
vertical-align: middle; }
|
||||
|
||||
.character-stat-text {
|
||||
color: #fff;
|
||||
background-color: #444; }
|
||||
|
||||
.character-stat-cell {
|
||||
text-align: right; }
|
||||
|
||||
#character-str-wrapper td,
|
||||
#character-cha-wrapper td {
|
||||
padding-top: 10px; }
|
||||
|
||||
.character-divider td {
|
||||
border-top: 1px #aaa solid;
|
||||
padding-top: 10px; }
|
||||
|
||||
#character-hp-wrapper {
|
||||
color: #dd3434; }
|
||||
|
||||
.character-hp-cell {
|
||||
color: #dd3434; }
|
||||
|
||||
#character-money-wrapper {
|
||||
color: #ffd700; }
|
||||
|
||||
.character-money-cell {
|
||||
color: #ffd700; }
|
||||
|
||||
#character-hack-wrapper {
|
||||
color: #adff2f; }
|
||||
|
||||
.character-hack-cell {
|
||||
color: #adff2f; }
|
||||
|
||||
#character-cha-wrapper {
|
||||
color: #a671d1; }
|
||||
|
||||
.character-cha-cell {
|
||||
color: #a671d1; }
|
||||
|
||||
#character-int-wrapper {
|
||||
color: #6495ed; }
|
||||
|
||||
.character-int-cell {
|
||||
color: #6495ed; }
|
||||
|
||||
.character-combat-cell {
|
||||
color: #faffdf; }
|
||||
|
||||
#character-work-wrapper {
|
||||
color: #adff2f; }
|
||||
|
||||
.character-work-cell {
|
||||
color: #adff2f; }
|
||||
|
||||
.character-overview-btn {
|
||||
-webkit-border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-webkit-box-shadow: 1px 1px 3px #000;
|
||||
-moz-box-shadow: 1px 1px 3px #000;
|
||||
box-shadow: 1px 1px 3px #000;
|
||||
color: #cecece;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
height: 25px;
|
||||
background-color: #000;
|
||||
padding: 5px 8px; }
|
||||
|
||||
.character-quick-options {
|
||||
margin-top: 10px;
|
||||
text-align: center; }
|
||||
|
||||
.character-overview-btn:hover,
|
||||
.character-overview-btn:focus {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
cursor: pointer; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
#terminal-container {
|
||||
@ -1639,18 +1533,13 @@ button {
|
||||
/* Attributes */
|
||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||
terminal which has its own page) */
|
||||
.generic-menupage-container {
|
||||
padding-left: 2px;
|
||||
#generic-react-container {
|
||||
-ms-overflow-style: none;
|
||||
/* for Internet Explorer, Edge */
|
||||
scrollbar-width: none;
|
||||
/* for Firefox */
|
||||
flex-grow: 1; }
|
||||
|
||||
#generic-react-container {
|
||||
padding: 10px;
|
||||
overflow-y: scroll; }
|
||||
|
||||
#generic-react-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
/* for Chrome, Safari, and Opera */ }
|
||||
@ -3041,7 +2930,9 @@ input[type="checkbox"] {
|
||||
overflow-x: auto;
|
||||
overflow: visible;
|
||||
top: 10px;
|
||||
width: 45%; }
|
||||
width: 45%;
|
||||
vertical-align: top;
|
||||
margin-top: 10px; }
|
||||
|
||||
.cmpy-mgmt-industry-overview-panel {
|
||||
border: 1px solid #fff;
|
||||
|
225
dist/vendor.bundle.js
vendored
225
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
BIN
electron/icon.png
Normal file
BIN
electron/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
19
electron/main.js
Normal file
19
electron/main.js
Normal file
@ -0,0 +1,19 @@
|
||||
const { app, BrowserWindow, Menu } = require("electron");
|
||||
Menu.setApplicationMenu(false);
|
||||
function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
devTools: false,
|
||||
},
|
||||
});
|
||||
|
||||
win.removeMenu();
|
||||
win.maximize();
|
||||
win.loadFile("index.html");
|
||||
win.show();
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
});
|
7
electron/package.json
Executable file
7
electron/package.json
Executable file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.0.0",
|
||||
"description": "A cyberpunk-themed programming incremental game",
|
||||
"main": "main.js",
|
||||
"author": "Daniel Xie"
|
||||
}
|
27
index.html
27
index.html
@ -42,21 +42,7 @@
|
||||
<div id="mainmenu-container" style="display: flex; flex-direction: row">
|
||||
<!-- Main menu -->
|
||||
<div id="sidebar" style=""></div>
|
||||
<!-- Terminal page -->
|
||||
<div id="terminal-container" style="flex-grow: 1">
|
||||
<table id="terminal">
|
||||
<tr id="terminal-input">
|
||||
<td id="terminal-input-td" tabindex="2">
|
||||
$
|
||||
<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1" onfocus="this.value = this.value;" autocomplete="off"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="generic-menupage-container">
|
||||
<div id="generic-react-container"></div>
|
||||
</div>
|
||||
<div id="generic-react-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="infiltration-container" class="generic-fullscreen-container"></div>
|
||||
@ -89,16 +75,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Character Overview Screen -->
|
||||
<div id="character-overview-wrapper">
|
||||
<div id="character-overview-container">
|
||||
<div id="character-overview-text">
|
||||
<!-- ReactJS Component -->
|
||||
</div>
|
||||
<div class="character-quick-options noselect">
|
||||
<button id="character-overview-save-button" class="character-overview-btn">Save Game</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="character-overview"></div>
|
||||
|
||||
<!-- Status text -->
|
||||
<div id="status-text-container">
|
||||
|
4100
package-lock.json
generated
4100
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@ -1,4 +1,8 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "0.53.0",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie"
|
||||
},
|
||||
@ -6,13 +10,17 @@
|
||||
"url": "https://github.com/danielyxie/bitburner/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.3",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@emotion/react": "^11.4.1",
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@monaco-editor/react": "^4.2.2",
|
||||
"@mui/icons-material": "^5.0.0-rc.1",
|
||||
"@mui/lab": "^5.0.0-alpha.46",
|
||||
"@mui/material": "^5.0.0-rc.1",
|
||||
"@mui/styles": "^5.0.0-rc.1",
|
||||
"@types/js-beautify": "^1.13.2",
|
||||
"@types/numeral": "0.0.25",
|
||||
"@types/react": "^16.8.6",
|
||||
"@types/react-dom": "^16.8.2",
|
||||
"@types/react": "^17.0.21",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"ajv": "^5.1.5",
|
||||
@ -42,8 +50,8 @@
|
||||
"node-sass": "^6.0.1",
|
||||
"normalize.css": "^8.0.0",
|
||||
"numeral": "2.0.6",
|
||||
"react": "^16.8.3",
|
||||
"react-dom": "^16.8.3",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-modal": "^3.12.1",
|
||||
"sprintf-js": "^1.1.1",
|
||||
"tapable": "^1.0.0",
|
||||
@ -59,6 +67,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",
|
||||
@ -71,6 +80,8 @@
|
||||
"bundle-loader": "~0.5.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"cypress": "^8.3.1",
|
||||
"electron": "^14.0.1",
|
||||
"electron-packager": "^15.4.0",
|
||||
"es6-promise-polyfill": "^1.1.1",
|
||||
"eslint": "^7.24.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
@ -120,8 +131,6 @@
|
||||
"node": ">=8 || <=9"
|
||||
},
|
||||
"homepage": "https://github.com/danielyxie/bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"name": "bitburner",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/danielyxie/bitburner.git"
|
||||
@ -144,7 +153,7 @@
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"watch": "webpack --watch --mode production",
|
||||
"watch:dev": "webpack --watch --mode development"
|
||||
},
|
||||
"version": "0.53.0"
|
||||
"watch:dev": "webpack --watch --mode development",
|
||||
"package-electron": "electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png"
|
||||
}
|
||||
}
|
||||
|
14
package.sh
Executable file
14
package.sh
Executable file
@ -0,0 +1,14 @@
|
||||
# npm install electron --save-dev
|
||||
# npm install electron-packager --save-dev
|
||||
|
||||
mkdir -p .package/dist || true
|
||||
|
||||
cp index.html .package
|
||||
cp electron/* .package
|
||||
cp dist/engine.bundle.js .package/dist
|
||||
cp dist/engineStyle.css .package/dist
|
||||
cp dist/vendor.css .package/dist
|
||||
cp dist/engineStyle.bundle.js .package/dist
|
||||
cp dist/vendor.bundle.js .package/dist
|
||||
|
||||
npm run package-electron
|
@ -1,5 +1,5 @@
|
||||
import { IMap } from "./types";
|
||||
import { post } from "./ui/postToTerminal";
|
||||
import { Terminal } from "./Terminal";
|
||||
|
||||
export let Aliases: IMap<string> = {};
|
||||
export let GlobalAliases: IMap<string> = {};
|
||||
@ -24,12 +24,12 @@ export function loadGlobalAliases(saveString: string): void {
|
||||
export function printAliases(): void {
|
||||
for (const name in Aliases) {
|
||||
if (Aliases.hasOwnProperty(name)) {
|
||||
post("alias " + name + "=" + Aliases[name]);
|
||||
Terminal.print("alias " + name + "=" + Aliases[name]);
|
||||
}
|
||||
}
|
||||
for (const name in GlobalAliases) {
|
||||
if (GlobalAliases.hasOwnProperty(name)) {
|
||||
post("global alias " + name + "=" + GlobalAliases[name]);
|
||||
Terminal.print("global alias " + name + "=" + GlobalAliases[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { Money } from "../ui/React/Money";
|
||||
import { Game } from "./Game";
|
||||
import { Deck } from "./CardDeck/Deck";
|
||||
import { Hand } from "./CardDeck/Hand";
|
||||
import { InputAdornment } from "@material-ui/core";
|
||||
import { InputAdornment } from "@mui/material";
|
||||
import { ReactCard } from "./CardDeck/ReactCard";
|
||||
import { MuiTextField } from "../ui/React/MuiTextField";
|
||||
import { MuiButton } from "../ui/React/MuiButton";
|
||||
|
@ -179,7 +179,6 @@ export class CodingContract {
|
||||
removePopup(popupId);
|
||||
},
|
||||
onAttempt: (val: string) => {
|
||||
console.error("attempting");
|
||||
if (this.isSolution(val)) {
|
||||
resolve(CodingContractResult.Success);
|
||||
} else {
|
||||
|
@ -1,10 +1,9 @@
|
||||
import * as React from "react";
|
||||
import { DarkWebItems } from "./DarkWebItems";
|
||||
|
||||
import { Player } from "../Player";
|
||||
import { Terminal } from "../Terminal";
|
||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||
import { post, postElement } from "../ui/postToTerminal";
|
||||
import { Money } from "../ui/React/Money";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import { isValidIPAddress } from "../../utils/helpers/isValidIPAddress";
|
||||
|
||||
@ -16,7 +15,7 @@ export function checkIfConnectedToDarkweb(): void {
|
||||
return;
|
||||
}
|
||||
if (darkwebIp == Player.getCurrentServer().ip) {
|
||||
post(
|
||||
Terminal.print(
|
||||
"You are now connected to the dark web. From the dark web you can purchase illegal items. " +
|
||||
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
|
||||
"to purchase an item.",
|
||||
@ -35,9 +34,9 @@ export function executeDarkwebTerminalCommand(commandArray: string[]): void {
|
||||
switch (commandArray[0]) {
|
||||
case "buy": {
|
||||
if (commandArray.length != 2) {
|
||||
post("Incorrect number of arguments. Usage: ");
|
||||
post("buy -l");
|
||||
post("buy [item name]");
|
||||
Terminal.error("Incorrect number of arguments. Usage: ");
|
||||
Terminal.print("buy -l");
|
||||
Terminal.print("buy [item name]");
|
||||
return;
|
||||
}
|
||||
const arg = commandArray[1];
|
||||
@ -49,23 +48,19 @@ export function executeDarkwebTerminalCommand(commandArray: string[]): void {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
post("Command not found");
|
||||
Terminal.error("Command not found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function listAllDarkwebItems(): void {
|
||||
export function listAllDarkwebItems(): void {
|
||||
for (const key in DarkWebItems) {
|
||||
const item = DarkWebItems[key];
|
||||
postElement(
|
||||
<>
|
||||
{item.program} - <Money money={item.price} player={Player} /> - {item.description}
|
||||
</>,
|
||||
);
|
||||
Terminal.print(`${item.program} - ${numeralWrapper.formatMoney(item.price)} - ${item.description}`);
|
||||
}
|
||||
}
|
||||
|
||||
function buyDarkwebItem(itemName: string): void {
|
||||
export function buyDarkwebItem(itemName: string): void {
|
||||
itemName = itemName.toLowerCase();
|
||||
|
||||
// find the program that matches, if any
|
||||
@ -79,24 +74,26 @@ function buyDarkwebItem(itemName: string): void {
|
||||
|
||||
// return if invalid
|
||||
if (item === null) {
|
||||
post("Unrecognized item: " + itemName);
|
||||
Terminal.print("Unrecognized item: " + itemName);
|
||||
return;
|
||||
}
|
||||
|
||||
// return if the player already has it.
|
||||
if (Player.hasProgram(item.program)) {
|
||||
post("You already have the " + item.program + " program");
|
||||
Terminal.print("You already have the " + item.program + " program");
|
||||
return;
|
||||
}
|
||||
|
||||
// return if the player doesn't have enough money
|
||||
if (Player.money.lt(item.price)) {
|
||||
post("Not enough money to purchase " + item.program);
|
||||
Terminal.print("Not enough money to purchase " + item.program);
|
||||
return;
|
||||
}
|
||||
|
||||
// buy and push
|
||||
Player.loseMoney(item.price);
|
||||
Player.getHomeComputer().programs.push(item.program);
|
||||
post("You have purchased the " + item.program + " program. The new program can be found on your home computer.");
|
||||
Terminal.print(
|
||||
"You have purchased the " + item.program + " program. The new program can be found on your home computer.",
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { IEngine } from "./IEngine";
|
||||
|
||||
import React from "react";
|
||||
import { Theme } from "./ui/React/Theme";
|
||||
import { TTheme as Theme } from "./ui/React/Theme";
|
||||
|
||||
import { General } from "./DevMenu/ui/General";
|
||||
import { Stats } from "./DevMenu/ui/Stats";
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import AddIcon from "@material-ui/icons/Add";
|
||||
import RemoveIcon from "@material-ui/icons/Remove";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import ExposureZeroIcon from "@material-ui/icons/ExposureZero";
|
||||
import DoubleArrowIcon from "@material-ui/icons/DoubleArrow";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import RemoveIcon from "@mui/icons-material/Remove";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import DoubleArrowIcon from "@mui/icons-material/DoubleArrow";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
|
||||
interface IProps {
|
||||
label: string;
|
||||
@ -37,12 +37,12 @@ export function Adjuster(props: IProps): React.ReactElement {
|
||||
startAdornment: (
|
||||
<>
|
||||
<Tooltip title="Add a lot">
|
||||
<IconButton color="primary" onClick={tons}>
|
||||
<IconButton color="primary" onClick={tons} size="large">
|
||||
<DoubleArrowIcon style={{ transform: "rotate(-90deg)" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Add">
|
||||
<IconButton color="primary" onClick={() => add(typeof value !== "string" ? value : 0)}>
|
||||
<IconButton color="primary" onClick={() => add(typeof value !== "string" ? value : 0)} size="large">
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
@ -51,13 +51,17 @@ export function Adjuster(props: IProps): React.ReactElement {
|
||||
endAdornment: (
|
||||
<>
|
||||
<Tooltip title="Remove">
|
||||
<IconButton color="primary" onClick={() => subtract(typeof value !== "string" ? value : 0)}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => subtract(typeof value !== "string" ? value : 0)}
|
||||
size="large"
|
||||
>
|
||||
<RemoveIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Reset">
|
||||
<IconButton color="primary" onClick={reset}>
|
||||
<ExposureZeroIcon />
|
||||
<IconButton color="primary" onClick={reset} size="large">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
|
@ -1,17 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Select from "@material-ui/core/Select";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import ReplyAllIcon from "@material-ui/icons/ReplyAll";
|
||||
import ReplyIcon from "@material-ui/icons/Reply";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
||||
import ReplyIcon from "@mui/icons-material/Reply";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
@ -20,7 +21,7 @@ interface IProps {
|
||||
export function Augmentations(props: IProps): React.ReactElement {
|
||||
const [augmentation, setAugmentation] = useState("Augmented Targeting I");
|
||||
|
||||
function setAugmentationDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setAugmentationDropdown(event: SelectChangeEvent<string>): void {
|
||||
setAugmentation(event.target.value as string);
|
||||
}
|
||||
function queueAug(): void {
|
||||
@ -33,6 +34,11 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
props.player.queueAugmentation(augName);
|
||||
}
|
||||
}
|
||||
|
||||
function clearAugs(): void {
|
||||
props.player.augmentations = [];
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
@ -53,14 +59,21 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
value={augmentation}
|
||||
startAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={queueAllAugs}>
|
||||
<IconButton color="primary" onClick={queueAllAugs} size="large">
|
||||
<ReplyAllIcon />
|
||||
</IconButton>
|
||||
<IconButton color="primary" onClick={queueAug}>
|
||||
<IconButton color="primary" onClick={queueAug} size="large">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
endAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={clearAugs} size="large">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{Object.values(AugmentationNames).map((aug) => (
|
||||
<MenuItem key={aug} value={aug}>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
@ -1,19 +1,19 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { generateContract, generateRandomContract, generateRandomContractOnHome } from "../../CodingContractGenerator";
|
||||
import { CodingContractTypes } from "../../CodingContracts";
|
||||
|
||||
export function CodingContracts(): React.ReactElement {
|
||||
const [codingcontract, setCodingcontract] = useState("Find Largest Prime Factor");
|
||||
function setCodingcontractDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setCodingcontractDropdown(event: SelectChangeEvent<string>): void {
|
||||
setCodingcontract(event.target.value as string);
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { Companies as AllCompanies } from "../../Company/Companies";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
|
||||
const bigNumber = 1e12;
|
||||
|
||||
export function Companies(): React.ReactElement {
|
||||
const [company, setCompany] = useState("ECorp");
|
||||
function setCompanyDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setCompanyDropdown(event: SelectChangeEvent<string>): void {
|
||||
setCompany(event.target.value as string);
|
||||
}
|
||||
function resetCompanyRep(): void {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Factions as AllFaction } from "../../Faction/Factions";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import ReplyAllIcon from "@material-ui/icons/ReplyAll";
|
||||
import ReplyIcon from "@material-ui/icons/Reply";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
||||
import ReplyIcon from "@mui/icons-material/Reply";
|
||||
import InputLabel from "@mui/material/InputLabel";
|
||||
|
||||
const bigNumber = 1e12;
|
||||
|
||||
@ -26,7 +26,7 @@ interface IProps {
|
||||
export function Factions(props: IProps): React.ReactElement {
|
||||
const [faction, setFaction] = useState("Illuminati");
|
||||
|
||||
function setFactionDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setFactionDropdown(event: SelectChangeEvent<string>): void {
|
||||
setFaction(event.target.value as string);
|
||||
}
|
||||
|
||||
@ -119,10 +119,10 @@ export function Factions(props: IProps): React.ReactElement {
|
||||
value={faction}
|
||||
startAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={receiveAllInvites}>
|
||||
<IconButton color="primary" onClick={receiveAllInvites} size="large">
|
||||
<ReplyAllIcon />
|
||||
</IconButton>
|
||||
<IconButton color="primary" onClick={receiveInvite}>
|
||||
<IconButton color="primary" onClick={receiveInvite} size="large">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { hackWorldDaemon } from "../../RedPill";
|
||||
|
@ -1,15 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Programs as AllPrograms } from "../../Programs/Programs";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
@ -17,7 +17,7 @@ interface IProps {
|
||||
|
||||
export function Programs(props: IProps): React.ReactElement {
|
||||
const [program, setProgram] = useState("NUKE.exe");
|
||||
function setProgramDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setProgramDropdown(event: SelectChangeEvent<string>): void {
|
||||
setProgram(event.target.value as string);
|
||||
}
|
||||
function addProgram(): void {
|
||||
|
@ -1,20 +1,20 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { GetServerByHostname } from "../../Server/ServerHelpers";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
|
||||
export function Servers(): React.ReactElement {
|
||||
const [server, setServer] = useState("home");
|
||||
function setServerDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
|
||||
function setServerDropdown(event: SelectChangeEvent<string>): void {
|
||||
setServer(event.target.value as string);
|
||||
}
|
||||
function rootServer(): void {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface IProps {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { PlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import ButtonGroup from "@material-ui/core/ButtonGroup";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
|
||||
// Update as additional BitNodes get implemented
|
||||
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { StockMarket as SM } from "../../StockMarket/StockMarket";
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Button from "@mui/material/Button";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { saveObject } from "../../SaveObject";
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
@ -3,18 +3,18 @@ import { AllServers } from "../Server/AllServers";
|
||||
import { Modal } from "../ui/React/Modal";
|
||||
import { numeralWrapper } from "../ui/numeralFormat";
|
||||
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableContainer from "@material-ui/core/TableContainer";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Accordion from "@material-ui/core/Accordion";
|
||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Accordion from "@mui/material/Accordion";
|
||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
interface IServerProps {
|
||||
ip: string;
|
||||
|
1
src/Fconf/Fconf.d.ts
vendored
1
src/Fconf/Fconf.d.ts
vendored
@ -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,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
interface IProps {
|
||||
onFinish: () => void;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Countdown } from "./Countdown";
|
||||
import { BracketGame } from "./BracketGame";
|
||||
import { SlashGame } from "./SlashGame";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||
import LinearProgress from "@mui/material/LinearProgress";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
const TimerProgress = withStyles(() => ({
|
||||
bar: {
|
||||
|
@ -2,7 +2,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
@ -3,7 +3,7 @@ import { IEngine } from "../../IEngine";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import React, { useState } from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IMinigameProps } from "./IMinigameProps";
|
||||
import { KeyHandler } from "./KeyHandler";
|
||||
import { GameTimer } from "./GameTimer";
|
||||
|
1
src/Message/MessageHelpers.d.ts
vendored
Normal file
1
src/Message/MessageHelpers.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare function showMessage(msg: Message): void;
|
@ -1590,7 +1590,7 @@ HackingMission.prototype.finishMission = function (win) {
|
||||
Mission won! You earned {Reputation(gain)} reputation with {this.faction.name}
|
||||
</>,
|
||||
);
|
||||
Player.gainIntelligenceExp(this.difficulty * CONSTANTS.IntelligenceHackingMissionBaseExpGain);
|
||||
Player.gainIntelligenceExp(Math.pow(this.difficulty * CONSTANTS.IntelligenceHackingMissionBaseExpGain, 0.5));
|
||||
this.faction.playerReputation += gain;
|
||||
} else {
|
||||
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
|
||||
|
@ -145,7 +145,6 @@ import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers"
|
||||
import { Exploit } from "./Exploits/Exploit.ts";
|
||||
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { post } from "./ui/postToTerminal";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
import { is2DArray } from "./utils/helpers/is2DArray";
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
@ -1059,10 +1058,10 @@ function NetscriptFunctions(workerScript) {
|
||||
if (arguments.length === 0) {
|
||||
throw makeRuntimeErrorMsg("tprint", "Takes at least 1 argument.");
|
||||
}
|
||||
post(`${workerScript.scriptRef.filename}: ${argsToString(arguments)}`);
|
||||
Terminal.print(`${workerScript.scriptRef.filename}: ${argsToString(arguments)}`);
|
||||
},
|
||||
tprintf: function (format, ...args) {
|
||||
post(vsprintf(format, args));
|
||||
Terminal.print(vsprintf(format, args));
|
||||
},
|
||||
clearLog: function () {
|
||||
workerScript.scriptRef.clearLog();
|
||||
@ -3134,8 +3133,7 @@ function NetscriptFunctions(workerScript) {
|
||||
Player.getCurrentServer().isConnectedTo = false;
|
||||
Player.currentServer = Player.getHomeComputer().ip;
|
||||
Player.getCurrentServer().isConnectedTo = true;
|
||||
Terminal.currDir = "/";
|
||||
Terminal.resetTerminalInput(true);
|
||||
Terminal.setcwd("/");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3146,8 +3144,7 @@ function NetscriptFunctions(workerScript) {
|
||||
Player.getCurrentServer().isConnectedTo = false;
|
||||
Player.currentServer = target.ip;
|
||||
Player.getCurrentServer().isConnectedTo = true;
|
||||
Terminal.currDir = "/";
|
||||
Terminal.resetTerminalInput(true);
|
||||
Terminal.setcwd("/");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
1
src/NetscriptWorker.d.ts
vendored
Normal file
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;
|
||||
}
|
||||
|
@ -174,11 +174,8 @@ export function prestigeAugmentation() {
|
||||
this.hacknetNodes.length = 0;
|
||||
this.hashManager.prestige();
|
||||
|
||||
// Reset player multipliers
|
||||
this.resetMultipliers();
|
||||
|
||||
// Re-calculate skills and reset HP
|
||||
this.updateSkillLevels();
|
||||
// Reapply augs, re-calculate skills and reset HP
|
||||
this.reapplyAllAugmentations(true);
|
||||
this.hp = this.max_hp;
|
||||
}
|
||||
|
||||
@ -200,12 +197,6 @@ export function prestigeSourceFile() {
|
||||
}
|
||||
}
|
||||
|
||||
const characterMenuHeader = document.getElementById("character-menu-header");
|
||||
if (characterMenuHeader instanceof HTMLElement) {
|
||||
characterMenuHeader.click();
|
||||
characterMenuHeader.click();
|
||||
}
|
||||
|
||||
this.timeWorked = 0;
|
||||
|
||||
// Gang
|
||||
@ -2068,9 +2059,6 @@ export function applyForJob(entryPosType, sing = false) {
|
||||
this.jobs[company.name] = pos.name;
|
||||
this.companyName = this.location;
|
||||
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
|
||||
if (sing) {
|
||||
return true;
|
||||
}
|
||||
@ -2186,8 +2174,6 @@ export function applyForEmployeeJob(sing = false) {
|
||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
||||
this.companyName = company.name;
|
||||
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
if (sing) {
|
||||
return true;
|
||||
}
|
||||
@ -2204,8 +2190,6 @@ export function applyForPartTimeEmployeeJob(sing = false) {
|
||||
var company = Companies[this.location]; //Company being applied to
|
||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
if (sing) {
|
||||
return true;
|
||||
}
|
||||
@ -2223,8 +2207,6 @@ export function applyForWaiterJob(sing = false) {
|
||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
||||
this.companyName = company.name;
|
||||
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
if (sing) {
|
||||
return true;
|
||||
}
|
||||
@ -2242,8 +2224,6 @@ export function applyForPartTimeWaiterJob(sing = false) {
|
||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
||||
this.companyName = company.name;
|
||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
|
||||
document.getElementById("world-menu-header").click();
|
||||
document.getElementById("world-menu-header").click();
|
||||
if (sing) {
|
||||
return true;
|
||||
}
|
||||
@ -2307,6 +2287,8 @@ export function reapplyAllAugmentations(resetMultipliers = true) {
|
||||
}
|
||||
applyAugmentation(this.augmentations[i], true);
|
||||
}
|
||||
|
||||
this.updateSkillLevels();
|
||||
}
|
||||
|
||||
export function reapplyAllSourceFiles() {
|
||||
|
@ -81,7 +81,7 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
||||
if (isNaN(this.state.amt)) {
|
||||
purchaseBtnContent = <>Invalid value</>;
|
||||
} else if (this.state.amt > maxMemory) {
|
||||
purchaseBtnContent = <>Memory cannot exceed 100?</>;
|
||||
purchaseBtnContent = <>Memory cannot exceed 100</>;
|
||||
} else {
|
||||
purchaseBtnContent = (
|
||||
<>
|
||||
|
@ -23,7 +23,7 @@ import { prestigeHomeComputer } from "./Server/ServerHelpers";
|
||||
import { SourceFileFlags, updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SpecialServerIps, prestigeSpecialServerIps, SpecialServerNames } from "./Server/SpecialServerIps";
|
||||
import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Terminal, postVersion } from "./Terminal";
|
||||
import { Terminal } from "./Terminal";
|
||||
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
|
||||
@ -57,21 +57,13 @@ function prestigeAugmentation() {
|
||||
"Fulcrum Secret Technologies",
|
||||
];
|
||||
|
||||
let maintainMembership = Player.factions.filter(function (faction) {
|
||||
const maintainMembership = Player.factions.filter(function (faction) {
|
||||
return megaCorpFactions.includes(faction);
|
||||
});
|
||||
|
||||
Player.prestigeAugmentation();
|
||||
|
||||
Player.factions = Player.factions.concat(maintainMembership);
|
||||
|
||||
// Now actually go to the Terminal Screen (and reset it)
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
Terminal.resetTerminalInput();
|
||||
Terminal.clear();
|
||||
Engine.loadTerminalContent();
|
||||
$("#terminal tr:not(:last)").remove();
|
||||
postVersion();
|
||||
|
||||
// Delete all Worker Scripts objects
|
||||
prestigeWorkerScripts();
|
||||
@ -125,6 +117,9 @@ function prestigeAugmentation() {
|
||||
|
||||
// Re-initialize things - This will update any changes
|
||||
initFactions(); // Factions must be initialized before augmentations
|
||||
|
||||
Player.factions = Player.factions.concat(maintainMembership);
|
||||
Player.factions.map((f) => (Factions[f].isMember = true));
|
||||
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
@ -246,16 +241,12 @@ function prestigeSourceFile(flume) {
|
||||
Player.reapplyAllSourceFiles();
|
||||
initCompanies();
|
||||
|
||||
// Clear terminal
|
||||
$("#terminal tr:not(:last)").remove();
|
||||
postVersion();
|
||||
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
Terminal.resetTerminalInput();
|
||||
Terminal.clear();
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
// BitNode 3: Corporatocracy
|
||||
|
@ -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 --");
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -2,6 +2,9 @@ import React, { useState, useEffect } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
||||
|
||||
import { Box, ButtonGroup, Tooltip, Typography } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
@ -19,34 +22,29 @@ export function ProgramsRoot(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="create-program-page-text">
|
||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
||||
can vary based on how complex the program is. If you are working on creating a program you can cancel at any
|
||||
time. Your progress will be saved and you can continue later.
|
||||
</p>
|
||||
<div>
|
||||
<Box>
|
||||
<Typography>
|
||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
||||
can vary based on how complex the program is. If you are working on creating a program you can cancel at any
|
||||
time. Your progress will be saved and you can continue later.
|
||||
</Typography>
|
||||
</Box>
|
||||
<ButtonGroup>
|
||||
{getAvailableCreatePrograms(props.player).map((program) => {
|
||||
const create = program.create;
|
||||
if (create === null) return <></>;
|
||||
|
||||
<ul id="create-program-list">
|
||||
{getAvailableCreatePrograms(props.player).map((program) => {
|
||||
const create = program.create;
|
||||
if (create === null) return <></>;
|
||||
|
||||
return (
|
||||
<a
|
||||
key={program.name}
|
||||
className="a-link-button tooltip"
|
||||
onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}
|
||||
>
|
||||
{program.name}
|
||||
<span className="tooltiptext">{create.tooltip}</span>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
return (
|
||||
<Tooltip title={create.tooltip}>
|
||||
<Button onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}>
|
||||
{program.name}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
@ -92,13 +92,6 @@ function enterBitNode(flume, destroyedBitNode, newBitNode) {
|
||||
// Set new Bit Node
|
||||
Player.bitNodeN = newBitNode;
|
||||
|
||||
// Reenable terminal
|
||||
$("#hack-progress-bar").attr("id", "old-hack-progress-bar");
|
||||
$("#hack-progress").attr("id", "old-hack-progress");
|
||||
document.getElementById("terminal-input-td").innerHTML =
|
||||
'$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
|
||||
$("input[class=terminal-input]").prop("disabled", false);
|
||||
|
||||
prestigeSourceFile(flume);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { Script } from "./Script";
|
||||
import { FconfSettings } from "../Fconf/FconfSettings";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { IMap } from "../types";
|
||||
import { post } from "../ui/postToTerminal";
|
||||
import { Terminal } from "../Terminal";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
import { getTimestamp } from "../../utils/helpers/getTimestamp";
|
||||
@ -85,7 +85,7 @@ export class RunningScript {
|
||||
|
||||
displayLog(): void {
|
||||
for (let i = 0; i < this.logs.length; ++i) {
|
||||
post(this.logs[i]);
|
||||
Terminal.print(this.logs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
6
src/Script/ScriptHelpers.d.ts
vendored
Normal file
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;
|
||||
|
@ -45,6 +45,11 @@ interface IDefaultSettings {
|
||||
*/
|
||||
MaxPortCapacity: number;
|
||||
|
||||
/**
|
||||
* Limit the number of entries in the terminal.
|
||||
*/
|
||||
MaxTerminalCapacity: number;
|
||||
|
||||
/**
|
||||
* Whether the player should be asked to confirm purchasing each and every augmentation.
|
||||
*/
|
||||
@ -104,6 +109,7 @@ const defaultSettings: IDefaultSettings = {
|
||||
Locale: "en",
|
||||
MaxLogCapacity: 50,
|
||||
MaxPortCapacity: 50,
|
||||
MaxTerminalCapacity: 200,
|
||||
SuppressBuyAugmentationConfirmation: false,
|
||||
SuppressFactionInvites: false,
|
||||
SuppressHospitalizationPopup: false,
|
||||
@ -125,6 +131,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
||||
Locale: "en",
|
||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
||||
MaxPortCapacity: defaultSettings.MaxPortCapacity,
|
||||
MaxTerminalCapacity: defaultSettings.MaxTerminalCapacity,
|
||||
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
|
||||
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
|
||||
|
@ -1,51 +1,48 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import clsx from "clsx";
|
||||
import { createStyles, makeStyles, useTheme, 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 { styled, useTheme, Theme, CSSObject } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import MuiDrawer from "@mui/material/Drawer";
|
||||
import List from "@mui/material/List";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Badge from "@mui/material/Badge";
|
||||
|
||||
import { Theme as BBTheme, colors } from "../../ui/React/Theme";
|
||||
import { TTheme as BBTheme, colors } from "../../ui/React/Theme";
|
||||
|
||||
import ComputerIcon from "@material-ui/icons/Computer";
|
||||
import LastPageIcon from "@material-ui/icons/LastPage"; // Terminal
|
||||
import CreateIcon from "@material-ui/icons/Create"; // Create Script
|
||||
import StorageIcon from "@material-ui/icons/Storage"; // Active Scripts
|
||||
import BugReportIcon from "@material-ui/icons/BugReport"; // Create Program
|
||||
import EqualizerIcon from "@material-ui/icons/Equalizer"; // Stats
|
||||
import ContactsIcon from "@material-ui/icons/Contacts"; // Factions
|
||||
import DoubleArrowIcon from "@material-ui/icons/DoubleArrow"; // Augmentations
|
||||
import AccountTreeIcon from "@material-ui/icons/AccountTree"; // Hacknet
|
||||
import PeopleAltIcon from "@material-ui/icons/PeopleAlt"; // Sleeves
|
||||
import LocationCityIcon from "@material-ui/icons/LocationCity"; // City
|
||||
import AirplanemodeActiveIcon from "@material-ui/icons/AirplanemodeActive"; // Travel
|
||||
import WorkIcon from "@material-ui/icons/Work"; // Job
|
||||
import TrendingUpIcon from "@material-ui/icons/TrendingUp"; // Stock Market
|
||||
import FormatBoldIcon from "@material-ui/icons/FormatBold"; // Bladeburner
|
||||
import BusinessIcon from "@material-ui/icons/Business"; // Corp
|
||||
import SportsMmaIcon from "@material-ui/icons/SportsMma"; // Gang
|
||||
import CheckIcon from "@material-ui/icons/Check"; // Milestones
|
||||
import HelpIcon from "@material-ui/icons/Help"; // Tutorial
|
||||
import SettingsIcon from "@material-ui/icons/Settings"; // options
|
||||
import DeveloperBoardIcon from "@material-ui/icons/DeveloperBoard"; // Dev
|
||||
// import MemoryIcon from "@material-ui/icons/Memory";
|
||||
// import ShareIcon from "@material-ui/icons/Share";
|
||||
import AccountBoxIcon from "@material-ui/icons/AccountBox";
|
||||
import PublicIcon from "@material-ui/icons/Public";
|
||||
import LiveHelpIcon from "@material-ui/icons/LiveHelp";
|
||||
import ExpandLessIcon from "@material-ui/icons/ExpandLess";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import ComputerIcon from "@mui/icons-material/Computer";
|
||||
import LastPageIcon from "@mui/icons-material/LastPage"; // Terminal
|
||||
import CreateIcon from "@mui/icons-material/Create"; // Create Script
|
||||
import StorageIcon from "@mui/icons-material/Storage"; // Active Scripts
|
||||
import BugReportIcon from "@mui/icons-material/BugReport"; // Create Program
|
||||
import EqualizerIcon from "@mui/icons-material/Equalizer"; // Stats
|
||||
import ContactsIcon from "@mui/icons-material/Contacts"; // Factions
|
||||
import DoubleArrowIcon from "@mui/icons-material/DoubleArrow"; // Augmentations
|
||||
import AccountTreeIcon from "@mui/icons-material/AccountTree"; // Hacknet
|
||||
import PeopleAltIcon from "@mui/icons-material/PeopleAlt"; // Sleeves
|
||||
import LocationCityIcon from "@mui/icons-material/LocationCity"; // City
|
||||
import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; // Travel
|
||||
import WorkIcon from "@mui/icons-material/Work"; // Job
|
||||
import TrendingUpIcon from "@mui/icons-material/TrendingUp"; // Stock Market
|
||||
import FormatBoldIcon from "@mui/icons-material/FormatBold"; // Bladeburner
|
||||
import BusinessIcon from "@mui/icons-material/Business"; // Corp
|
||||
import SportsMmaIcon from "@mui/icons-material/SportsMma"; // Gang
|
||||
import CheckIcon from "@mui/icons-material/Check"; // Milestones
|
||||
import HelpIcon from "@mui/icons-material/Help"; // Tutorial
|
||||
import SettingsIcon from "@mui/icons-material/Settings"; // options
|
||||
import DeveloperBoardIcon from "@mui/icons-material/DeveloperBoard"; // Dev
|
||||
import AccountBoxIcon from "@mui/icons-material/AccountBox";
|
||||
import PublicIcon from "@mui/icons-material/Public";
|
||||
import LiveHelpIcon from "@mui/icons-material/LiveHelp";
|
||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
@ -63,31 +60,44 @@ import { Page, routing } from "../../ui/navigationTracking";
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
width: theme.spacing(31),
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
});
|
||||
|
||||
const closedMixin = (theme: Theme): CSSObject => ({
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
width: `calc(${theme.spacing(2)} + 1px)`,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||
},
|
||||
});
|
||||
|
||||
const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({
|
||||
width: theme.spacing(31),
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
boxSizing: "border-box",
|
||||
...(open && {
|
||||
...openedMixin(theme),
|
||||
"& .MuiDrawer-paper": openedMixin(theme),
|
||||
}),
|
||||
...(!open && {
|
||||
...closedMixin(theme),
|
||||
"& .MuiDrawer-paper": closedMixin(theme),
|
||||
}),
|
||||
}));
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
drawer: {
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
drawerOpen: {
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
},
|
||||
drawerClose: {
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
width: theme.spacing(7) + 1,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: theme.spacing(9) + 1,
|
||||
},
|
||||
},
|
||||
active: {
|
||||
borderLeft: "3px solid " + colors.primary,
|
||||
},
|
||||
@ -130,6 +140,8 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
|
||||
const flashTutorial = ITutorial.currStep === iTutorialSteps.WorldDescription;
|
||||
|
||||
const augmentationCount = props.player.queuedAugmentations.length;
|
||||
const invitationsCount = props.player.factionInvitations.length;
|
||||
const programCount = getAvailableCreatePrograms(props.player).length;
|
||||
const canCreateProgram =
|
||||
programCount > 0 ||
|
||||
@ -341,34 +353,24 @@ 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
|
||||
variant="permanent"
|
||||
className={clsx(classes.drawer, {
|
||||
[classes.drawerOpen]: open,
|
||||
[classes.drawerClose]: !open,
|
||||
})}
|
||||
classes={{
|
||||
paper: clsx({
|
||||
[classes.drawerOpen]: open,
|
||||
[classes.drawerClose]: !open,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Drawer open={open} anchor="left" variant="permanent">
|
||||
<ListItem button onClick={toggleDrawer}>
|
||||
<ListItemIcon>{!open ? <ChevronRightIcon /> : <ChevronLeftIcon />}</ListItemIcon>
|
||||
<ListItemIcon>
|
||||
{!open ? <ChevronRightIcon color={"primary"} /> : <ChevronLeftIcon color={"primary"} />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography color="primary">Bitburner v{CONSTANTS.Version}</Typography>} />
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem button onClick={() => setHackingOpen((old) => !old)}>
|
||||
<ListItemIcon>
|
||||
<ComputerIcon />
|
||||
<ComputerIcon color={"primary"} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography color="primary">Hacking</Typography>} />
|
||||
{hackingOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
{hackingOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||
</ListItem>
|
||||
<Collapse in={hackingOpen} timeout="auto" unmountOnExit>
|
||||
<List>
|
||||
@ -435,7 +437,9 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
onClick={clickCreateProgram}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<BugReportIcon color={activeTab !== "CreateProgram" ? "secondary" : "primary"} />
|
||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||
<BugReportIcon color={activeTab !== "CreateProgram" ? "secondary" : "primary"} />
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={activeTab !== "CreateProgram" ? "secondary" : "primary"}>
|
||||
@ -450,10 +454,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
<Divider />
|
||||
<ListItem button onClick={() => setCharacterOpen((old) => !old)}>
|
||||
<ListItemIcon>
|
||||
<AccountBoxIcon />
|
||||
<AccountBoxIcon color={"primary"} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography color="primary">Character</Typography>} />
|
||||
{characterOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
{characterOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||
</ListItem>
|
||||
<Collapse in={characterOpen} timeout="auto" unmountOnExit>
|
||||
<ListItem
|
||||
@ -483,7 +487,9 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
onClick={clickFactions}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ContactsIcon color={activeTab !== "Factions" ? "secondary" : "primary"} />
|
||||
<Badge badgeContent={invitationsCount !== 0 ? invitationsCount : undefined} color="error">
|
||||
<ContactsIcon color={activeTab !== "Factions" ? "secondary" : "primary"} />
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={activeTab !== "Factions" ? "secondary" : "primary"}>Factions</Typography>
|
||||
@ -500,10 +506,12 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
onClick={clickAugmentations}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DoubleArrowIcon
|
||||
style={{ transform: "rotate(-90deg)" }}
|
||||
color={activeTab !== "Augmentations" ? "secondary" : "primary"}
|
||||
/>
|
||||
<Badge badgeContent={augmentationCount !== 0 ? augmentationCount : undefined} color="error">
|
||||
<DoubleArrowIcon
|
||||
style={{ transform: "rotate(-90deg)" }}
|
||||
color={activeTab !== "Augmentations" ? "secondary" : "primary"}
|
||||
/>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={activeTab !== "Augmentations" ? "secondary" : "primary"}>Augmentations</Typography>
|
||||
@ -549,10 +557,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
<Divider />
|
||||
<ListItem button onClick={() => setWorldOpen((old) => !old)}>
|
||||
<ListItemIcon>
|
||||
<PublicIcon />
|
||||
<PublicIcon color={"primary"} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography color="primary">World</Typography>} />
|
||||
{worldOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
{worldOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||
</ListItem>
|
||||
<Collapse in={worldOpen} timeout="auto" unmountOnExit>
|
||||
<ListItem
|
||||
@ -677,10 +685,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
<Divider />
|
||||
<ListItem button onClick={() => setHelpOpen((old) => !old)}>
|
||||
<ListItemIcon>
|
||||
<LiveHelpIcon />
|
||||
<LiveHelpIcon color={"primary"} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={<Typography color="primary">Help</Typography>} />
|
||||
{helpOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
{helpOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||
</ListItem>
|
||||
<Collapse in={helpOpen} timeout="auto" unmountOnExit>
|
||||
<ListItem
|
||||
|
1
src/Terminal.d.ts
vendored
Normal file
1
src/Terminal.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare const Terminal: ITerminal;
|
2610
src/Terminal.jsx
2610
src/Terminal.jsx
File diff suppressed because it is too large
Load Diff
@ -1,282 +1,428 @@
|
||||
/* tslint:disable:max-line-length completed-docs variable-name*/
|
||||
import { IMap } from "../types";
|
||||
|
||||
export const TerminalHelpText: string =
|
||||
"Type 'help name' to learn more about the command 'name'<br><br>" +
|
||||
'alias [-g] [name="value"] Create or display Terminal aliases<br>' +
|
||||
"analyze Get information about the current machine <br>" +
|
||||
"backdoor Install a backdoor on the current machine <br>" +
|
||||
"buy [-l/program] Purchase a program through the Dark Web<br>" +
|
||||
"cat [file] Display a .msg, .lit, or .txt file<br>" +
|
||||
"cd [dir] Change to a new directory<br>" +
|
||||
"check [script] [args...] Print a script's logs to Terminal<br>" +
|
||||
"clear Clear all text on the terminal <br>" +
|
||||
"cls See 'clear' command <br>" +
|
||||
"connect [ip/hostname] Connects to a remote server<br>" +
|
||||
"download [script/text file] Downloads scripts or text files to your computer<br>" +
|
||||
"expr [math expression] Evaluate a mathematical expression<br>" +
|
||||
"free Check the machine's memory (RAM) usage<br>" +
|
||||
"hack Hack the current machine<br>" +
|
||||
"help [command] Display this help text, or the help text for a command<br>" +
|
||||
"home Connect to home computer<br>" +
|
||||
"hostname Displays the hostname of the machine<br>" +
|
||||
"ifconfig Displays the IP address of the machine<br>" +
|
||||
"kill [script/pid] [args...] Stops the specified script on the current server <br>" +
|
||||
"killall Stops all running scripts on the current machine<br>" +
|
||||
"ls [dir] [| grep pattern] Displays all files on the machine<br>" +
|
||||
"lscpu Displays the number of CPU cores on the machine<br>" +
|
||||
"mem [script] [-t] [n] Displays the amount of RAM required to run the script<br>" +
|
||||
"mv [src] [dest] Move/rename a text or script file<br>" +
|
||||
"nano [file] Text editor - Open up and edit a script or text file<br>" +
|
||||
"ps Display all scripts that are currently running<br>" +
|
||||
"rm [file] Delete a file from the server<br>" +
|
||||
"run [name] [-t] [n] [args...] Execute a program or script<br>" +
|
||||
"scan Prints all immediately-available network connections<br>" +
|
||||
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away<br>" +
|
||||
"scp [file] [server] Copies a file to a destination server<br>" +
|
||||
"sudov Shows whether you have root access on this computer<br>" +
|
||||
"tail [script] [args...] Displays dynamic logs for the specified script<br>" +
|
||||
"theme [preset] | bg txt hlgt Change the color scheme of the UI<br>" +
|
||||
"top Displays all running scripts and their RAM usage<br>" +
|
||||
"unalias [alias name] Deletes the specified alias<br>" +
|
||||
"wget [url] [target file] Retrieves code/text from a web server<br>";
|
||||
export const TerminalHelpText: string[] = [
|
||||
"Type 'help name' to learn more about the command ",
|
||||
"",
|
||||
'alias [-g] [name="value"] Create or display Terminal aliases',
|
||||
"analyze Get information about the current machine ",
|
||||
"backdoor Install a backdoor on the current machine ",
|
||||
"buy [-l/program] Purchase a program through the Dark Web",
|
||||
"cat [file] Display a .msg, .lit, or .txt file",
|
||||
"cd [dir] Change to a new directory",
|
||||
"check [script] [args...] Print a script's logs to Terminal",
|
||||
"clear Clear all text on the terminal ",
|
||||
"cls See 'clear' command ",
|
||||
"connect [ip/hostname] Connects to a remote server",
|
||||
"download [script/text file] Downloads scripts or text files to your computer",
|
||||
"expr [math expression] Evaluate a mathematical expression",
|
||||
"free Check the machine's memory (RAM) usage",
|
||||
"hack Hack the current machine",
|
||||
"help [command] Display this help text, or the help text for a command",
|
||||
"home Connect to home computer",
|
||||
"hostname Displays the hostname of the machine",
|
||||
"ifconfig Displays the IP address of the machine",
|
||||
"kill [script/pid] [args...] Stops the specified script on the current server ",
|
||||
"killall Stops all running scripts on the current machine",
|
||||
"ls [dir] [| grep pattern] Displays all files on the machine",
|
||||
"lscpu Displays the number of CPU cores on the machine",
|
||||
"mem [script] [-t] [n] Displays the amount of RAM required to run the script",
|
||||
"mv [src] [dest] Move/rename a text or script file",
|
||||
"nano [file] Text editor - Open up and edit a script or text file",
|
||||
"ps Display all scripts that are currently running",
|
||||
"rm [file] Delete a file from the server",
|
||||
"run [name] [-t] [n] [args...] Execute a program or script",
|
||||
"scan Prints all immediately-available network connections",
|
||||
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
||||
"scp [file] [server] Copies a file to a destination server",
|
||||
"sudov Shows whether you have root access on this computer",
|
||||
"tail [script] [args...] Displays dynamic logs for the specified script",
|
||||
"theme [preset] | bg txt hlgt Change the color scheme of the UI",
|
||||
"top Displays all running scripts and their RAM usage",
|
||||
"unalias [alias name] Deletes the specified alias",
|
||||
"wget [url] [target file] Retrieves code/text from a web server",
|
||||
];
|
||||
|
||||
export const HelpTexts: IMap<string> = {
|
||||
alias:
|
||||
'alias [-g] [name="value"] <br>' +
|
||||
"Create or display aliases. An alias enables a replacement of a word with another string. " +
|
||||
"It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME " +
|
||||
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, " +
|
||||
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: <br><br>" +
|
||||
'alias nuke="run NUKE.exe"<br><br>' +
|
||||
"Then, to run the NUKE.exe program you would just have to enter 'nuke' in Terminal rather than the full command. " +
|
||||
"It is important to note that 'default' aliases will only be substituted for the first word of a Terminal command. For " +
|
||||
"example, if the following alias was set: <br><br>" +
|
||||
'alias worm="HTTPWorm.exe"<br><br>' +
|
||||
"and then you tried to run the following terminal command: <br><br>" +
|
||||
"run worm<br><br>" +
|
||||
"This would fail because the worm alias is not the first word of a Terminal command. To allow an alias to be substituted " +
|
||||
"anywhere in a Terminal command, rather than just the first word, you must set it to be a global alias using the -g flag: <br><br>" +
|
||||
'alias -g worm="HTTPWorm.exe"<br><br>' +
|
||||
"Now, the 'worm' alias will be substituted anytime it shows up as an individual word in a Terminal command. <br><br>" +
|
||||
"Entering just the command 'alias' without any arguments prints the list of all defined aliases in the reusable form " +
|
||||
"'alias NAME=VALUE' on the Terminal. <br><br>" +
|
||||
"The 'unalias' command can be used to remove aliases.<br><br>",
|
||||
analyze:
|
||||
"analze<br>" +
|
||||
"Prints details and statistics about the current server. The information that is printed includes basic " +
|
||||
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also " +
|
||||
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is " +
|
||||
export const HelpTexts: IMap<string[]> = {
|
||||
alias: [
|
||||
'alias [-g] [name="value"] ',
|
||||
" ",
|
||||
"Create or display aliases. An alias enables a replacement of a word with another string. ",
|
||||
"It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME ",
|
||||
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, ",
|
||||
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: ",
|
||||
" ",
|
||||
'alias nuke="run NUKE.exe"',
|
||||
" ",
|
||||
"Then, to run the NUKE.exe program you would just have to enter 'nuke' in Terminal rather than the full command. ",
|
||||
"It is important to note that 'default' aliases will only be substituted for the first word of a Terminal command. For ",
|
||||
"example, if the following alias was set: ",
|
||||
" ",
|
||||
'alias worm="HTTPWorm.exe"',
|
||||
" ",
|
||||
"and then you tried to run the following terminal command: ",
|
||||
" ",
|
||||
"run worm",
|
||||
" ",
|
||||
"This would fail because the worm alias is not the first word of a Terminal command. To allow an alias to be substituted ",
|
||||
"anywhere in a Terminal command, rather than just the first word, you must set it to be a global alias using the -g flag: ",
|
||||
" ",
|
||||
'alias -g worm="HTTPWorm.exe"',
|
||||
" ",
|
||||
"Now, the 'worm' alias will be substituted anytime it shows up as an individual word in a Terminal command. ",
|
||||
" ",
|
||||
"Entering just the command 'alias' without any arguments prints the list of all defined aliases in the reusable form ",
|
||||
"'alias NAME=VALUE' on the Terminal. ",
|
||||
" ",
|
||||
"The 'unalias' command can be used to remove aliases.",
|
||||
" ",
|
||||
],
|
||||
analyze: [
|
||||
"analze",
|
||||
" ",
|
||||
"Prints details and statistics about the current server. The information that is printed includes basic ",
|
||||
"server details such as the hostname, whether the player has root access, what ports are opened/closed, and also ",
|
||||
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is ",
|
||||
"available on the server, etc.",
|
||||
backdoor:
|
||||
"backdoor<br>" +
|
||||
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.<br>" +
|
||||
"Requires root access to run.<br>",
|
||||
buy:
|
||||
"buy [-l / program]<br>" +
|
||||
"Purchase a program through the Dark Web. Requires a TOR router to use.<br><br>" +
|
||||
"If this command is ran with the '-l' flag, it will display a list of all programs that can be bought through the " +
|
||||
"dark web to the Terminal, as well as their costs.<br><br>" +
|
||||
],
|
||||
backdoor: [
|
||||
"backdoor",
|
||||
" ",
|
||||
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.",
|
||||
" ",
|
||||
"Requires root access to run.",
|
||||
" ",
|
||||
],
|
||||
buy: [
|
||||
"buy [-l / program]",
|
||||
" ",
|
||||
"Purchase a program through the Dark Web. Requires a TOR router to use.",
|
||||
" ",
|
||||
"If this command is ran with the '-l' flag, it will display a list of all programs that can be bought through the ",
|
||||
"dark web to the Terminal, as well as their costs.",
|
||||
" ",
|
||||
"Otherwise, the name of the program must be passed in as a parameter. This name is NOT case-sensitive.",
|
||||
cat:
|
||||
"cat [file]<br>" +
|
||||
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:<br><br>" +
|
||||
"cat j1.msg<br>" +
|
||||
"cat foo.lit<br>" +
|
||||
],
|
||||
cat: [
|
||||
"cat [file]",
|
||||
" ",
|
||||
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:",
|
||||
" ",
|
||||
"cat j1.msg",
|
||||
" ",
|
||||
"cat foo.lit",
|
||||
" ",
|
||||
"cat servers.txt",
|
||||
cd:
|
||||
"cd [dir]<br>" +
|
||||
"Change to the specified directory. Note that this works even for directories that don't exist. If you " +
|
||||
"change to a directory that does not exist, it will not be 'created'. Examples:<br><br>" +
|
||||
"cd scripts/hacking<br>" +
|
||||
"cd /logs<br>" +
|
||||
],
|
||||
cd: [
|
||||
"cd [dir]",
|
||||
" ",
|
||||
"Change to the specified directory. Note that this works even for directories that don't exist. If you ",
|
||||
"change to a directory that does not exist, it will not be 'created'. Examples:",
|
||||
" ",
|
||||
"cd scripts/hacking",
|
||||
" ",
|
||||
"cd /logs",
|
||||
" ",
|
||||
"cd ../",
|
||||
check:
|
||||
"check [script name] [args...]<br>" +
|
||||
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by " +
|
||||
"a space. Remember that a running script is uniquely " +
|
||||
"identified both by its name and the arguments that are used to start it. So, if a script was ran with the following arguments: <br><br>" +
|
||||
"run foo.script 1 2 foodnstuff<br><br>" +
|
||||
"Then to run the 'check' command on this script you would have to pass the same arguments in: <br><br>" +
|
||||
],
|
||||
check: [
|
||||
"check [script name] [args...]",
|
||||
" ",
|
||||
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by ",
|
||||
"a space. Remember that a running script is uniquely ",
|
||||
"identified both by its name and the arguments that are used to start it. So, if a script was ran with the following arguments: ",
|
||||
" ",
|
||||
"run foo.script 1 2 foodnstuff",
|
||||
" ",
|
||||
"Then to run the 'check' command on this script you would have to pass the same arguments in: ",
|
||||
" ",
|
||||
"check foo.script 1 2 foodnstuff",
|
||||
clear:
|
||||
"clear<br>" +
|
||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up " +
|
||||
],
|
||||
clear: [
|
||||
"clear",
|
||||
" ",
|
||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'cls' command",
|
||||
cls:
|
||||
"cls<br>" +
|
||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up " +
|
||||
],
|
||||
cls: [
|
||||
"cls",
|
||||
" ",
|
||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'clear' command",
|
||||
connect:
|
||||
"connect [hostname/ip]<br>" +
|
||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument " +
|
||||
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To " +
|
||||
],
|
||||
connect: [
|
||||
"connect [hostname/ip]",
|
||||
" ",
|
||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument ",
|
||||
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To ",
|
||||
"see which servers can be connected to, use the 'scan' command.",
|
||||
download:
|
||||
"download [script/text file]<br>" +
|
||||
"Downloads a script or text file to your computer (like your real life computer).<br>" +
|
||||
"You can also download all of your scripts/text files as a zip file using the following Terminal commands:<br><br>" +
|
||||
"Download all scripts and text files: download *<br>" +
|
||||
"Download all scripts: download *.script<br>" +
|
||||
"Download all text files: download *.txt<br>",
|
||||
expr:
|
||||
"expr [mathematical expression]<br>" +
|
||||
"Evaluate a simple mathematical expression. Supports native JavaScript operators:<br>" +
|
||||
"+, -, /, *, **, %<br>" +
|
||||
"Example:<br>" +
|
||||
"expr 25 * 2 ** 10<br>" +
|
||||
],
|
||||
download: [
|
||||
"download [script/text file]",
|
||||
" ",
|
||||
"Downloads a script or text file to your computer (like your real life computer).",
|
||||
" ",
|
||||
"You can also download all of your scripts/text files as a zip file using the following Terminal commands:",
|
||||
" ",
|
||||
"Download all scripts and text files: download *",
|
||||
" ",
|
||||
"Download all scripts: download *.script",
|
||||
" ",
|
||||
"Download all text files: download *.txt",
|
||||
" ",
|
||||
],
|
||||
expr: [
|
||||
"expr [mathematical expression]",
|
||||
" ",
|
||||
"Evaluate a simple mathematical expression. Supports native JavaScript operators:",
|
||||
" ",
|
||||
"+, -, /, *, **, %",
|
||||
" ",
|
||||
"Example:",
|
||||
" ",
|
||||
"expr 25 * 2 ** 10",
|
||||
" ",
|
||||
"Note that letters (non-digits) are not allowed and will be removed from the input.",
|
||||
free:
|
||||
"free<br>" +
|
||||
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as " +
|
||||
],
|
||||
free: [
|
||||
"free",
|
||||
" ",
|
||||
"Display's the memory usage on the current machine. Print the amount of RAM that is available on the current server as well as ",
|
||||
"how much of it is being used.",
|
||||
hack:
|
||||
"hack<br>" +
|
||||
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics<br>",
|
||||
help:
|
||||
"help [command]<br>" +
|
||||
"Display Terminal help information. Without arguments, 'help' prints a list of all valid Terminal commands and a brief " +
|
||||
"description of their functionality. You can also pass the name of a Terminal command as an argument to 'help' to print " +
|
||||
"more detailed information about the Terminal command. Examples: <br><br>" +
|
||||
"help alias<br>" +
|
||||
],
|
||||
hack: [
|
||||
"hack",
|
||||
" ",
|
||||
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics",
|
||||
" ",
|
||||
],
|
||||
help: [
|
||||
"help [command]",
|
||||
" ",
|
||||
"Display Terminal help information. Without arguments, 'help' prints a list of all valid Terminal commands and a brief ",
|
||||
"description of their functionality. You can also pass the name of a Terminal command as an argument to 'help' to print ",
|
||||
"more detailed information about the Terminal command. Examples: ",
|
||||
" ",
|
||||
"help alias",
|
||||
" ",
|
||||
"help scan-analyze",
|
||||
home:
|
||||
"home<br>" + "Connect to your home computer. This will work no matter what server you are currently connected to.",
|
||||
hostname: "hostname<br>" + "Prints the hostname of the current server",
|
||||
ifconfig: "ipconfig<br>" + "Prints the IP address of the current server",
|
||||
kill:
|
||||
"kill [script name] [args...]<br>" +
|
||||
"kill [pid]<br>" +
|
||||
"Kill the script specified by the script name and arguments OR by its PID.<br><br>" +
|
||||
"If you are killing the script using its filename and arguments, then each " +
|
||||
"argument must be separated by a space. Remember that a running script is " +
|
||||
"uniquely identified by both its name and the arguments that are used to start " +
|
||||
"it. So, if a script was ran with the following arguments:<br><br>" +
|
||||
"run foo.script 1 sigma-cosmetics<br><br>" +
|
||||
"Then to kill this script the same arguments would have to be used:<br><br>" +
|
||||
"kill foo.script 1 sigma-cosmetics<br><br>" +
|
||||
],
|
||||
home: [
|
||||
"home" + "Connect to your home computer. This will work no matter what server you are currently connected to.",
|
||||
],
|
||||
hostname: ["hostname", " ", "Prints the hostname of the current server"],
|
||||
ifconfig: ["ipconfig", " ", "Prints the IP address of the current server"],
|
||||
kill: [
|
||||
"kill [script name] [args...]",
|
||||
" ",
|
||||
"kill [pid]",
|
||||
" ",
|
||||
"Kill the script specified by the script name and arguments OR by its PID.",
|
||||
" ",
|
||||
"If you are killing the script using its filename and arguments, then each ",
|
||||
"argument must be separated by a space. Remember that a running script is ",
|
||||
"uniquely identified by both its name and the arguments that are used to start ",
|
||||
"it. So, if a script was ran with the following arguments:",
|
||||
" ",
|
||||
"run foo.script 1 sigma-cosmetics",
|
||||
" ",
|
||||
"Then to kill this script the same arguments would have to be used:",
|
||||
" ",
|
||||
"kill foo.script 1 sigma-cosmetics",
|
||||
" ",
|
||||
"If you are killing the script using its PID, then the PID argument must be numeric",
|
||||
killall:
|
||||
"killall<br>" +
|
||||
"Kills all scripts on the current server. " +
|
||||
"Note that after the 'kill' command is issued for a script, it may take a while for the script to actually stop running. " +
|
||||
"This will happen if the script is in the middle of a command such as grow() or weaken() that takes time to execute. " +
|
||||
],
|
||||
killall: [
|
||||
"killall",
|
||||
" ",
|
||||
"Kills all scripts on the current server. ",
|
||||
"Note that after the 'kill' command is issued for a script, it may take a while for the script to actually stop running. ",
|
||||
"This will happen if the script is in the middle of a command such as grow() or weaken() that takes time to execute. ",
|
||||
"The script will not be stopped/killed until after that time has elapsed.",
|
||||
ls:
|
||||
"ls [dir] [| grep pattern]<br>" +
|
||||
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. " +
|
||||
"The files will be displayed in alphabetical order. <br><br>" +
|
||||
"The 'dir' optional parameter can be used to display files/directories in another directory.<br><br>" +
|
||||
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern.<br><br>" +
|
||||
"Examples:<br><br>" +
|
||||
"List all files with the '.script' extension in the current directory:<br>" +
|
||||
"ls | grep .script<br><br>" +
|
||||
"List all files with the '.js' extension in the root directory:<br>" +
|
||||
"ls / | grep .js<br><br>" +
|
||||
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:<br>" +
|
||||
],
|
||||
ls: [
|
||||
"ls [dir] [| grep pattern]",
|
||||
" ",
|
||||
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. ",
|
||||
"The files will be displayed in alphabetical order. ",
|
||||
" ",
|
||||
"The 'dir' optional parameter can be used to display files/directories in another directory.",
|
||||
" ",
|
||||
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern.",
|
||||
" ",
|
||||
"Examples:",
|
||||
" ",
|
||||
"List all files with the '.script' extension in the current directory:",
|
||||
" ",
|
||||
"ls | grep .script",
|
||||
" ",
|
||||
"List all files with the '.js' extension in the root directory:",
|
||||
" ",
|
||||
"ls / | grep .js",
|
||||
" ",
|
||||
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:",
|
||||
" ",
|
||||
"ls scripts | grep purchase",
|
||||
lscpu: "lscpu<br>" + "Prints the number of CPU Cores the current server has",
|
||||
mem:
|
||||
"mem [script name] [-t] [num threads]<br>" +
|
||||
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print " +
|
||||
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then " +
|
||||
"an argument for the number of threads must be passed in afterwards. Examples:<br><br>" +
|
||||
"mem foo.script<br>" +
|
||||
"mem foo.script -t 50<br>" +
|
||||
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example " +
|
||||
],
|
||||
lscpu: ["lscpu", " ", "Prints the number of CPU Cores the current server has"],
|
||||
|
||||
mem: [
|
||||
"mem [script name] [-t] [num threads]",
|
||||
" ",
|
||||
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
||||
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
||||
"an argument for the number of threads must be passed in afterwards. Examples:",
|
||||
" ",
|
||||
"mem foo.script",
|
||||
" ",
|
||||
"mem foo.script -t 50",
|
||||
" ",
|
||||
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example ",
|
||||
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
|
||||
mv:
|
||||
"mv [src] [dest]<br>" +
|
||||
"Move the source file to the specified destination. This can also be used to rename files. " +
|
||||
"This command only works for scripts and text files (.txt). This command CANNOT be used to " +
|
||||
"convert to different file types<br><br>" +
|
||||
"Note that, unlike the Linux 'mv' command, the destination argument must be the " +
|
||||
"full filepath. " +
|
||||
"Examples: <br><br>" +
|
||||
"mv hacking-controller.script scripts/hacking-controller.script<br>" +
|
||||
],
|
||||
mv: [
|
||||
"mv [src] [dest]",
|
||||
" ",
|
||||
"Move the source file to the specified destination. This can also be used to rename files. ",
|
||||
"This command only works for scripts and text files (.txt). This command CANNOT be used to ",
|
||||
"convert to different file types",
|
||||
" ",
|
||||
"Note that, unlike the Linux 'mv' command, the destination argument must be the ",
|
||||
"full filepath. ",
|
||||
"Examples: ",
|
||||
" ",
|
||||
"mv hacking-controller.script scripts/hacking-controller.script",
|
||||
" ",
|
||||
"mv myScript.js myOldScript.js",
|
||||
nano:
|
||||
"nano [file name]<br>" +
|
||||
"Opens up the specified file in the Text Editor. Only scripts (.script) or text files (.txt) can be " +
|
||||
"edited using the Text Editor. If the file does not already exist, then a new, empty one " +
|
||||
],
|
||||
nano: [
|
||||
"nano [file name]",
|
||||
" ",
|
||||
"Opens up the specified file in the Text Editor. Only scripts (.script) or text files (.txt) can be ",
|
||||
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
|
||||
"will be created",
|
||||
ps: "ps<br>" + "Prints all scripts that are running on the current server",
|
||||
rm:
|
||||
"rm [file]<br>" +
|
||||
"Removes the specified file from the current server. A file can be a script, a program, or a message file. <br><br>" +
|
||||
],
|
||||
ps: ["ps", " ", "Prints all scripts that are running on the current server"],
|
||||
|
||||
rm: [
|
||||
"rm [file]",
|
||||
" ",
|
||||
"Removes the specified file from the current server. A file can be a script, a program, or a message file. ",
|
||||
" ",
|
||||
"WARNING: This is permanent and cannot be undone",
|
||||
run:
|
||||
"run [file name] [-t] [num threads] [args...]<br>" +
|
||||
"Execute a program or a script.<br><br>" +
|
||||
"The '[-t]', '[num threads]', and '[args...]' arguments are only valid when running a script. The '-t' flag is used " +
|
||||
"to indicate that the script should be run with the specified number of threads. If the flag is omitted, " +
|
||||
"then the script will be run with a single thread by default. " +
|
||||
"If the '-t' flag is used, then it MUST come immediately " +
|
||||
"after the script name, and the [num threads] argument MUST come immediately afterwards. <br><br>" +
|
||||
"[args...] represents a variable number of arguments that will be passed into the script. See the documentation " +
|
||||
"about script arguments. Each specified argument must be separated by a space. <br><br>",
|
||||
scan:
|
||||
"scan<br>" +
|
||||
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect " +
|
||||
],
|
||||
run: [
|
||||
"run [file name] [-t] [num threads] [args...]",
|
||||
" ",
|
||||
"Execute a program or a script.",
|
||||
" ",
|
||||
"The '[-t]', '[num threads]', and '[args...]' arguments are only valid when running a script. The '-t' flag is used ",
|
||||
"to indicate that the script should be run with the specified number of threads. If the flag is omitted, ",
|
||||
"then the script will be run with a single thread by default. ",
|
||||
"If the '-t' flag is used, then it MUST come immediately ",
|
||||
"after the script name, and the [num threads] argument MUST come immediately afterwards. ",
|
||||
" ",
|
||||
"[args...] represents a variable number of arguments that will be passed into the script. See the documentation ",
|
||||
"about script arguments. Each specified argument must be separated by a space. ",
|
||||
" ",
|
||||
],
|
||||
scan: [
|
||||
"scan",
|
||||
" ",
|
||||
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect ",
|
||||
"to using the 'connect' Terminal command.",
|
||||
"scan-analyze":
|
||||
"scan-analyze [depth] [-a]<br>" +
|
||||
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling " +
|
||||
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal " +
|
||||
"command. This command also shows the relative paths to reach each server.<br><br>" +
|
||||
"By default, the maximum depth that can be specified for 'scan-analyze' is 3. However, once you have " +
|
||||
"the DeepscanV1.exe and DeepscanV2.exe programs, you can execute 'scan-analyze' with a depth up to " +
|
||||
"5 and 10, respectively.<br><br>" +
|
||||
"The information 'scan-analyze' displays about each server includes whether or not you have root access to it, " +
|
||||
"its required hacking level, the number of open ports required to run NUKE.exe on it, and how much RAM " +
|
||||
"it has.<br><br>" +
|
||||
"By default, this command will not display servers that you have purchased. However, you can pass in the " +
|
||||
],
|
||||
"scan-analyze": [
|
||||
"scan-analyze [depth] [-a]",
|
||||
" ",
|
||||
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling ",
|
||||
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal ",
|
||||
"command. This command also shows the relative paths to reach each server.",
|
||||
" ",
|
||||
"By default, the maximum depth that can be specified for 'scan-analyze' is 3. However, once you have ",
|
||||
"the DeepscanV1.exe and DeepscanV2.exe programs, you can execute 'scan-analyze' with a depth up to ",
|
||||
"5 and 10, respectively.",
|
||||
" ",
|
||||
"The information 'scan-analyze' displays about each server includes whether or not you have root access to it, ",
|
||||
"its required hacking level, the number of open ports required to run NUKE.exe on it, and how much RAM ",
|
||||
"it has.",
|
||||
" ",
|
||||
"By default, this command will not display servers that you have purchased. However, you can pass in the ",
|
||||
"-a flag at the end of the command if you would like to enable that.",
|
||||
scp:
|
||||
"scp [filename] [target server]<br>" +
|
||||
"Copies the specified file from the current server to the target server. " +
|
||||
"This command only works for script files (.script extension), literature files (.lit extension), " +
|
||||
"and text files (.txt extension). " +
|
||||
],
|
||||
scp: [
|
||||
"scp [filename] [target server]",
|
||||
" ",
|
||||
"Copies the specified file from the current server to the target server. ",
|
||||
"This command only works for script files (.script extension), literature files (.lit extension), ",
|
||||
"and text files (.txt extension). ",
|
||||
"The second argument passed in must be the hostname or IP of the target server.",
|
||||
sudov: "sudov<br>" + "Prints whether or not you have root access to the current machine",
|
||||
tail:
|
||||
"tail [script name] [args...]<br>" +
|
||||
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated " +
|
||||
"by a space. Remember that a running script is uniquely identified by both its name and the arguments that were used " +
|
||||
"to run it. So, if a script was ran with the following arguments: <br><br>" +
|
||||
"run foo.script 10 50000<br><br>" +
|
||||
"Then in order to check its logs with 'tail' the same arguments must be used: <br><br>" +
|
||||
],
|
||||
sudov: ["sudov", " ", "Prints whether or not you have root access to the current machine"],
|
||||
|
||||
tail: [
|
||||
"tail [script name] [args...]",
|
||||
" ",
|
||||
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated ",
|
||||
"by a space. Remember that a running script is uniquely identified by both its name and the arguments that were used ",
|
||||
"to run it. So, if a script was ran with the following arguments: ",
|
||||
" ",
|
||||
"run foo.script 10 50000",
|
||||
" ",
|
||||
"Then in order to check its logs with 'tail' the same arguments must be used: ",
|
||||
" ",
|
||||
"tail foo.script 10 50000",
|
||||
theme:
|
||||
"theme [preset] | [#background #text #highlight]<br>" +
|
||||
"Change the color of the game's user interface<br><br>" +
|
||||
"This command can be called with a preset theme. Currently, the supported presets are 'default', 'muted', and 'solarized'. " +
|
||||
"However, you can also specify your own color scheme using hex values. To do so, you must specify three hex color values " +
|
||||
"for the background color, the text color, and the highlight color. These hex values must be preceded by a pound sign (#) and " +
|
||||
"must be either 3 or 6 digits. Example:<br><br>" +
|
||||
"theme #ffffff #385 #235012<br><br>" +
|
||||
"A color picker such as " +
|
||||
"<a href='https://www.google.com/search?q=color+picker&oq=color+picker&aqs=chrome.0.0l6.951j0j1&sourceid=chrome&ie=UTF-8' target='_blank'>Google's</a> " +
|
||||
"can be used to get your desired hex color values<br><br>" +
|
||||
],
|
||||
theme: [
|
||||
"theme [preset] | [#background #text #highlight]",
|
||||
" ",
|
||||
"Change the color of the game's user interface",
|
||||
" ",
|
||||
"This command can be called with a preset theme. Currently, the supported presets are 'default', 'muted', and 'solarized'. ",
|
||||
"However, you can also specify your own color scheme using hex values. To do so, you must specify three hex color values ",
|
||||
"for the background color, the text color, and the highlight color. These hex values must be preceded by a pound sign (#) and ",
|
||||
"must be either 3 or 6 digits. Example:",
|
||||
" ",
|
||||
"theme #ffffff #385 #235012",
|
||||
" ",
|
||||
"A color picker such as ",
|
||||
"<a href='https://www.google.com/search?q=color+picker&oq=color+picker&aqs=chrome.0.0l6.951j0j1&sourceid=chrome&ie=UTF-8' target='_blank'>Google's</a> ",
|
||||
"can be used to get your desired hex color values",
|
||||
" ",
|
||||
"Themes are not saved, so when the game is closed and then re-opened or reloaded then it will revert back to the default theme.",
|
||||
top:
|
||||
"top<br>" +
|
||||
"Prints a list of all scripts running on the current server as well as their thread count and how much " +
|
||||
],
|
||||
top: [
|
||||
"top",
|
||||
" ",
|
||||
"Prints a list of all scripts running on the current server as well as their thread count and how much ",
|
||||
"RAM they are using in total.",
|
||||
unalias:
|
||||
"unalias [alias name]<br>" +
|
||||
"Deletes the specified alias. Note that the double quotation marks are required. <br><br>" +
|
||||
"As an example, if an alias was declared using:<br><br>" +
|
||||
'alias r="run"<br><br>' +
|
||||
"Then it could be removed using:<br><br>" +
|
||||
"unalias r<br><br>" +
|
||||
],
|
||||
unalias: [
|
||||
"unalias [alias name]",
|
||||
" ",
|
||||
"Deletes the specified alias. Note that the double quotation marks are required. ",
|
||||
" ",
|
||||
"As an example, if an alias was declared using:",
|
||||
" ",
|
||||
'alias r="run"',
|
||||
" ",
|
||||
"Then it could be removed using:",
|
||||
" ",
|
||||
"unalias r",
|
||||
" ",
|
||||
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
||||
wget:
|
||||
"wget [url] [target file]<br>" +
|
||||
"Retrieves data from a URL and downloads it to a file on the current server. The data can only " +
|
||||
"be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, " +
|
||||
"it will be overwritten by this command.<br><br>" +
|
||||
"Note that it will not be possible to download data from many websites because they do not allow " +
|
||||
"cross-origin resource sharing (CORS). Example:<br><br>" +
|
||||
],
|
||||
wget: [
|
||||
"wget [url] [target file]",
|
||||
" ",
|
||||
"Retrieves data from a URL and downloads it to a file on the current server. The data can only ",
|
||||
"be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, ",
|
||||
"it will be overwritten by this command.",
|
||||
" ",
|
||||
"Note that it will not be possible to download data from many websites because they do not allow ",
|
||||
"cross-origin resource sharing (CORS). Example:",
|
||||
" ",
|
||||
"wget https://raw.githubusercontent.com/danielyxie/bitburner/master/README.md game_readme.txt",
|
||||
],
|
||||
};
|
||||
|
80
src/Terminal/ITerminal.ts
Normal file
80
src/Terminal/ITerminal.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { TextFile } from "../TextFile";
|
||||
import { Script } from "../Script/Script";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../IEngine";
|
||||
|
||||
export class Output {
|
||||
text: string;
|
||||
color: "inherit" | "initial" | "primary" | "secondary" | "error" | "textPrimary" | "textSecondary" | undefined;
|
||||
constructor(
|
||||
text: string,
|
||||
color: "inherit" | "initial" | "primary" | "secondary" | "error" | "textPrimary" | "textSecondary" | undefined,
|
||||
) {
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
export class Link {
|
||||
hostname: string;
|
||||
constructor(hostname: string) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
}
|
||||
|
||||
export class TTimer {
|
||||
time: number;
|
||||
timeLeft: number;
|
||||
action: "h" | "b" | "a";
|
||||
|
||||
constructor(time: number, action: "h" | "b" | "a") {
|
||||
this.time = time;
|
||||
this.timeLeft = time;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITerminal {
|
||||
action: TTimer | null;
|
||||
|
||||
commandHistory: string[];
|
||||
commandHistoryIndex: number;
|
||||
|
||||
outputHistory: (Output | Link)[];
|
||||
|
||||
// True if a Coding Contract prompt is opened
|
||||
contractOpen: boolean;
|
||||
|
||||
// Full Path of current directory
|
||||
// Excludes the trailing forward slash
|
||||
currDir: string;
|
||||
|
||||
print(s: string): void;
|
||||
error(s: string): void;
|
||||
|
||||
clear(): 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;
|
||||
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;
|
||||
// If there was any changes, will return true, once.
|
||||
pollChanges(): boolean;
|
||||
process(player: IPlayer, cycles: number): void;
|
||||
prestige(): void;
|
||||
getProgressText(): string;
|
||||
}
|
127
src/Terminal/Parser.ts
Normal file
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;
|
||||
}
|
726
src/Terminal/Terminal.ts
Normal file
726
src/Terminal/Terminal.ts
Normal file
@ -0,0 +1,726 @@
|
||||
import { ITerminal, Output, Link, TTimer } 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 { 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 { Settings } from "../Settings/Settings";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
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";
|
||||
|
||||
export class Terminal implements ITerminal {
|
||||
hasChanges = false;
|
||||
// Flags to determine whether the player is currently running a hack or an analyze
|
||||
action: TTimer | null = null;
|
||||
|
||||
commandHistory: string[] = [];
|
||||
commandHistoryIndex = 0;
|
||||
|
||||
outputHistory: (Output | Link)[] = [new Output(`Bitburner v${CONSTANTS.Version}`, "primary")];
|
||||
|
||||
// True if a Coding Contract prompt is opened
|
||||
contractOpen = false;
|
||||
|
||||
// Full Path of current directory
|
||||
// Excludes the trailing forward slash
|
||||
currDir = "/";
|
||||
|
||||
process(player: IPlayer, cycles: number): void {
|
||||
if (this.action === null) return;
|
||||
this.action.timeLeft -= (CONSTANTS._idleSpeed * cycles) / 1000;
|
||||
this.hasChanges = true;
|
||||
if (this.action.timeLeft < 0) this.finishAction(player, false);
|
||||
}
|
||||
|
||||
pollChanges(): boolean {
|
||||
if (this.hasChanges) {
|
||||
this.hasChanges = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
append(item: Output | Link): void {
|
||||
this.outputHistory.push(item);
|
||||
if (this.outputHistory.length > Settings.MaxTerminalCapacity) {
|
||||
this.outputHistory.slice(this.outputHistory.length - Settings.MaxTerminalCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
print(s: string): void {
|
||||
this.append(new Output(s, "primary"));
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
error(s: string): void {
|
||||
this.append(new Output(s, "error"));
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
startHack(player: IPlayer): void {
|
||||
// Hacking through Terminal should be faster than hacking through a script
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "h");
|
||||
}
|
||||
|
||||
startBackdoor(player: IPlayer): void {
|
||||
// Backdoor should take the same amount of time as hack
|
||||
this.startAction(calculateHackingTime(player.getCurrentServer(), player) / 4, "b");
|
||||
}
|
||||
|
||||
startAnalyze(): void {
|
||||
this.print("Analyzing system...");
|
||||
this.startAction(1, "a");
|
||||
}
|
||||
|
||||
startAction(n: number, action: "h" | "b" | "a"): void {
|
||||
this.action = new TTimer(n, action);
|
||||
}
|
||||
|
||||
// Complete the hack/analyze command
|
||||
finishHack(player: IPlayer, cancelled = false): void {
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
|
||||
// Calculate whether hack was successful
|
||||
const hackChance = calculateHackingChance(server, player);
|
||||
const rand = Math.random();
|
||||
const expGainedOnSuccess = calculateHackingExpGain(server, player);
|
||||
const expGainedOnFailure = expGainedOnSuccess / 4;
|
||||
if (rand < hackChance) {
|
||||
// Success!
|
||||
if (
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] &&
|
||||
SpecialServerIps[SpecialServerNames.WorldDaemon] == server.ip
|
||||
) {
|
||||
if (player.bitNodeN == null) {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
this.print("Backdoor successful!");
|
||||
}
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
finishAction(player: IPlayer, cancelled = false): void {
|
||||
if (this.action === null) {
|
||||
if (!cancelled) throw new Error("Finish action called when there was no action");
|
||||
return;
|
||||
}
|
||||
this.print(this.getProgressText());
|
||||
if (this.action.action === "h") {
|
||||
this.finishHack(player, cancelled);
|
||||
} else if (this.action.action === "b") {
|
||||
this.finishBackdoor(player, cancelled);
|
||||
} else if (this.action.action === "a") {
|
||||
this.finishAnalyze(player, cancelled);
|
||||
}
|
||||
if (cancelled) {
|
||||
this.print("Cancelled");
|
||||
}
|
||||
this.action = null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cwd(): string {
|
||||
return this.currDir;
|
||||
}
|
||||
|
||||
setcwd(dir: string): void {
|
||||
this.currDir = dir;
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
async runContract(player: IPlayer, contractName: string): Promise<void> {
|
||||
// There's already an opened contract
|
||||
if (this.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");
|
||||
}
|
||||
|
||||
this.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;
|
||||
}
|
||||
this.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.append(new Link(s.hostname));
|
||||
} else {
|
||||
this.print(s.hostname);
|
||||
}
|
||||
|
||||
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 (this.action !== null) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 (this.commandHistory[this.commandHistory.length - 1] != commands) {
|
||||
this.commandHistory.push(commands);
|
||||
if (this.commandHistory.length > 50) {
|
||||
this.commandHistory.splice(0, 1);
|
||||
}
|
||||
}
|
||||
this.commandHistoryIndex = this.commandHistory.length;
|
||||
const allCommands = ParseCommands(commands);
|
||||
|
||||
for (let i = 0; i < allCommands.length; i++) {
|
||||
this.executeCommand(engine, player, allCommands[i]);
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
// TODO: remove this once we figure out the height issue.
|
||||
this.outputHistory = [new Output(`Bitburner v${CONSTANTS.Version}`, "primary")];
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
prestige(): void {
|
||||
this.action = null;
|
||||
this.clear();
|
||||
}
|
||||
|
||||
executeCommand(engine: IEngine, player: IPlayer, command: string): void {
|
||||
if (this.action !== null) {
|
||||
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") {
|
||||
TerminalHelpText.forEach((line) => this.print(line));
|
||||
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: () => this.clear(),
|
||||
clear: () => this.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));
|
||||
}
|
||||
|
||||
getProgressText(): string {
|
||||
if (this.action === null) throw new Error("trying to get the progress text when there's no action");
|
||||
return createProgressBarText({
|
||||
progress: (this.action.time - this.action.timeLeft) / this.action.time,
|
||||
totalTicks: 50,
|
||||
});
|
||||
}
|
||||
}
|
33
src/Terminal/commands/alias.ts
Normal file
33
src/Terminal/commands/alias.ts
Normal file
@ -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"]');
|
||||
}
|
18
src/Terminal/commands/analyze.ts
Normal file
18
src/Terminal/commands/analyze.ts
Normal file
@ -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();
|
||||
}
|
41
src/Terminal/commands/backdoor.ts
Normal file
41
src/Terminal/commands/backdoor.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
33
src/Terminal/commands/buy.ts
Normal file
33
src/Terminal/commands/buy.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
53
src/Terminal/commands/cat.ts
Normal file
53
src/Terminal/commands/cat.ts
Normal file
@ -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}`);
|
||||
}
|
45
src/Terminal/commands/cd.ts
Normal file
45
src/Terminal/commands/cd.ts
Normal file
@ -0,0 +1,45 @@
|
||||
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);
|
||||
}
|
||||
}
|
33
src/Terminal/commands/check.ts
Normal file
33
src/Terminal/commands/check.ts
Normal file
@ -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();
|
||||
}
|
||||
}
|
32
src/Terminal/commands/connect.ts
Normal file
32
src/Terminal/commands/connect.ts
Normal file
@ -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");
|
||||
}
|
79
src/Terminal/commands/download.ts
Normal file
79
src/Terminal/commands/download.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
29
src/Terminal/commands/expr.ts
Normal file
29
src/Terminal/commands/expr.ts
Normal file
@ -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);
|
||||
}
|
29
src/Terminal/commands/free.ts
Normal file
29
src/Terminal/commands/free.ts
Normal file
@ -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}`);
|
||||
}
|
44
src/Terminal/commands/hack.ts
Normal file
44
src/Terminal/commands/hack.ts
Normal file
@ -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);
|
||||
}
|
29
src/Terminal/commands/help.ts
Normal file
29
src/Terminal/commands/help.ts
Normal file
@ -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) {
|
||||
TerminalHelpText.forEach((line) => terminal.print(line));
|
||||
} else {
|
||||
const cmd = args[0];
|
||||
const txt = HelpTexts[cmd];
|
||||
if (txt == null) {
|
||||
terminal.error("No help topics match '" + cmd + "'");
|
||||
return;
|
||||
}
|
||||
txt.forEach((t) => terminal.print(t));
|
||||
}
|
||||
}
|
22
src/Terminal/commands/home.ts
Normal file
22
src/Terminal/commands/home.ts
Normal file
@ -0,0 +1,22 @@
|
||||
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("/");
|
||||
}
|
18
src/Terminal/commands/hostname.ts
Normal file
18
src/Terminal/commands/hostname.ts
Normal file
@ -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);
|
||||
}
|
18
src/Terminal/commands/ifconfig.ts
Normal file
18
src/Terminal/commands/ifconfig.ts
Normal file
@ -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);
|
||||
}
|
44
src/Terminal/commands/kill.ts
Normal file
44
src/Terminal/commands/kill.ts
Normal file
@ -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 + "");
|
||||
}
|
||||
}
|
14
src/Terminal/commands/killall.ts
Normal file
14
src/Terminal/commands/killall.ts
Normal file
@ -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");
|
||||
}
|
148
src/Terminal/commands/ls.tsx
Normal file
148
src/Terminal/commands/ls.tsx
Normal file
@ -0,0 +1,148 @@
|
||||
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[]): 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);
|
||||
}
|
||||
}
|
||||
|
||||
const groups = [
|
||||
{ segments: folders },
|
||||
{ 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);
|
||||
}
|
||||
}
|
7
src/Terminal/commands/lscpu.ts
Normal file
7
src/Terminal/commands/lscpu.ts
Normal file
@ -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)");
|
||||
}
|
44
src/Terminal/commands/mem.ts
Normal file
44
src/Terminal/commands/mem.ts
Normal file
@ -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 + "");
|
||||
}
|
||||
}
|
91
src/Terminal/commands/mv.ts
Normal file
91
src/Terminal/commands/mv.ts
Normal file
@ -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 + "");
|
||||
}
|
||||
}
|
57
src/Terminal/commands/nano.ts
Normal file
57
src/Terminal/commands/nano.ts
Normal file
@ -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 + "");
|
||||
}
|
||||
}
|
25
src/Terminal/commands/ps.ts
Normal file
25
src/Terminal/commands/ps.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user