mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-26 07:57:32 +01:00
commit
2cb762184f
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
Changelog.txt
|
Changelog.txt
|
||||||
Netburner.txt
|
Netburner.txt
|
||||||
@ -9,5 +10,9 @@ Netburner.txt
|
|||||||
/test/*.css
|
/test/*.css
|
||||||
.cypress
|
.cypress
|
||||||
|
|
||||||
|
# tmp folder for electron
|
||||||
|
.package
|
||||||
|
.build
|
||||||
|
|
||||||
# editor files
|
# editor files
|
||||||
.vscode
|
.vscode
|
||||||
|
@ -5,120 +5,8 @@
|
|||||||
* Styling for the Character Overview Panel (top-right panel)
|
* Styling for the Character Overview Panel (top-right panel)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#character-overview-wrapper {
|
#character-overview {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 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;
|
overflow: visible;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
width: 45%;
|
width: 45%;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cmpy-mgmt-industry-overview-panel {
|
.cmpy-mgmt-industry-overview-panel {
|
||||||
|
@ -4,18 +4,12 @@
|
|||||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||||
terminal which has its own page) */
|
terminal which has its own page) */
|
||||||
|
|
||||||
.generic-menupage-container {
|
#generic-react-container {
|
||||||
padding-left: 2px;
|
|
||||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||||
scrollbar-width: none; /* for Firefox */
|
scrollbar-width: none; /* for Firefox */
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#generic-react-container {
|
|
||||||
padding: 10px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#generic-react-container::-webkit-scrollbar {
|
#generic-react-container::-webkit-scrollbar {
|
||||||
display: none; /* for Chrome, Safari, and Opera */
|
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
|
//# 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)
|
* Styling for the Character Overview Panel (top-right panel)
|
||||||
*/
|
*/
|
||||||
#character-overview-wrapper {
|
#character-overview {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 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 */
|
/* COLORS */
|
||||||
/* Attributes */
|
/* Attributes */
|
||||||
#terminal-container {
|
#terminal-container {
|
||||||
@ -1639,18 +1533,13 @@ button {
|
|||||||
/* Attributes */
|
/* Attributes */
|
||||||
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
|
||||||
terminal which has its own page) */
|
terminal which has its own page) */
|
||||||
.generic-menupage-container {
|
#generic-react-container {
|
||||||
padding-left: 2px;
|
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
/* for Internet Explorer, Edge */
|
/* for Internet Explorer, Edge */
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
/* for Firefox */
|
/* for Firefox */
|
||||||
flex-grow: 1; }
|
flex-grow: 1; }
|
||||||
|
|
||||||
#generic-react-container {
|
|
||||||
padding: 10px;
|
|
||||||
overflow-y: scroll; }
|
|
||||||
|
|
||||||
#generic-react-container::-webkit-scrollbar {
|
#generic-react-container::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
/* for Chrome, Safari, and Opera */ }
|
/* for Chrome, Safari, and Opera */ }
|
||||||
@ -3041,7 +2930,9 @@ input[type="checkbox"] {
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
width: 45%; }
|
width: 45%;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-top: 10px; }
|
||||||
|
|
||||||
.cmpy-mgmt-industry-overview-panel {
|
.cmpy-mgmt-industry-overview-panel {
|
||||||
border: 1px solid #fff;
|
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"
|
||||||
|
}
|
25
index.html
25
index.html
@ -42,22 +42,8 @@
|
|||||||
<div id="mainmenu-container" style="display: flex; flex-direction: row">
|
<div id="mainmenu-container" style="display: flex; flex-direction: row">
|
||||||
<!-- Main menu -->
|
<!-- Main menu -->
|
||||||
<div id="sidebar" style=""></div>
|
<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 id="generic-react-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="infiltration-container" class="generic-fullscreen-container"></div>
|
<div id="infiltration-container" class="generic-fullscreen-container"></div>
|
||||||
<div id="mission-container" class="generic-fullscreen-container"></div>
|
<div id="mission-container" class="generic-fullscreen-container"></div>
|
||||||
@ -89,16 +75,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Character Overview Screen -->
|
<!-- Character Overview Screen -->
|
||||||
<div id="character-overview-wrapper">
|
<div id="character-overview"></div>
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Status text -->
|
<!-- Status text -->
|
||||||
<div id="status-text-container">
|
<div id="status-text-container">
|
||||||
|
4072
package-lock.json
generated
4072
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": {
|
"author": {
|
||||||
"name": "Daniel Xie"
|
"name": "Daniel Xie"
|
||||||
},
|
},
|
||||||
@ -6,13 +10,17 @@
|
|||||||
"url": "https://github.com/danielyxie/bitburner/issues"
|
"url": "https://github.com/danielyxie/bitburner/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.3",
|
"@emotion/react": "^11.4.1",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@emotion/styled": "^11.3.0",
|
||||||
"@monaco-editor/react": "^4.2.2",
|
"@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/js-beautify": "^1.13.2",
|
||||||
"@types/numeral": "0.0.25",
|
"@types/numeral": "0.0.25",
|
||||||
"@types/react": "^16.8.6",
|
"@types/react": "^17.0.21",
|
||||||
"@types/react-dom": "^16.8.2",
|
"@types/react-dom": "^17.0.9",
|
||||||
"acorn": "^8.4.1",
|
"acorn": "^8.4.1",
|
||||||
"acorn-walk": "^8.1.1",
|
"acorn-walk": "^8.1.1",
|
||||||
"ajv": "^5.1.5",
|
"ajv": "^5.1.5",
|
||||||
@ -42,8 +50,8 @@
|
|||||||
"node-sass": "^6.0.1",
|
"node-sass": "^6.0.1",
|
||||||
"normalize.css": "^8.0.0",
|
"normalize.css": "^8.0.0",
|
||||||
"numeral": "2.0.6",
|
"numeral": "2.0.6",
|
||||||
"react": "^16.8.3",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^16.8.3",
|
"react-dom": "^17.0.2",
|
||||||
"react-modal": "^3.12.1",
|
"react-modal": "^3.12.1",
|
||||||
"sprintf-js": "^1.1.1",
|
"sprintf-js": "^1.1.1",
|
||||||
"tapable": "^1.0.0",
|
"tapable": "^1.0.0",
|
||||||
@ -59,6 +67,7 @@
|
|||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
"@babel/preset-typescript": "^7.15.0",
|
||||||
"@testing-library/cypress": "^8.0.1",
|
"@testing-library/cypress": "^8.0.1",
|
||||||
|
"@types/file-saver": "^2.0.3",
|
||||||
"@types/jest": "^27.0.1",
|
"@types/jest": "^27.0.1",
|
||||||
"@types/lodash": "^4.14.168",
|
"@types/lodash": "^4.14.168",
|
||||||
"@types/node": "^16.9.1",
|
"@types/node": "^16.9.1",
|
||||||
@ -71,6 +80,8 @@
|
|||||||
"bundle-loader": "~0.5.0",
|
"bundle-loader": "~0.5.0",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
"cypress": "^8.3.1",
|
"cypress": "^8.3.1",
|
||||||
|
"electron": "^14.0.1",
|
||||||
|
"electron-packager": "^15.4.0",
|
||||||
"es6-promise-polyfill": "^1.1.1",
|
"es6-promise-polyfill": "^1.1.1",
|
||||||
"eslint": "^7.24.0",
|
"eslint": "^7.24.0",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
@ -120,8 +131,6 @@
|
|||||||
"node": ">=8 || <=9"
|
"node": ">=8 || <=9"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/danielyxie/bitburner",
|
"homepage": "https://github.com/danielyxie/bitburner",
|
||||||
"license": "SEE LICENSE IN license.txt",
|
|
||||||
"name": "bitburner",
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/danielyxie/bitburner.git"
|
"url": "git+https://github.com/danielyxie/bitburner.git"
|
||||||
@ -144,7 +153,7 @@
|
|||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"watch": "webpack --watch --mode production",
|
"watch": "webpack --watch --mode production",
|
||||||
"watch:dev": "webpack --watch --mode development"
|
"watch:dev": "webpack --watch --mode development",
|
||||||
},
|
"package-electron": "electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png"
|
||||||
"version": "0.53.0"
|
}
|
||||||
}
|
}
|
||||||
|
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 { IMap } from "./types";
|
||||||
import { post } from "./ui/postToTerminal";
|
import { Terminal } from "./Terminal";
|
||||||
|
|
||||||
export let Aliases: IMap<string> = {};
|
export let Aliases: IMap<string> = {};
|
||||||
export let GlobalAliases: IMap<string> = {};
|
export let GlobalAliases: IMap<string> = {};
|
||||||
@ -24,12 +24,12 @@ export function loadGlobalAliases(saveString: string): void {
|
|||||||
export function printAliases(): void {
|
export function printAliases(): void {
|
||||||
for (const name in Aliases) {
|
for (const name in Aliases) {
|
||||||
if (Aliases.hasOwnProperty(name)) {
|
if (Aliases.hasOwnProperty(name)) {
|
||||||
post("alias " + name + "=" + Aliases[name]);
|
Terminal.print("alias " + name + "=" + Aliases[name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const name in GlobalAliases) {
|
for (const name in GlobalAliases) {
|
||||||
if (GlobalAliases.hasOwnProperty(name)) {
|
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 { Game } from "./Game";
|
||||||
import { Deck } from "./CardDeck/Deck";
|
import { Deck } from "./CardDeck/Deck";
|
||||||
import { Hand } from "./CardDeck/Hand";
|
import { Hand } from "./CardDeck/Hand";
|
||||||
import { InputAdornment } from "@material-ui/core";
|
import { InputAdornment } from "@mui/material";
|
||||||
import { ReactCard } from "./CardDeck/ReactCard";
|
import { ReactCard } from "./CardDeck/ReactCard";
|
||||||
import { MuiTextField } from "../ui/React/MuiTextField";
|
import { MuiTextField } from "../ui/React/MuiTextField";
|
||||||
import { MuiButton } from "../ui/React/MuiButton";
|
import { MuiButton } from "../ui/React/MuiButton";
|
||||||
|
@ -179,7 +179,6 @@ export class CodingContract {
|
|||||||
removePopup(popupId);
|
removePopup(popupId);
|
||||||
},
|
},
|
||||||
onAttempt: (val: string) => {
|
onAttempt: (val: string) => {
|
||||||
console.error("attempting");
|
|
||||||
if (this.isSolution(val)) {
|
if (this.isSolution(val)) {
|
||||||
resolve(CodingContractResult.Success);
|
resolve(CodingContractResult.Success);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { DarkWebItems } from "./DarkWebItems";
|
import { DarkWebItems } from "./DarkWebItems";
|
||||||
|
|
||||||
import { Player } from "../Player";
|
import { Player } from "../Player";
|
||||||
|
import { Terminal } from "../Terminal";
|
||||||
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
import { SpecialServerIps } from "../Server/SpecialServerIps";
|
||||||
import { post, postElement } from "../ui/postToTerminal";
|
import { numeralWrapper } from "../ui/numeralFormat";
|
||||||
import { Money } from "../ui/React/Money";
|
|
||||||
|
|
||||||
import { isValidIPAddress } from "../../utils/helpers/isValidIPAddress";
|
import { isValidIPAddress } from "../../utils/helpers/isValidIPAddress";
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ export function checkIfConnectedToDarkweb(): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (darkwebIp == Player.getCurrentServer().ip) {
|
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. " +
|
"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] " +
|
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
|
||||||
"to purchase an item.",
|
"to purchase an item.",
|
||||||
@ -35,9 +34,9 @@ export function executeDarkwebTerminalCommand(commandArray: string[]): void {
|
|||||||
switch (commandArray[0]) {
|
switch (commandArray[0]) {
|
||||||
case "buy": {
|
case "buy": {
|
||||||
if (commandArray.length != 2) {
|
if (commandArray.length != 2) {
|
||||||
post("Incorrect number of arguments. Usage: ");
|
Terminal.error("Incorrect number of arguments. Usage: ");
|
||||||
post("buy -l");
|
Terminal.print("buy -l");
|
||||||
post("buy [item name]");
|
Terminal.print("buy [item name]");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const arg = commandArray[1];
|
const arg = commandArray[1];
|
||||||
@ -49,23 +48,19 @@ export function executeDarkwebTerminalCommand(commandArray: string[]): void {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
post("Command not found");
|
Terminal.error("Command not found");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function listAllDarkwebItems(): void {
|
export function listAllDarkwebItems(): void {
|
||||||
for (const key in DarkWebItems) {
|
for (const key in DarkWebItems) {
|
||||||
const item = DarkWebItems[key];
|
const item = DarkWebItems[key];
|
||||||
postElement(
|
Terminal.print(`${item.program} - ${numeralWrapper.formatMoney(item.price)} - ${item.description}`);
|
||||||
<>
|
|
||||||
{item.program} - <Money money={item.price} player={Player} /> - {item.description}
|
|
||||||
</>,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buyDarkwebItem(itemName: string): void {
|
export function buyDarkwebItem(itemName: string): void {
|
||||||
itemName = itemName.toLowerCase();
|
itemName = itemName.toLowerCase();
|
||||||
|
|
||||||
// find the program that matches, if any
|
// find the program that matches, if any
|
||||||
@ -79,24 +74,26 @@ function buyDarkwebItem(itemName: string): void {
|
|||||||
|
|
||||||
// return if invalid
|
// return if invalid
|
||||||
if (item === null) {
|
if (item === null) {
|
||||||
post("Unrecognized item: " + itemName);
|
Terminal.print("Unrecognized item: " + itemName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return if the player already has it.
|
// return if the player already has it.
|
||||||
if (Player.hasProgram(item.program)) {
|
if (Player.hasProgram(item.program)) {
|
||||||
post("You already have the " + item.program + " program");
|
Terminal.print("You already have the " + item.program + " program");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return if the player doesn't have enough money
|
// return if the player doesn't have enough money
|
||||||
if (Player.money.lt(item.price)) {
|
if (Player.money.lt(item.price)) {
|
||||||
post("Not enough money to purchase " + item.program);
|
Terminal.print("Not enough money to purchase " + item.program);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// buy and push
|
// buy and push
|
||||||
Player.loseMoney(item.price);
|
Player.loseMoney(item.price);
|
||||||
Player.getHomeComputer().programs.push(item.program);
|
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 { IEngine } from "./IEngine";
|
||||||
|
|
||||||
import React from "react";
|
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 { General } from "./DevMenu/ui/General";
|
||||||
import { Stats } from "./DevMenu/ui/Stats";
|
import { Stats } from "./DevMenu/ui/Stats";
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import AddIcon from "@material-ui/icons/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import RemoveIcon from "@material-ui/icons/Remove";
|
import RemoveIcon from "@mui/icons-material/Remove";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import ExposureZeroIcon from "@material-ui/icons/ExposureZero";
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
import DoubleArrowIcon from "@material-ui/icons/DoubleArrow";
|
import DoubleArrowIcon from "@mui/icons-material/DoubleArrow";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Tooltip from "@material-ui/core/Tooltip";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
label: string;
|
label: string;
|
||||||
@ -37,12 +37,12 @@ export function Adjuster(props: IProps): React.ReactElement {
|
|||||||
startAdornment: (
|
startAdornment: (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="Add a lot">
|
<Tooltip title="Add a lot">
|
||||||
<IconButton color="primary" onClick={tons}>
|
<IconButton color="primary" onClick={tons} size="large">
|
||||||
<DoubleArrowIcon style={{ transform: "rotate(-90deg)" }} />
|
<DoubleArrowIcon style={{ transform: "rotate(-90deg)" }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Add">
|
<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 />
|
<AddIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -51,13 +51,17 @@ export function Adjuster(props: IProps): React.ReactElement {
|
|||||||
endAdornment: (
|
endAdornment: (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="Remove">
|
<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 />
|
<RemoveIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Reset">
|
<Tooltip title="Reset">
|
||||||
<IconButton color="primary" onClick={reset}>
|
<IconButton color="primary" onClick={reset} size="large">
|
||||||
<ExposureZeroIcon />
|
<ClearIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import ReplyAllIcon from "@material-ui/icons/ReplyAll";
|
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
||||||
import ReplyIcon from "@material-ui/icons/Reply";
|
import ReplyIcon from "@mui/icons-material/Reply";
|
||||||
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
@ -20,7 +21,7 @@ interface IProps {
|
|||||||
export function Augmentations(props: IProps): React.ReactElement {
|
export function Augmentations(props: IProps): React.ReactElement {
|
||||||
const [augmentation, setAugmentation] = useState("Augmented Targeting I");
|
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);
|
setAugmentation(event.target.value as string);
|
||||||
}
|
}
|
||||||
function queueAug(): void {
|
function queueAug(): void {
|
||||||
@ -33,6 +34,11 @@ export function Augmentations(props: IProps): React.ReactElement {
|
|||||||
props.player.queueAugmentation(augName);
|
props.player.queueAugmentation(augName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearAugs(): void {
|
||||||
|
props.player.augmentations = [];
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion>
|
<Accordion>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||||
@ -53,14 +59,21 @@ export function Augmentations(props: IProps): React.ReactElement {
|
|||||||
value={augmentation}
|
value={augmentation}
|
||||||
startAdornment={
|
startAdornment={
|
||||||
<>
|
<>
|
||||||
<IconButton color="primary" onClick={queueAllAugs}>
|
<IconButton color="primary" onClick={queueAllAugs} size="large">
|
||||||
<ReplyAllIcon />
|
<ReplyAllIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton color="primary" onClick={queueAug}>
|
<IconButton color="primary" onClick={queueAug} size="large">
|
||||||
<ReplyIcon />
|
<ReplyIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
endAdornment={
|
||||||
|
<>
|
||||||
|
<IconButton color="primary" onClick={clearAugs} size="large">
|
||||||
|
<ClearIcon />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{Object.values(AugmentationNames).map((aug) => (
|
{Object.values(AugmentationNames).map((aug) => (
|
||||||
<MenuItem key={aug} value={aug}>
|
<MenuItem key={aug} value={aug}>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import { Adjuster } from "./Adjuster";
|
import { Adjuster } from "./Adjuster";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@material-ui/core/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import { generateContract, generateRandomContract, generateRandomContractOnHome } from "../../CodingContractGenerator";
|
import { generateContract, generateRandomContract, generateRandomContractOnHome } from "../../CodingContractGenerator";
|
||||||
import { CodingContractTypes } from "../../CodingContracts";
|
import { CodingContractTypes } from "../../CodingContracts";
|
||||||
|
|
||||||
export function CodingContracts(): React.ReactElement {
|
export function CodingContracts(): React.ReactElement {
|
||||||
const [codingcontract, setCodingcontract] = useState("Find Largest Prime Factor");
|
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);
|
setCodingcontract(event.target.value as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@material-ui/core/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import { Companies as AllCompanies } from "../../Company/Companies";
|
import { Companies as AllCompanies } from "../../Company/Companies";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import { Adjuster } from "./Adjuster";
|
import { Adjuster } from "./Adjuster";
|
||||||
|
|
||||||
const bigNumber = 1e12;
|
const bigNumber = 1e12;
|
||||||
|
|
||||||
export function Companies(): React.ReactElement {
|
export function Companies(): React.ReactElement {
|
||||||
const [company, setCompany] = useState("ECorp");
|
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);
|
setCompany(event.target.value as string);
|
||||||
}
|
}
|
||||||
function resetCompanyRep(): void {
|
function resetCompanyRep(): void {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { Adjuster } from "./Adjuster";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@material-ui/core/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import { Adjuster } from "./Adjuster";
|
import { Adjuster } from "./Adjuster";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Factions as AllFaction } from "../../Faction/Factions";
|
import { Factions as AllFaction } from "../../Faction/Factions";
|
||||||
import FormControl from "@material-ui/core/FormControl";
|
import FormControl from "@mui/material/FormControl";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import ReplyAllIcon from "@material-ui/icons/ReplyAll";
|
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
||||||
import ReplyIcon from "@material-ui/icons/Reply";
|
import ReplyIcon from "@mui/icons-material/Reply";
|
||||||
import InputLabel from "@material-ui/core/InputLabel";
|
import InputLabel from "@mui/material/InputLabel";
|
||||||
|
|
||||||
const bigNumber = 1e12;
|
const bigNumber = 1e12;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ interface IProps {
|
|||||||
export function Factions(props: IProps): React.ReactElement {
|
export function Factions(props: IProps): React.ReactElement {
|
||||||
const [faction, setFaction] = useState("Illuminati");
|
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);
|
setFaction(event.target.value as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ export function Factions(props: IProps): React.ReactElement {
|
|||||||
value={faction}
|
value={faction}
|
||||||
startAdornment={
|
startAdornment={
|
||||||
<>
|
<>
|
||||||
<IconButton color="primary" onClick={receiveAllInvites}>
|
<IconButton color="primary" onClick={receiveAllInvites} size="large">
|
||||||
<ReplyAllIcon />
|
<ReplyAllIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton color="primary" onClick={receiveInvite}>
|
<IconButton color="primary" onClick={receiveInvite} size="large">
|
||||||
<ReplyIcon />
|
<ReplyIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import { Adjuster } from "./Adjuster";
|
import { Adjuster } from "./Adjuster";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { Money } from "../../ui/React/Money";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { hackWorldDaemon } from "../../RedPill";
|
import { hackWorldDaemon } from "../../RedPill";
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@material-ui/core/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { Programs as AllPrograms } from "../../Programs/Programs";
|
import { Programs as AllPrograms } from "../../Programs/Programs";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
@ -17,7 +17,7 @@ interface IProps {
|
|||||||
|
|
||||||
export function Programs(props: IProps): React.ReactElement {
|
export function Programs(props: IProps): React.ReactElement {
|
||||||
const [program, setProgram] = useState("NUKE.exe");
|
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);
|
setProgram(event.target.value as string);
|
||||||
}
|
}
|
||||||
function addProgram(): void {
|
function addProgram(): void {
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Select from "@material-ui/core/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import { AllServers } from "../../Server/AllServers";
|
import { AllServers } from "../../Server/AllServers";
|
||||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||||
import { GetServerByHostname } from "../../Server/ServerHelpers";
|
import { GetServerByHostname } from "../../Server/ServerHelpers";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
|
||||||
export function Servers(): React.ReactElement {
|
export function Servers(): React.ReactElement {
|
||||||
const [server, setServer] = useState("home");
|
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);
|
setServer(event.target.value as string);
|
||||||
}
|
}
|
||||||
function rootServer(): void {
|
function rootServer(): void {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { PlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import ButtonGroup from "@material-ui/core/ButtonGroup";
|
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||||
|
|
||||||
// Update as additional BitNodes get implemented
|
// Update as additional BitNodes get implemented
|
||||||
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { Adjuster } from "./Adjuster";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@mui/material/Button";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
import { StockMarket as SM } from "../../StockMarket/StockMarket";
|
import { StockMarket as SM } from "../../StockMarket/StockMarket";
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
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 { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { saveObject } from "../../SaveObject";
|
import { saveObject } from "../../SaveObject";
|
||||||
import { IEngine } from "../../IEngine";
|
import { IEngine } from "../../IEngine";
|
||||||
|
@ -3,18 +3,18 @@ import { AllServers } from "../Server/AllServers";
|
|||||||
import { Modal } from "../ui/React/Modal";
|
import { Modal } from "../ui/React/Modal";
|
||||||
import { numeralWrapper } from "../ui/numeralFormat";
|
import { numeralWrapper } from "../ui/numeralFormat";
|
||||||
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@mui/material/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@mui/material/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@mui/material/TableCell";
|
||||||
import TableContainer from "@material-ui/core/TableContainer";
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
import TableHead from "@material-ui/core/TableHead";
|
import TableHead from "@mui/material/TableHead";
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
import TableRow from "@mui/material/TableRow";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import Accordion from "@material-ui/core/Accordion";
|
import Accordion from "@mui/material/Accordion";
|
||||||
import AccordionSummary from "@material-ui/core/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@material-ui/core/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
|
||||||
interface IServerProps {
|
interface IServerProps {
|
||||||
ip: string;
|
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 parseFconfSettings(config: string): void;
|
||||||
|
export declare function createFconf(): string;
|
||||||
|
@ -7,7 +7,7 @@ export interface IEngine {
|
|||||||
_lastUpdate: number;
|
_lastUpdate: number;
|
||||||
hideAllContent: () => void;
|
hideAllContent: () => void;
|
||||||
loadTerminalContent: () => void;
|
loadTerminalContent: () => void;
|
||||||
loadScriptEditorContent: () => void;
|
loadScriptEditorContent: (filename?: string, code?: string) => void;
|
||||||
loadActiveScriptsContent: () => void;
|
loadActiveScriptsContent: () => void;
|
||||||
loadCreateProgramContent: () => void;
|
loadCreateProgramContent: () => void;
|
||||||
loadCharacterContent: () => void;
|
loadCharacterContent: () => void;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinish: () => void;
|
onFinish: () => void;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { IEngine } from "../../IEngine";
|
import { IEngine } from "../../IEngine";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { Countdown } from "./Countdown";
|
import { Countdown } from "./Countdown";
|
||||||
import { BracketGame } from "./BracketGame";
|
import { BracketGame } from "./BracketGame";
|
||||||
import { SlashGame } from "./SlashGame";
|
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 React, { useState, useEffect } from "react";
|
||||||
import { withStyles } from "@material-ui/core/styles";
|
import withStyles from '@mui/styles/withStyles';
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
|
|
||||||
const TimerProgress = withStyles(() => ({
|
const TimerProgress = withStyles(() => ({
|
||||||
bar: {
|
bar: {
|
||||||
|
@ -2,7 +2,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer";
|
|||||||
import { IEngine } from "../../IEngine";
|
import { IEngine } from "../../IEngine";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
import { StdButton } from "../../ui/React/StdButton";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
Player: IPlayer;
|
Player: IPlayer;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
import { GameTimer } from "./GameTimer";
|
||||||
|
@ -3,7 +3,7 @@ import { IEngine } from "../../IEngine";
|
|||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { StdButton } from "../../ui/React/StdButton";
|
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 { Money } from "../../ui/React/Money";
|
||||||
import { Reputation } from "../../ui/React/Reputation";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { IMinigameProps } from "./IMinigameProps";
|
import { IMinigameProps } from "./IMinigameProps";
|
||||||
import { KeyHandler } from "./KeyHandler";
|
import { KeyHandler } from "./KeyHandler";
|
||||||
import { GameTimer } from "./GameTimer";
|
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}
|
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;
|
this.faction.playerReputation += gain;
|
||||||
} else {
|
} else {
|
||||||
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
|
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 { Exploit } from "./Exploits/Exploit.ts";
|
||||||
|
|
||||||
import { numeralWrapper } from "./ui/numeralFormat";
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
import { post } from "./ui/postToTerminal";
|
|
||||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||||
import { is2DArray } from "./utils/helpers/is2DArray";
|
import { is2DArray } from "./utils/helpers/is2DArray";
|
||||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||||
@ -1059,10 +1058,10 @@ function NetscriptFunctions(workerScript) {
|
|||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
throw makeRuntimeErrorMsg("tprint", "Takes at least 1 argument.");
|
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) {
|
tprintf: function (format, ...args) {
|
||||||
post(vsprintf(format, args));
|
Terminal.print(vsprintf(format, args));
|
||||||
},
|
},
|
||||||
clearLog: function () {
|
clearLog: function () {
|
||||||
workerScript.scriptRef.clearLog();
|
workerScript.scriptRef.clearLog();
|
||||||
@ -3134,8 +3133,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
Player.getCurrentServer().isConnectedTo = false;
|
Player.getCurrentServer().isConnectedTo = false;
|
||||||
Player.currentServer = Player.getHomeComputer().ip;
|
Player.currentServer = Player.getHomeComputer().ip;
|
||||||
Player.getCurrentServer().isConnectedTo = true;
|
Player.getCurrentServer().isConnectedTo = true;
|
||||||
Terminal.currDir = "/";
|
Terminal.setcwd("/");
|
||||||
Terminal.resetTerminalInput(true);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3146,8 +3144,7 @@ function NetscriptFunctions(workerScript) {
|
|||||||
Player.getCurrentServer().isConnectedTo = false;
|
Player.getCurrentServer().isConnectedTo = false;
|
||||||
Player.currentServer = target.ip;
|
Player.currentServer = target.ip;
|
||||||
Player.getCurrentServer().isConnectedTo = true;
|
Player.getCurrentServer().isConnectedTo = true;
|
||||||
Terminal.currDir = "/";
|
Terminal.setcwd("/");
|
||||||
Terminal.resetTerminalInput(true);
|
|
||||||
return true;
|
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 { ICorporation } from "../Corporation/ICorporation";
|
||||||
import { IGang } from "../Gang/IGang";
|
import { IGang } from "../Gang/IGang";
|
||||||
import { IBladeburner } from "../Bladeburner/IBladeburner";
|
import { IBladeburner } from "../Bladeburner/IBladeburner";
|
||||||
|
import { ICodingContractReward } from "../CodingContracts";
|
||||||
|
|
||||||
export interface IPlayer {
|
export interface IPlayer {
|
||||||
// Class members
|
// Class members
|
||||||
@ -207,4 +208,5 @@ export interface IPlayer {
|
|||||||
queueAugmentation(augmentationName: string): void;
|
queueAugmentation(augmentationName: string): void;
|
||||||
receiveInvite(factionName: string): void;
|
receiveInvite(factionName: string): void;
|
||||||
updateSkillLevels(): void;
|
updateSkillLevels(): void;
|
||||||
|
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
|
||||||
}
|
}
|
||||||
|
@ -174,11 +174,8 @@ export function prestigeAugmentation() {
|
|||||||
this.hacknetNodes.length = 0;
|
this.hacknetNodes.length = 0;
|
||||||
this.hashManager.prestige();
|
this.hashManager.prestige();
|
||||||
|
|
||||||
// Reset player multipliers
|
// Reapply augs, re-calculate skills and reset HP
|
||||||
this.resetMultipliers();
|
this.reapplyAllAugmentations(true);
|
||||||
|
|
||||||
// Re-calculate skills and reset HP
|
|
||||||
this.updateSkillLevels();
|
|
||||||
this.hp = this.max_hp;
|
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;
|
this.timeWorked = 0;
|
||||||
|
|
||||||
// Gang
|
// Gang
|
||||||
@ -2068,9 +2059,6 @@ export function applyForJob(entryPosType, sing = false) {
|
|||||||
this.jobs[company.name] = pos.name;
|
this.jobs[company.name] = pos.name;
|
||||||
this.companyName = this.location;
|
this.companyName = this.location;
|
||||||
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2186,8 +2174,6 @@ export function applyForEmployeeJob(sing = false) {
|
|||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
|
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2204,8 +2190,6 @@ export function applyForPartTimeEmployeeJob(sing = false) {
|
|||||||
var company = Companies[this.location]; //Company being applied to
|
var company = Companies[this.location]; //Company being applied to
|
||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
|
||||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
|
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2223,8 +2207,6 @@ export function applyForWaiterJob(sing = false) {
|
|||||||
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
|
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2242,8 +2224,6 @@ export function applyForPartTimeWaiterJob(sing = false) {
|
|||||||
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
|
||||||
this.companyName = company.name;
|
this.companyName = company.name;
|
||||||
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
|
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
document.getElementById("world-menu-header").click();
|
|
||||||
if (sing) {
|
if (sing) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2307,6 +2287,8 @@ export function reapplyAllAugmentations(resetMultipliers = true) {
|
|||||||
}
|
}
|
||||||
applyAugmentation(this.augmentations[i], true);
|
applyAugmentation(this.augmentations[i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateSkillLevels();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reapplyAllSourceFiles() {
|
export function reapplyAllSourceFiles() {
|
||||||
|
@ -81,7 +81,7 @@ export class CovenantSleeveMemoryUpgrade extends React.Component<IProps, IState>
|
|||||||
if (isNaN(this.state.amt)) {
|
if (isNaN(this.state.amt)) {
|
||||||
purchaseBtnContent = <>Invalid value</>;
|
purchaseBtnContent = <>Invalid value</>;
|
||||||
} else if (this.state.amt > maxMemory) {
|
} else if (this.state.amt > maxMemory) {
|
||||||
purchaseBtnContent = <>Memory cannot exceed 100?</>;
|
purchaseBtnContent = <>Memory cannot exceed 100</>;
|
||||||
} else {
|
} else {
|
||||||
purchaseBtnContent = (
|
purchaseBtnContent = (
|
||||||
<>
|
<>
|
||||||
|
@ -23,7 +23,7 @@ import { prestigeHomeComputer } from "./Server/ServerHelpers";
|
|||||||
import { SourceFileFlags, updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
import { SourceFileFlags, updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||||
import { SpecialServerIps, prestigeSpecialServerIps, SpecialServerNames } from "./Server/SpecialServerIps";
|
import { SpecialServerIps, prestigeSpecialServerIps, SpecialServerNames } from "./Server/SpecialServerIps";
|
||||||
import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
|
import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
|
||||||
import { Terminal, postVersion } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
|
|
||||||
import { Page, routing } from "./ui/navigationTracking";
|
import { Page, routing } from "./ui/navigationTracking";
|
||||||
|
|
||||||
@ -57,21 +57,13 @@ function prestigeAugmentation() {
|
|||||||
"Fulcrum Secret Technologies",
|
"Fulcrum Secret Technologies",
|
||||||
];
|
];
|
||||||
|
|
||||||
let maintainMembership = Player.factions.filter(function (faction) {
|
const maintainMembership = Player.factions.filter(function (faction) {
|
||||||
return megaCorpFactions.includes(faction);
|
return megaCorpFactions.includes(faction);
|
||||||
});
|
});
|
||||||
|
|
||||||
Player.prestigeAugmentation();
|
Player.prestigeAugmentation();
|
||||||
|
|
||||||
Player.factions = Player.factions.concat(maintainMembership);
|
Terminal.clear();
|
||||||
|
|
||||||
// Now actually go to the Terminal Screen (and reset it)
|
|
||||||
var mainMenu = document.getElementById("mainmenu-container");
|
|
||||||
mainMenu.style.visibility = "visible";
|
|
||||||
Terminal.resetTerminalInput();
|
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
$("#terminal tr:not(:last)").remove();
|
|
||||||
postVersion();
|
|
||||||
|
|
||||||
// Delete all Worker Scripts objects
|
// Delete all Worker Scripts objects
|
||||||
prestigeWorkerScripts();
|
prestigeWorkerScripts();
|
||||||
@ -125,6 +117,9 @@ function prestigeAugmentation() {
|
|||||||
|
|
||||||
// Re-initialize things - This will update any changes
|
// Re-initialize things - This will update any changes
|
||||||
initFactions(); // Factions must be initialized before augmentations
|
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
|
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
|
||||||
Player.reapplyAllSourceFiles();
|
Player.reapplyAllSourceFiles();
|
||||||
initCompanies();
|
initCompanies();
|
||||||
@ -246,16 +241,12 @@ function prestigeSourceFile(flume) {
|
|||||||
Player.reapplyAllSourceFiles();
|
Player.reapplyAllSourceFiles();
|
||||||
initCompanies();
|
initCompanies();
|
||||||
|
|
||||||
// Clear terminal
|
|
||||||
$("#terminal tr:not(:last)").remove();
|
|
||||||
postVersion();
|
|
||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
initMessages();
|
initMessages();
|
||||||
|
|
||||||
var mainMenu = document.getElementById("mainmenu-container");
|
var mainMenu = document.getElementById("mainmenu-container");
|
||||||
mainMenu.style.visibility = "visible";
|
mainMenu.style.visibility = "visible";
|
||||||
Terminal.resetTerminalInput();
|
Terminal.clear();
|
||||||
Engine.loadTerminalContent();
|
Engine.loadTerminalContent();
|
||||||
|
|
||||||
// BitNode 3: Corporatocracy
|
// BitNode 3: Corporatocracy
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
export interface IPlayer {
|
import { BaseServer } from "../Server/BaseServer";
|
||||||
hacking_skill: number;
|
import { ITerminal } from "../Terminal/ITerminal";
|
||||||
sourceFiles: any[];
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
}
|
|
||||||
|
|
||||||
export interface IProgramCreate {
|
export interface IProgramCreate {
|
||||||
level: number;
|
level: number;
|
||||||
@ -13,10 +12,16 @@ export interface IProgramCreate {
|
|||||||
export class Program {
|
export class Program {
|
||||||
name = "";
|
name = "";
|
||||||
create: IProgramCreate | null;
|
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.name = name;
|
||||||
this.create = create;
|
this.create = create;
|
||||||
|
this.run = run;
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlID(): string {
|
htmlID(): string {
|
||||||
|
@ -5,5 +5,5 @@ import { IMap } from "../types";
|
|||||||
export const Programs: IMap<Program> = {};
|
export const Programs: IMap<Program> = {};
|
||||||
|
|
||||||
for (const params of programsMetadata) {
|
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 { 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) {
|
function requireHackingLevel(lvl: number) {
|
||||||
return function (p: IPlayer) {
|
return function (p: IPlayer) {
|
||||||
@ -17,6 +30,7 @@ export interface IProgramCreationParams {
|
|||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
create: IProgramCreate | null;
|
create: IProgramCreate | null;
|
||||||
|
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const programsMetadata: IProgramCreationParams[] = [
|
export const programsMetadata: IProgramCreationParams[] = [
|
||||||
@ -29,6 +43,25 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(1),
|
req: requireHackingLevel(1),
|
||||||
time: CONSTANTS.MillisecondsPerFiveMinutes,
|
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",
|
key: "BruteSSHProgram",
|
||||||
@ -39,6 +72,20 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(50),
|
req: requireHackingLevel(50),
|
||||||
time: CONSTANTS.MillisecondsPerFiveMinutes * 2,
|
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",
|
key: "FTPCrackProgram",
|
||||||
@ -49,6 +96,20 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(100),
|
req: requireHackingLevel(100),
|
||||||
time: CONSTANTS.MillisecondsPerHalfHour,
|
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",
|
key: "RelaySMTPProgram",
|
||||||
@ -59,6 +120,20 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(250),
|
req: requireHackingLevel(250),
|
||||||
time: CONSTANTS.MillisecondsPer2Hours,
|
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",
|
key: "HTTPWormProgram",
|
||||||
@ -69,6 +144,20 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(500),
|
req: requireHackingLevel(500),
|
||||||
time: CONSTANTS.MillisecondsPer4Hours,
|
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",
|
key: "SQLInjectProgram",
|
||||||
@ -79,6 +168,20 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(750),
|
req: requireHackingLevel(750),
|
||||||
time: CONSTANTS.MillisecondsPer8Hours,
|
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",
|
key: "DeepscanV1",
|
||||||
@ -89,6 +192,10 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(75),
|
req: requireHackingLevel(75),
|
||||||
time: CONSTANTS.MillisecondsPerQuarterHour,
|
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",
|
key: "DeepscanV2",
|
||||||
@ -99,6 +206,10 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(400),
|
req: requireHackingLevel(400),
|
||||||
time: CONSTANTS.MillisecondsPer2Hours,
|
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",
|
key: "ServerProfiler",
|
||||||
@ -109,6 +220,46 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(75),
|
req: requireHackingLevel(75),
|
||||||
time: CONSTANTS.MillisecondsPerHalfHour,
|
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",
|
key: "AutoLink",
|
||||||
@ -119,6 +270,11 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: requireHackingLevel(25),
|
req: requireHackingLevel(25),
|
||||||
time: CONSTANTS.MillisecondsPerQuarterHour,
|
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",
|
key: "BitFlume",
|
||||||
@ -129,10 +285,31 @@ export const programsMetadata: IProgramCreationParams[] = [
|
|||||||
req: bitFlumeRequirements(),
|
req: bitFlumeRequirements(),
|
||||||
time: CONSTANTS.MillisecondsPerFiveMinutes / 20,
|
time: CONSTANTS.MillisecondsPerFiveMinutes / 20,
|
||||||
},
|
},
|
||||||
|
run: (terminal: ITerminal, player: IPlayer): void => {
|
||||||
|
const popupId = "bitflume-popup";
|
||||||
|
createPopup(popupId, BitFlumePopup, {
|
||||||
|
player: player,
|
||||||
|
popupId: popupId,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Flight",
|
key: "Flight",
|
||||||
name: "fl1ght.exe",
|
name: "fl1ght.exe",
|
||||||
create: null,
|
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 { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
||||||
|
|
||||||
|
import { Box, ButtonGroup, Tooltip, Typography } from "@mui/material";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
}
|
}
|
||||||
@ -19,34 +22,29 @@ export function ProgramsRoot(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p id="create-program-page-text">
|
<div>
|
||||||
|
<Box>
|
||||||
|
<Typography>
|
||||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
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
|
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.
|
time. Your progress will be saved and you can continue later.
|
||||||
</p>
|
</Typography>
|
||||||
|
</Box>
|
||||||
<ul id="create-program-list">
|
<ButtonGroup>
|
||||||
{getAvailableCreatePrograms(props.player).map((program) => {
|
{getAvailableCreatePrograms(props.player).map((program) => {
|
||||||
const create = program.create;
|
const create = program.create;
|
||||||
if (create === null) return <></>;
|
if (create === null) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<Tooltip title={create.tooltip}>
|
||||||
key={program.name}
|
<Button onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}>
|
||||||
className="a-link-button tooltip"
|
|
||||||
onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}
|
|
||||||
>
|
|
||||||
{program.name}
|
{program.name}
|
||||||
<span className="tooltiptext">{create.tooltip}</span>
|
</Button>
|
||||||
</a>
|
</Tooltip>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ButtonGroup>
|
||||||
<br />
|
</div>
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
@ -92,13 +92,6 @@ function enterBitNode(flume, destroyedBitNode, newBitNode) {
|
|||||||
// Set new Bit Node
|
// Set new Bit Node
|
||||||
Player.bitNodeN = newBitNode;
|
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);
|
prestigeSourceFile(flume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { Script } from "./Script";
|
|||||||
import { FconfSettings } from "../Fconf/FconfSettings";
|
import { FconfSettings } from "../Fconf/FconfSettings";
|
||||||
import { Settings } from "../Settings/Settings";
|
import { Settings } from "../Settings/Settings";
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
import { post } from "../ui/postToTerminal";
|
import { Terminal } from "../Terminal";
|
||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||||
import { getTimestamp } from "../../utils/helpers/getTimestamp";
|
import { getTimestamp } from "../../utils/helpers/getTimestamp";
|
||||||
@ -85,7 +85,7 @@ export class RunningScript {
|
|||||||
|
|
||||||
displayLog(): void {
|
displayLog(): void {
|
||||||
for (let i = 0; i < this.logs.length; ++i) {
|
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 { AllServers, createUniqueRandomIp, ipExists } from "./AllServers";
|
||||||
import { Server, IConstructorParams } from "./Server";
|
import { Server, IConstructorParams } from "./Server";
|
||||||
|
import { BaseServer } from "./BaseServer";
|
||||||
import { calculateServerGrowth } from "./formulas/grow";
|
import { calculateServerGrowth } from "./formulas/grow";
|
||||||
|
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
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
|
// Returns the i-th server on the specified server's network
|
||||||
// A Server's serverOnNetwork property holds only the IPs. This function returns
|
// A Server's serverOnNetwork property holds only the IPs. This function returns
|
||||||
// the actual Server object
|
// 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) {
|
if (i > server.serversOnNetwork.length) {
|
||||||
console.error("Tried to get server on network that was out of range");
|
console.error("Tried to get server on network that was out of range");
|
||||||
return null;
|
return null;
|
||||||
|
@ -45,6 +45,11 @@ interface IDefaultSettings {
|
|||||||
*/
|
*/
|
||||||
MaxPortCapacity: number;
|
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.
|
* Whether the player should be asked to confirm purchasing each and every augmentation.
|
||||||
*/
|
*/
|
||||||
@ -104,6 +109,7 @@ const defaultSettings: IDefaultSettings = {
|
|||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: 50,
|
MaxLogCapacity: 50,
|
||||||
MaxPortCapacity: 50,
|
MaxPortCapacity: 50,
|
||||||
|
MaxTerminalCapacity: 200,
|
||||||
SuppressBuyAugmentationConfirmation: false,
|
SuppressBuyAugmentationConfirmation: false,
|
||||||
SuppressFactionInvites: false,
|
SuppressFactionInvites: false,
|
||||||
SuppressHospitalizationPopup: false,
|
SuppressHospitalizationPopup: false,
|
||||||
@ -125,6 +131,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
Locale: "en",
|
Locale: "en",
|
||||||
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
MaxLogCapacity: defaultSettings.MaxLogCapacity,
|
||||||
MaxPortCapacity: defaultSettings.MaxPortCapacity,
|
MaxPortCapacity: defaultSettings.MaxPortCapacity,
|
||||||
|
MaxTerminalCapacity: defaultSettings.MaxTerminalCapacity,
|
||||||
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
|
OwnedAugmentationsOrder: OwnedAugmentationsOrderSetting.AcquirementTime,
|
||||||
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
|
PurchaseAugmentationsOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||||
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
|
SuppressBuyAugmentationConfirmation: defaultSettings.SuppressBuyAugmentationConfirmation,
|
||||||
|
@ -1,51 +1,48 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { createStyles, makeStyles, useTheme, Theme } from "@material-ui/core/styles";
|
import { styled, useTheme, Theme, CSSObject } from "@mui/material/styles";
|
||||||
import Drawer from "@material-ui/core/Drawer";
|
import createStyles from "@mui/styles/createStyles";
|
||||||
import List from "@material-ui/core/List";
|
import makeStyles from "@mui/styles/makeStyles";
|
||||||
import Divider from "@material-ui/core/Divider";
|
import MuiDrawer from "@mui/material/Drawer";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import List from "@mui/material/List";
|
||||||
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
|
import Divider from "@mui/material/Divider";
|
||||||
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
|
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||||
import ListItem from "@material-ui/core/ListItem";
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||||
import ListSubheader from "@material-ui/core/ListSubheader";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import ListItemText from "@material-ui/core/ListItemText";
|
import ListItemText from "@mui/material/ListItemText";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Collapse from "@material-ui/core/Collapse";
|
import Collapse from "@mui/material/Collapse";
|
||||||
import InboxIcon from "@material-ui/icons/MoveToInbox";
|
import Badge from "@mui/material/Badge";
|
||||||
import MailIcon from "@material-ui/icons/Mail";
|
|
||||||
|
|
||||||
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 ComputerIcon from "@mui/icons-material/Computer";
|
||||||
import LastPageIcon from "@material-ui/icons/LastPage"; // Terminal
|
import LastPageIcon from "@mui/icons-material/LastPage"; // Terminal
|
||||||
import CreateIcon from "@material-ui/icons/Create"; // Create Script
|
import CreateIcon from "@mui/icons-material/Create"; // Create Script
|
||||||
import StorageIcon from "@material-ui/icons/Storage"; // Active Scripts
|
import StorageIcon from "@mui/icons-material/Storage"; // Active Scripts
|
||||||
import BugReportIcon from "@material-ui/icons/BugReport"; // Create Program
|
import BugReportIcon from "@mui/icons-material/BugReport"; // Create Program
|
||||||
import EqualizerIcon from "@material-ui/icons/Equalizer"; // Stats
|
import EqualizerIcon from "@mui/icons-material/Equalizer"; // Stats
|
||||||
import ContactsIcon from "@material-ui/icons/Contacts"; // Factions
|
import ContactsIcon from "@mui/icons-material/Contacts"; // Factions
|
||||||
import DoubleArrowIcon from "@material-ui/icons/DoubleArrow"; // Augmentations
|
import DoubleArrowIcon from "@mui/icons-material/DoubleArrow"; // Augmentations
|
||||||
import AccountTreeIcon from "@material-ui/icons/AccountTree"; // Hacknet
|
import AccountTreeIcon from "@mui/icons-material/AccountTree"; // Hacknet
|
||||||
import PeopleAltIcon from "@material-ui/icons/PeopleAlt"; // Sleeves
|
import PeopleAltIcon from "@mui/icons-material/PeopleAlt"; // Sleeves
|
||||||
import LocationCityIcon from "@material-ui/icons/LocationCity"; // City
|
import LocationCityIcon from "@mui/icons-material/LocationCity"; // City
|
||||||
import AirplanemodeActiveIcon from "@material-ui/icons/AirplanemodeActive"; // Travel
|
import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; // Travel
|
||||||
import WorkIcon from "@material-ui/icons/Work"; // Job
|
import WorkIcon from "@mui/icons-material/Work"; // Job
|
||||||
import TrendingUpIcon from "@material-ui/icons/TrendingUp"; // Stock Market
|
import TrendingUpIcon from "@mui/icons-material/TrendingUp"; // Stock Market
|
||||||
import FormatBoldIcon from "@material-ui/icons/FormatBold"; // Bladeburner
|
import FormatBoldIcon from "@mui/icons-material/FormatBold"; // Bladeburner
|
||||||
import BusinessIcon from "@material-ui/icons/Business"; // Corp
|
import BusinessIcon from "@mui/icons-material/Business"; // Corp
|
||||||
import SportsMmaIcon from "@material-ui/icons/SportsMma"; // Gang
|
import SportsMmaIcon from "@mui/icons-material/SportsMma"; // Gang
|
||||||
import CheckIcon from "@material-ui/icons/Check"; // Milestones
|
import CheckIcon from "@mui/icons-material/Check"; // Milestones
|
||||||
import HelpIcon from "@material-ui/icons/Help"; // Tutorial
|
import HelpIcon from "@mui/icons-material/Help"; // Tutorial
|
||||||
import SettingsIcon from "@material-ui/icons/Settings"; // options
|
import SettingsIcon from "@mui/icons-material/Settings"; // options
|
||||||
import DeveloperBoardIcon from "@material-ui/icons/DeveloperBoard"; // Dev
|
import DeveloperBoardIcon from "@mui/icons-material/DeveloperBoard"; // Dev
|
||||||
// import MemoryIcon from "@material-ui/icons/Memory";
|
import AccountBoxIcon from "@mui/icons-material/AccountBox";
|
||||||
// import ShareIcon from "@material-ui/icons/Share";
|
import PublicIcon from "@mui/icons-material/Public";
|
||||||
import AccountBoxIcon from "@material-ui/icons/AccountBox";
|
import LiveHelpIcon from "@mui/icons-material/LiveHelp";
|
||||||
import PublicIcon from "@material-ui/icons/Public";
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
import LiveHelpIcon from "@material-ui/icons/LiveHelp";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
import ExpandLessIcon from "@material-ui/icons/ExpandLess";
|
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
|
||||||
|
|
||||||
import { IEngine } from "../../IEngine";
|
import { IEngine } from "../../IEngine";
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
@ -63,31 +60,44 @@ import { Page, routing } from "../../ui/navigationTracking";
|
|||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 240;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const openedMixin = (theme: Theme): CSSObject => ({
|
||||||
createStyles({
|
width: theme.spacing(31),
|
||||||
drawer: {
|
|
||||||
width: drawerWidth,
|
|
||||||
flexShrink: 0,
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
},
|
|
||||||
drawerOpen: {
|
|
||||||
width: drawerWidth,
|
|
||||||
transition: theme.transitions.create("width", {
|
transition: theme.transitions.create("width", {
|
||||||
easing: theme.transitions.easing.sharp,
|
easing: theme.transitions.easing.sharp,
|
||||||
duration: theme.transitions.duration.enteringScreen,
|
duration: theme.transitions.duration.enteringScreen,
|
||||||
}),
|
}),
|
||||||
},
|
overflowX: "hidden",
|
||||||
drawerClose: {
|
});
|
||||||
|
|
||||||
|
const closedMixin = (theme: Theme): CSSObject => ({
|
||||||
transition: theme.transitions.create("width", {
|
transition: theme.transitions.create("width", {
|
||||||
easing: theme.transitions.easing.sharp,
|
easing: theme.transitions.easing.sharp,
|
||||||
duration: theme.transitions.duration.leavingScreen,
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
}),
|
}),
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
width: theme.spacing(7) + 1,
|
width: `calc(${theme.spacing(2)} + 1px)`,
|
||||||
[theme.breakpoints.up("sm")]: {
|
[theme.breakpoints.up("sm")]: {
|
||||||
width: theme.spacing(9) + 1,
|
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({
|
||||||
active: {
|
active: {
|
||||||
borderLeft: "3px solid " + colors.primary,
|
borderLeft: "3px solid " + colors.primary,
|
||||||
},
|
},
|
||||||
@ -130,6 +140,8 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
const flashTutorial = ITutorial.currStep === iTutorialSteps.WorldDescription;
|
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 programCount = getAvailableCreatePrograms(props.player).length;
|
||||||
const canCreateProgram =
|
const canCreateProgram =
|
||||||
programCount > 0 ||
|
programCount > 0 ||
|
||||||
@ -341,34 +353,24 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const toggleDrawer = () => setOpen((old) => !old);
|
const toggleDrawer = (): void => setOpen((old) => !old);
|
||||||
return (
|
return (
|
||||||
<BBTheme>
|
<BBTheme>
|
||||||
<Drawer
|
<Drawer open={open} anchor="left" variant="permanent">
|
||||||
variant="permanent"
|
|
||||||
className={clsx(classes.drawer, {
|
|
||||||
[classes.drawerOpen]: open,
|
|
||||||
[classes.drawerClose]: !open,
|
|
||||||
})}
|
|
||||||
classes={{
|
|
||||||
paper: clsx({
|
|
||||||
[classes.drawerOpen]: open,
|
|
||||||
[classes.drawerClose]: !open,
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItem button onClick={toggleDrawer}>
|
<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>} />
|
<ListItemText primary={<Typography color="primary">Bitburner v{CONSTANTS.Version}</Typography>} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
<List>
|
<List>
|
||||||
<ListItem button onClick={() => setHackingOpen((old) => !old)}>
|
<ListItem button onClick={() => setHackingOpen((old) => !old)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ComputerIcon />
|
<ComputerIcon color={"primary"} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={<Typography color="primary">Hacking</Typography>} />
|
<ListItemText primary={<Typography color="primary">Hacking</Typography>} />
|
||||||
{hackingOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
{hackingOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={hackingOpen} timeout="auto" unmountOnExit>
|
<Collapse in={hackingOpen} timeout="auto" unmountOnExit>
|
||||||
<List>
|
<List>
|
||||||
@ -435,7 +437,9 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
onClick={clickCreateProgram}
|
onClick={clickCreateProgram}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||||
<BugReportIcon color={activeTab !== "CreateProgram" ? "secondary" : "primary"} />
|
<BugReportIcon color={activeTab !== "CreateProgram" ? "secondary" : "primary"} />
|
||||||
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography color={activeTab !== "CreateProgram" ? "secondary" : "primary"}>
|
<Typography color={activeTab !== "CreateProgram" ? "secondary" : "primary"}>
|
||||||
@ -450,10 +454,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<ListItem button onClick={() => setCharacterOpen((old) => !old)}>
|
<ListItem button onClick={() => setCharacterOpen((old) => !old)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<AccountBoxIcon />
|
<AccountBoxIcon color={"primary"} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={<Typography color="primary">Character</Typography>} />
|
<ListItemText primary={<Typography color="primary">Character</Typography>} />
|
||||||
{characterOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
{characterOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={characterOpen} timeout="auto" unmountOnExit>
|
<Collapse in={characterOpen} timeout="auto" unmountOnExit>
|
||||||
<ListItem
|
<ListItem
|
||||||
@ -483,7 +487,9 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
onClick={clickFactions}
|
onClick={clickFactions}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
<Badge badgeContent={invitationsCount !== 0 ? invitationsCount : undefined} color="error">
|
||||||
<ContactsIcon color={activeTab !== "Factions" ? "secondary" : "primary"} />
|
<ContactsIcon color={activeTab !== "Factions" ? "secondary" : "primary"} />
|
||||||
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography color={activeTab !== "Factions" ? "secondary" : "primary"}>Factions</Typography>
|
<Typography color={activeTab !== "Factions" ? "secondary" : "primary"}>Factions</Typography>
|
||||||
@ -500,10 +506,12 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
onClick={clickAugmentations}
|
onClick={clickAugmentations}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
<Badge badgeContent={augmentationCount !== 0 ? augmentationCount : undefined} color="error">
|
||||||
<DoubleArrowIcon
|
<DoubleArrowIcon
|
||||||
style={{ transform: "rotate(-90deg)" }}
|
style={{ transform: "rotate(-90deg)" }}
|
||||||
color={activeTab !== "Augmentations" ? "secondary" : "primary"}
|
color={activeTab !== "Augmentations" ? "secondary" : "primary"}
|
||||||
/>
|
/>
|
||||||
|
</Badge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography color={activeTab !== "Augmentations" ? "secondary" : "primary"}>Augmentations</Typography>
|
<Typography color={activeTab !== "Augmentations" ? "secondary" : "primary"}>Augmentations</Typography>
|
||||||
@ -549,10 +557,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<ListItem button onClick={() => setWorldOpen((old) => !old)}>
|
<ListItem button onClick={() => setWorldOpen((old) => !old)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<PublicIcon />
|
<PublicIcon color={"primary"} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={<Typography color="primary">World</Typography>} />
|
<ListItemText primary={<Typography color="primary">World</Typography>} />
|
||||||
{worldOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
{worldOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={worldOpen} timeout="auto" unmountOnExit>
|
<Collapse in={worldOpen} timeout="auto" unmountOnExit>
|
||||||
<ListItem
|
<ListItem
|
||||||
@ -677,10 +685,10 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<ListItem button onClick={() => setHelpOpen((old) => !old)}>
|
<ListItem button onClick={() => setHelpOpen((old) => !old)}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<LiveHelpIcon />
|
<LiveHelpIcon color={"primary"} />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={<Typography color="primary">Help</Typography>} />
|
<ListItemText primary={<Typography color="primary">Help</Typography>} />
|
||||||
{helpOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
{helpOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<Collapse in={helpOpen} timeout="auto" unmountOnExit>
|
<Collapse in={helpOpen} timeout="auto" unmountOnExit>
|
||||||
<ListItem
|
<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*/
|
/* tslint:disable:max-line-length completed-docs variable-name*/
|
||||||
import { IMap } from "../types";
|
import { IMap } from "../types";
|
||||||
|
|
||||||
export const TerminalHelpText: string =
|
export const TerminalHelpText: string[] = [
|
||||||
"Type 'help name' to learn more about the command 'name'<br><br>" +
|
"Type 'help name' to learn more about the command ",
|
||||||
'alias [-g] [name="value"] Create or display Terminal aliases<br>' +
|
"",
|
||||||
"analyze Get information about the current machine <br>" +
|
'alias [-g] [name="value"] Create or display Terminal aliases',
|
||||||
"backdoor Install a backdoor on the current machine <br>" +
|
"analyze Get information about the current machine ",
|
||||||
"buy [-l/program] Purchase a program through the Dark Web<br>" +
|
"backdoor Install a backdoor on the current machine ",
|
||||||
"cat [file] Display a .msg, .lit, or .txt file<br>" +
|
"buy [-l/program] Purchase a program through the Dark Web",
|
||||||
"cd [dir] Change to a new directory<br>" +
|
"cat [file] Display a .msg, .lit, or .txt file",
|
||||||
"check [script] [args...] Print a script's logs to Terminal<br>" +
|
"cd [dir] Change to a new directory",
|
||||||
"clear Clear all text on the terminal <br>" +
|
"check [script] [args...] Print a script's logs to Terminal",
|
||||||
"cls See 'clear' command <br>" +
|
"clear Clear all text on the terminal ",
|
||||||
"connect [ip/hostname] Connects to a remote server<br>" +
|
"cls See 'clear' command ",
|
||||||
"download [script/text file] Downloads scripts or text files to your computer<br>" +
|
"connect [ip/hostname] Connects to a remote server",
|
||||||
"expr [math expression] Evaluate a mathematical expression<br>" +
|
"download [script/text file] Downloads scripts or text files to your computer",
|
||||||
"free Check the machine's memory (RAM) usage<br>" +
|
"expr [math expression] Evaluate a mathematical expression",
|
||||||
"hack Hack the current machine<br>" +
|
"free Check the machine's memory (RAM) usage",
|
||||||
"help [command] Display this help text, or the help text for a command<br>" +
|
"hack Hack the current machine",
|
||||||
"home Connect to home computer<br>" +
|
"help [command] Display this help text, or the help text for a command",
|
||||||
"hostname Displays the hostname of the machine<br>" +
|
"home Connect to home computer",
|
||||||
"ifconfig Displays the IP address of the machine<br>" +
|
"hostname Displays the hostname of the machine",
|
||||||
"kill [script/pid] [args...] Stops the specified script on the current server <br>" +
|
"ifconfig Displays the IP address of the machine",
|
||||||
"killall Stops all running scripts on the current machine<br>" +
|
"kill [script/pid] [args...] Stops the specified script on the current server ",
|
||||||
"ls [dir] [| grep pattern] Displays all files on the machine<br>" +
|
"killall Stops all running scripts on the current machine",
|
||||||
"lscpu Displays the number of CPU cores on the machine<br>" +
|
"ls [dir] [| grep pattern] Displays all files on the machine",
|
||||||
"mem [script] [-t] [n] Displays the amount of RAM required to run the script<br>" +
|
"lscpu Displays the number of CPU cores on the machine",
|
||||||
"mv [src] [dest] Move/rename a text or script file<br>" +
|
"mem [script] [-t] [n] Displays the amount of RAM required to run the script",
|
||||||
"nano [file] Text editor - Open up and edit a script or text file<br>" +
|
"mv [src] [dest] Move/rename a text or script file",
|
||||||
"ps Display all scripts that are currently running<br>" +
|
"nano [file] Text editor - Open up and edit a script or text file",
|
||||||
"rm [file] Delete a file from the server<br>" +
|
"ps Display all scripts that are currently running",
|
||||||
"run [name] [-t] [n] [args...] Execute a program or script<br>" +
|
"rm [file] Delete a file from the server",
|
||||||
"scan Prints all immediately-available network connections<br>" +
|
"run [name] [-t] [n] [args...] Execute a program or script",
|
||||||
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away<br>" +
|
"scan Prints all immediately-available network connections",
|
||||||
"scp [file] [server] Copies a file to a destination server<br>" +
|
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away",
|
||||||
"sudov Shows whether you have root access on this computer<br>" +
|
"scp [file] [server] Copies a file to a destination server",
|
||||||
"tail [script] [args...] Displays dynamic logs for the specified script<br>" +
|
"sudov Shows whether you have root access on this computer",
|
||||||
"theme [preset] | bg txt hlgt Change the color scheme of the UI<br>" +
|
"tail [script] [args...] Displays dynamic logs for the specified script",
|
||||||
"top Displays all running scripts and their RAM usage<br>" +
|
"theme [preset] | bg txt hlgt Change the color scheme of the UI",
|
||||||
"unalias [alias name] Deletes the specified alias<br>" +
|
"top Displays all running scripts and their RAM usage",
|
||||||
"wget [url] [target file] Retrieves code/text from a web server<br>";
|
"unalias [alias name] Deletes the specified alias",
|
||||||
|
"wget [url] [target file] Retrieves code/text from a web server",
|
||||||
|
];
|
||||||
|
|
||||||
export const HelpTexts: IMap<string> = {
|
export const HelpTexts: IMap<string[]> = {
|
||||||
alias:
|
alias: [
|
||||||
'alias [-g] [name="value"] <br>' +
|
'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 " +
|
"Create or display aliases. An alias enables a replacement of a word with another string. ",
|
||||||
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, " +
|
"It can be used to abbreviate a commonly used command, or commonly used parts of a command. The NAME ",
|
||||||
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: <br><br>" +
|
"of an alias defines the word that will be replaced, while the VALUE defines what it will be replaced by. For example, ",
|
||||||
'alias nuke="run NUKE.exe"<br><br>' +
|
"you could create the alias 'nuke' for the Terminal command 'run NUKE.exe' using the following: ",
|
||||||
"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 " +
|
'alias nuke="run NUKE.exe"',
|
||||||
"example, if the following alias was set: <br><br>" +
|
" ",
|
||||||
'alias worm="HTTPWorm.exe"<br><br>' +
|
"Then, to run the NUKE.exe program you would just have to enter 'nuke' in Terminal rather than the full command. ",
|
||||||
"and then you tried to run the following terminal command: <br><br>" +
|
"It is important to note that 'default' aliases will only be substituted for the first word of a Terminal command. For ",
|
||||||
"run worm<br><br>" +
|
"example, if the following alias was set: ",
|
||||||
"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 worm="HTTPWorm.exe"',
|
||||||
'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>" +
|
"and then you tried to run the following 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. <br><br>" +
|
"run worm",
|
||||||
"The 'unalias' command can be used to remove aliases.<br><br>",
|
" ",
|
||||||
analyze:
|
"This would fail because the worm alias is not the first word of a Terminal command. To allow an alias to be substituted ",
|
||||||
"analze<br>" +
|
"anywhere in a Terminal command, rather than just the first word, you must set it to be a global alias using the -g flag: ",
|
||||||
"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 " +
|
'alias -g worm="HTTPWorm.exe"',
|
||||||
"hacking-related information such as an estimated chance to successfully hack, an estimate of how much money is " +
|
" ",
|
||||||
|
"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.",
|
"available on the server, etc.",
|
||||||
backdoor:
|
],
|
||||||
"backdoor<br>" +
|
backdoor: [
|
||||||
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.<br>" +
|
"backdoor",
|
||||||
"Requires root access to run.<br>",
|
" ",
|
||||||
buy:
|
"Install a backdoor on the current machine, grants a secret bonus depending on the machine.",
|
||||||
"buy [-l / program]<br>" +
|
" ",
|
||||||
"Purchase a program through the Dark Web. Requires a TOR router to use.<br><br>" +
|
"Requires root access to run.",
|
||||||
"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>" +
|
],
|
||||||
|
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.",
|
"Otherwise, the name of the program must be passed in as a parameter. This name is NOT case-sensitive.",
|
||||||
cat:
|
],
|
||||||
"cat [file]<br>" +
|
cat: [
|
||||||
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:<br><br>" +
|
"cat [file]",
|
||||||
"cat j1.msg<br>" +
|
" ",
|
||||||
"cat foo.lit<br>" +
|
"Display message (.msg), literature (.lit), or text (.txt) files. Examples:",
|
||||||
|
" ",
|
||||||
|
"cat j1.msg",
|
||||||
|
" ",
|
||||||
|
"cat foo.lit",
|
||||||
|
" ",
|
||||||
"cat servers.txt",
|
"cat servers.txt",
|
||||||
cd:
|
],
|
||||||
"cd [dir]<br>" +
|
cd: [
|
||||||
"Change to the specified directory. Note that this works even for directories that don't exist. If you " +
|
"cd [dir]",
|
||||||
"change to a directory that does not exist, it will not be 'created'. Examples:<br><br>" +
|
" ",
|
||||||
"cd scripts/hacking<br>" +
|
"Change to the specified directory. Note that this works even for directories that don't exist. If you ",
|
||||||
"cd /logs<br>" +
|
"change to a directory that does not exist, it will not be 'created'. Examples:",
|
||||||
|
" ",
|
||||||
|
"cd scripts/hacking",
|
||||||
|
" ",
|
||||||
|
"cd /logs",
|
||||||
|
" ",
|
||||||
"cd ../",
|
"cd ../",
|
||||||
check:
|
],
|
||||||
"check [script name] [args...]<br>" +
|
check: [
|
||||||
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by " +
|
"check [script name] [args...]",
|
||||||
"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>" +
|
"Print the logs of the script specified by the script name and arguments to the Terminal. Each argument must be separated by ",
|
||||||
"run foo.script 1 2 foodnstuff<br><br>" +
|
"a space. Remember that a running script is uniquely ",
|
||||||
"Then to run the 'check' command on this script you would have to pass the same arguments in: <br><br>" +
|
"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",
|
"check foo.script 1 2 foodnstuff",
|
||||||
clear:
|
],
|
||||||
"clear<br>" +
|
clear: [
|
||||||
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up " +
|
"clear",
|
||||||
|
" ",
|
||||||
|
"Clear the Terminal screen, deleting all of the text. Note that this does not delete the user's command history, so using the up ",
|
||||||
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'cls' command",
|
"and down arrow keys is still valid. Also note that this is permanent and there is no way to undo this. Synonymous with 'cls' command",
|
||||||
cls:
|
],
|
||||||
"cls<br>" +
|
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 " +
|
"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",
|
"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: [
|
||||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument " +
|
"connect [hostname/ip]",
|
||||||
"to this command. Note that only servers that are immediately adjacent to the current server in the network can be connected to. To " +
|
" ",
|
||||||
|
"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.",
|
"see which servers can be connected to, use the 'scan' command.",
|
||||||
download:
|
],
|
||||||
"download [script/text file]<br>" +
|
download: [
|
||||||
"Downloads a script or text file to your computer (like your real life computer).<br>" +
|
"download [script/text file]",
|
||||||
"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>" +
|
"Downloads a script or text file to your computer (like your real life computer).",
|
||||||
"Download all scripts: download *.script<br>" +
|
" ",
|
||||||
"Download all text files: download *.txt<br>",
|
"You can also download all of your scripts/text files as a zip file using the following Terminal commands:",
|
||||||
expr:
|
" ",
|
||||||
"expr [mathematical expression]<br>" +
|
"Download all scripts and text files: download *",
|
||||||
"Evaluate a simple mathematical expression. Supports native JavaScript operators:<br>" +
|
" ",
|
||||||
"+, -, /, *, **, %<br>" +
|
"Download all scripts: download *.script",
|
||||||
"Example:<br>" +
|
" ",
|
||||||
"expr 25 * 2 ** 10<br>" +
|
"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.",
|
"Note that letters (non-digits) are not allowed and will be removed from the input.",
|
||||||
free:
|
],
|
||||||
"free<br>" +
|
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 " +
|
"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.",
|
"how much of it is being used.",
|
||||||
hack:
|
],
|
||||||
"hack<br>" +
|
hack: [
|
||||||
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics<br>",
|
"hack",
|
||||||
help:
|
" ",
|
||||||
"help [command]<br>" +
|
"Attempt to hack the current server. Requires root access in order to be run. See the wiki page for hacking mechanics",
|
||||||
"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: [
|
||||||
"help alias<br>" +
|
"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",
|
"help scan-analyze",
|
||||||
home:
|
],
|
||||||
"home<br>" + "Connect to your home computer. This will work no matter what server you are currently connected to.",
|
home: [
|
||||||
hostname: "hostname<br>" + "Prints the hostname of the current server",
|
"home" + "Connect to your home computer. This will work no matter what server you are currently connected to.",
|
||||||
ifconfig: "ipconfig<br>" + "Prints the IP address of the current server",
|
],
|
||||||
kill:
|
hostname: ["hostname", " ", "Prints the hostname of the current server"],
|
||||||
"kill [script name] [args...]<br>" +
|
ifconfig: ["ipconfig", " ", "Prints the IP address of the current server"],
|
||||||
"kill [pid]<br>" +
|
kill: [
|
||||||
"Kill the script specified by the script name and arguments OR by its PID.<br><br>" +
|
"kill [script name] [args...]",
|
||||||
"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 " +
|
"kill [pid]",
|
||||||
"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>" +
|
"Kill the script specified by the script name and arguments OR by its PID.",
|
||||||
"run foo.script 1 sigma-cosmetics<br><br>" +
|
" ",
|
||||||
"Then to kill this script the same arguments would have to be used:<br><br>" +
|
"If you are killing the script using its filename and arguments, then each ",
|
||||||
"kill foo.script 1 sigma-cosmetics<br><br>" +
|
"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",
|
"If you are killing the script using its PID, then the PID argument must be numeric",
|
||||||
killall:
|
],
|
||||||
"killall<br>" +
|
killall: [
|
||||||
"Kills all scripts on the current server. " +
|
"killall",
|
||||||
"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. " +
|
"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.",
|
"The script will not be stopped/killed until after that time has elapsed.",
|
||||||
ls:
|
],
|
||||||
"ls [dir] [| grep pattern]<br>" +
|
ls: [
|
||||||
"The ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. " +
|
"ls [dir] [| grep pattern]",
|
||||||
"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 ls command, with no arguments, prints all files and directories on the current server's directory to the Terminal screen. ",
|
||||||
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern.<br><br>" +
|
"The files will be displayed in alphabetical order. ",
|
||||||
"Examples:<br><br>" +
|
" ",
|
||||||
"List all files with the '.script' extension in the current directory:<br>" +
|
"The 'dir' optional parameter can be used to display files/directories in another directory.",
|
||||||
"ls | grep .script<br><br>" +
|
" ",
|
||||||
"List all files with the '.js' extension in the root directory:<br>" +
|
"The '| grep pattern' optional parameter can be used to only display files whose filenames match the specified pattern.",
|
||||||
"ls / | grep .js<br><br>" +
|
" ",
|
||||||
"List all files with the word 'purchase' in the filename, in the 'scripts' directory:<br>" +
|
"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",
|
"ls scripts | grep purchase",
|
||||||
lscpu: "lscpu<br>" + "Prints the number of CPU Cores the current server has",
|
],
|
||||||
mem:
|
lscpu: ["lscpu", " ", "Prints the number of CPU Cores the current server has"],
|
||||||
"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 " +
|
mem: [
|
||||||
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then " +
|
"mem [script name] [-t] [num threads]",
|
||||||
"an argument for the number of threads must be passed in afterwards. Examples:<br><br>" +
|
" ",
|
||||||
"mem foo.script<br>" +
|
"Displays the amount of RAM needed to run the specified script with a single thread. The command can also be used to print ",
|
||||||
"mem foo.script -t 50<br>" +
|
"the amount of RAM needed to run a script with multiple threads using the '-t' flag. If the '-t' flag is specified, then ",
|
||||||
"The first example above will print the amount of RAM needed to run 'foo.script' with a single thread. The second example " +
|
"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.",
|
"above will print the amount of RAM needed to run 'foo.script' with 50 threads.",
|
||||||
mv:
|
],
|
||||||
"mv [src] [dest]<br>" +
|
mv: [
|
||||||
"Move the source file to the specified destination. This can also be used to rename files. " +
|
"mv [src] [dest]",
|
||||||
"This command only works for scripts and text files (.txt). This command CANNOT be used to " +
|
" ",
|
||||||
"convert to different file types<br><br>" +
|
"Move the source file to the specified destination. This can also be used to rename files. ",
|
||||||
"Note that, unlike the Linux 'mv' command, the destination argument must be the " +
|
"This command only works for scripts and text files (.txt). This command CANNOT be used to ",
|
||||||
"full filepath. " +
|
"convert to different file types",
|
||||||
"Examples: <br><br>" +
|
" ",
|
||||||
"mv hacking-controller.script scripts/hacking-controller.script<br>" +
|
"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",
|
"mv myScript.js myOldScript.js",
|
||||||
nano:
|
],
|
||||||
"nano [file name]<br>" +
|
nano: [
|
||||||
"Opens up the specified file in the Text Editor. Only scripts (.script) or text files (.txt) can be " +
|
"nano [file name]",
|
||||||
"edited using the Text Editor. If the file does not already exist, then a new, empty one " +
|
" ",
|
||||||
|
"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",
|
"will be created",
|
||||||
ps: "ps<br>" + "Prints all scripts that are running on the current server",
|
],
|
||||||
rm:
|
ps: ["ps", " ", "Prints all scripts that are running on the current server"],
|
||||||
"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>" +
|
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",
|
"WARNING: This is permanent and cannot be undone",
|
||||||
run:
|
],
|
||||||
"run [file name] [-t] [num threads] [args...]<br>" +
|
run: [
|
||||||
"Execute a program or a script.<br><br>" +
|
"run [file name] [-t] [num threads] [args...]",
|
||||||
"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, " +
|
"Execute a program or a script.",
|
||||||
"then the script will be run with a single thread by default. " +
|
" ",
|
||||||
"If the '-t' flag is used, then it MUST come immediately " +
|
"The '[-t]', '[num threads]', and '[args...]' arguments are only valid when running a script. The '-t' flag is used ",
|
||||||
"after the script name, and the [num threads] argument MUST come immediately afterwards. <br><br>" +
|
"to indicate that the script should be run with the specified number of threads. If the flag is omitted, ",
|
||||||
"[args...] represents a variable number of arguments that will be passed into the script. See the documentation " +
|
"then the script will be run with a single thread by default. ",
|
||||||
"about script arguments. Each specified argument must be separated by a space. <br><br>",
|
"If the '-t' flag is used, then it MUST come immediately ",
|
||||||
scan:
|
"after the script name, and the [num threads] argument MUST come immediately afterwards. ",
|
||||||
"scan<br>" +
|
" ",
|
||||||
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect " +
|
"[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.",
|
"to using the 'connect' Terminal command.",
|
||||||
"scan-analyze":
|
],
|
||||||
"scan-analyze [depth] [-a]<br>" +
|
"scan-analyze": [
|
||||||
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling " +
|
"scan-analyze [depth] [-a]",
|
||||||
"'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>" +
|
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling ",
|
||||||
"By default, the maximum depth that can be specified for 'scan-analyze' is 3. However, once you have " +
|
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal ",
|
||||||
"the DeepscanV1.exe and DeepscanV2.exe programs, you can execute 'scan-analyze' with a depth up to " +
|
"command. This command also shows the relative paths to reach each server.",
|
||||||
"5 and 10, respectively.<br><br>" +
|
" ",
|
||||||
"The information 'scan-analyze' displays about each server includes whether or not you have root access to it, " +
|
"By default, the maximum depth that can be specified for 'scan-analyze' is 3. However, once you have ",
|
||||||
"its required hacking level, the number of open ports required to run NUKE.exe on it, and how much RAM " +
|
"the DeepscanV1.exe and DeepscanV2.exe programs, you can execute 'scan-analyze' with a depth up to ",
|
||||||
"it has.<br><br>" +
|
"5 and 10, respectively.",
|
||||||
"By default, this command will not display servers that you have purchased. However, you can pass in the " +
|
" ",
|
||||||
|
"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.",
|
"-a flag at the end of the command if you would like to enable that.",
|
||||||
scp:
|
],
|
||||||
"scp [filename] [target server]<br>" +
|
scp: [
|
||||||
"Copies the specified file from the current server to the target server. " +
|
"scp [filename] [target server]",
|
||||||
"This command only works for script files (.script extension), literature files (.lit extension), " +
|
" ",
|
||||||
"and text files (.txt extension). " +
|
"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.",
|
"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:
|
sudov: ["sudov", " ", "Prints whether or not you have root access to the current machine"],
|
||||||
"tail [script name] [args...]<br>" +
|
|
||||||
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated " +
|
tail: [
|
||||||
"by a space. Remember that a running script is uniquely identified by both its name and the arguments that were used " +
|
"tail [script name] [args...]",
|
||||||
"to run it. So, if a script was ran with the following arguments: <br><br>" +
|
" ",
|
||||||
"run foo.script 10 50000<br><br>" +
|
"Displays dynamic logs for the script specified by the script name and arguments. Each argument must be separated ",
|
||||||
"Then in order to check its logs with 'tail' the same arguments must be used: <br><br>" +
|
"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",
|
"tail foo.script 10 50000",
|
||||||
theme:
|
],
|
||||||
"theme [preset] | [#background #text #highlight]<br>" +
|
theme: [
|
||||||
"Change the color of the game's user interface<br><br>" +
|
"theme [preset] | [#background #text #highlight]",
|
||||||
"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 " +
|
"Change the color of the game's user interface",
|
||||||
"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>" +
|
"This command can be called with a preset theme. Currently, the supported presets are 'default', 'muted', and 'solarized'. ",
|
||||||
"theme #ffffff #385 #235012<br><br>" +
|
"However, you can also specify your own color scheme using hex values. To do so, you must specify three hex color values ",
|
||||||
"A color picker such as " +
|
"for the background color, the text color, and the highlight color. These hex values must be preceded by a pound sign (#) and ",
|
||||||
"<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> " +
|
"must be either 3 or 6 digits. Example:",
|
||||||
"can be used to get your desired hex color values<br><br>" +
|
" ",
|
||||||
|
"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.",
|
"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>" +
|
top: [
|
||||||
"Prints a list of all scripts running on the current server as well as their thread count and how much " +
|
"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.",
|
"RAM they are using in total.",
|
||||||
unalias:
|
],
|
||||||
"unalias [alias name]<br>" +
|
unalias: [
|
||||||
"Deletes the specified alias. Note that the double quotation marks are required. <br><br>" +
|
"unalias [alias name]",
|
||||||
"As an example, if an alias was declared using:<br><br>" +
|
" ",
|
||||||
'alias r="run"<br><br>' +
|
"Deletes the specified alias. Note that the double quotation marks are required. ",
|
||||||
"Then it could be removed using:<br><br>" +
|
" ",
|
||||||
"unalias r<br><br>" +
|
"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'",
|
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
||||||
wget:
|
],
|
||||||
"wget [url] [target file]<br>" +
|
wget: [
|
||||||
"Retrieves data from a URL and downloads it to a file on the current server. The data can only " +
|
"wget [url] [target file]",
|
||||||
"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>" +
|
"Retrieves data from a URL and downloads it to a file on the current server. The data can only ",
|
||||||
"Note that it will not be possible to download data from many websites because they do not allow " +
|
"be downloaded to a script (.script, .ns, .js) or a text file (.txt). If the file already exists, ",
|
||||||
"cross-origin resource sharing (CORS). Example:<br><br>" +
|
"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",
|
"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