mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-11 10:13:52 +01:00
commit
e379288536
@ -1,129 +0,0 @@
|
||||
@import "theme";
|
||||
|
||||
.active-scripts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.active-scripts-container {
|
||||
> p {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
> pre {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: $defaultFontSize * 1.25;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
content: "\02795"; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-header.active {
|
||||
&:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none;
|
||||
|
||||
div,
|
||||
ul,
|
||||
ul > li {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
border: none;
|
||||
color: var(--my-font-color);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 4px 25px 4px 10px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: auto;
|
||||
|
||||
&:after {
|
||||
content: "\02795"; /* "plus" sign (+) */
|
||||
font-size: $defaultFontSize * 0.8125;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&.active:after {
|
||||
content: "\2796"; /* "minus" sign (-) */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.active-scripts-script-panel {
|
||||
background-color: #555;
|
||||
display: none;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
padding: 0 18px;
|
||||
width: auto;
|
||||
|
||||
pre,
|
||||
h2,
|
||||
ul,
|
||||
li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%;
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
.augmentations-content {
|
||||
> p {
|
||||
font-size: $defaultFontSize * 0.875;
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
.hacknet-general-info {
|
||||
margin: 10px;
|
||||
width: 70vw;
|
||||
}
|
||||
|
||||
#hacknet-nodes-container li {
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
.loaderoverlay {
|
||||
$spinnerBoxSize: 200px;
|
||||
$themeColor: #6f3;
|
||||
$themeColor: #0c0;
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
@ -4,7 +4,7 @@
|
||||
@import "reset";
|
||||
|
||||
:root {
|
||||
--my-font-color: #6f3;
|
||||
--my-font-color: #0c0;
|
||||
--my-background-color: #000;
|
||||
--my-highlight-color: #fff;
|
||||
--my-prompt-color: #f92672;
|
||||
@ -331,7 +331,7 @@ a:visited {
|
||||
|
||||
#status-text-container {
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
@import "theme";
|
||||
|
||||
#terminal-container {
|
||||
height: 100%;
|
||||
width: 99%;
|
||||
overflow: auto;
|
||||
overflow-y: scroll;
|
||||
|
||||
scrollbar-width: "none"; // firefox
|
||||
}
|
||||
|
||||
#terminal-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
padding-top: 10px;
|
||||
padding-left: 10px;
|
||||
height: auto;
|
||||
width: 70%;
|
||||
font-size: $defaultFontSize;
|
||||
overflow: auto;
|
||||
overflow-y: scroll;
|
||||
background-color: var(--my-background-color);
|
||||
table-layout: fixed;
|
||||
|
||||
.prompt {
|
||||
color: var(--my-prompt-color);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#terminal-input {
|
||||
background-color: var(--my-background-color);
|
||||
color: var(--my-font-color);
|
||||
transition: height 1s;
|
||||
}
|
||||
|
||||
.terminal-input {
|
||||
display: inline-block;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
border: 0;
|
||||
background-color: var(--my-background-color);
|
||||
font-size: $defaultFontSize;
|
||||
outline: none;
|
||||
color: var(--my-font-color);
|
||||
}
|
||||
|
||||
.terminal-line {
|
||||
width: 70%;
|
||||
word-wrap: break-word;
|
||||
hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
}
|
||||
|
||||
#terminal-input-td {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#terminal-input-td textarea {
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#terminal-input-header {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#terminal-input-text-box {
|
||||
margin-left: 2px;
|
||||
flex: 1 1 auto;
|
||||
}
|
@ -4,5 +4,7 @@
|
||||
"trashAssetsBeforeRuns": true,
|
||||
"screenshotsFolder": ".cypress/screenshots",
|
||||
"videosFolder": ".cypress/videos",
|
||||
"videoUploadOnPasses": false
|
||||
"videoUploadOnPasses": false,
|
||||
"viewportWidth": 1980,
|
||||
"viewportHeight": 1080
|
||||
}
|
||||
|
73
cypress/integration/naviguation.spec.ts
Normal file
73
cypress/integration/naviguation.spec.ts
Normal file
@ -0,0 +1,73 @@
|
||||
export {};
|
||||
|
||||
describe("netscript", () => {
|
||||
it("Do naviguation", () => {
|
||||
cy.findByRole("button", { name: "SKIP TUTORIAL" }).click();
|
||||
cy.findByText("Got it!").click();
|
||||
|
||||
cy.findByText("Dev").click();
|
||||
cy.findByText(/Source-Files/i).click();
|
||||
cy.findByLabelText(/all-sf-3/i).click();
|
||||
cy.findByText(/Experience/i).click();
|
||||
cy.findByText(/Tons of exp/i).click();
|
||||
cy.findByText(/General/i).click();
|
||||
cy.findByText(/Hack w0/i).click();
|
||||
cy.findByText(/SEMPOOL INVALID/i);
|
||||
cy.findByText(/Many decades/i, { timeout: 15000 });
|
||||
cy.findByLabelText("enter-bitnode-1").click();
|
||||
cy.findByText(/Enter BN1.2/i).click();
|
||||
|
||||
cy.get("body").type("{esc}");
|
||||
|
||||
cy.findByText("Dev").click();
|
||||
cy.findByText(/Experience/i).click();
|
||||
cy.findByText(/Tons of exp/i).click();
|
||||
|
||||
cy.findByText("Create Script").click();
|
||||
cy.findByText(/Script name:/i);
|
||||
|
||||
cy.findByText("Active Scripts").click();
|
||||
cy.findByText(/Total online production of/i);
|
||||
|
||||
cy.findByText("Create Program").click();
|
||||
cy.findByText(/This page displays/i);
|
||||
|
||||
cy.findByText("Stats").click();
|
||||
cy.findByText(/Current City:/i);
|
||||
|
||||
cy.findByText("Factions").click();
|
||||
cy.findByText(/Lists all/i);
|
||||
|
||||
cy.findByText("Augmentations").click();
|
||||
cy.findByText(/Purchased Augmentations/i);
|
||||
|
||||
cy.findByText("Hacknet").click();
|
||||
cy.findByText(/The Hacknet is a global/i);
|
||||
|
||||
cy.findByText("Sleeves").click();
|
||||
cy.findByText(/Duplicate Sleeves are MK/i);
|
||||
|
||||
cy.findByText("City").click();
|
||||
cy.findByText(/Sector-12/i);
|
||||
cy.findByLabelText("The Slums").click();
|
||||
cy.findByText("City").click();
|
||||
cy.findByLabelText("Powerhouse Gym").click();
|
||||
cy.findByText("City").click();
|
||||
cy.findByLabelText("MegaCorp").click();
|
||||
|
||||
cy.findByText("Travel").click();
|
||||
cy.findByText(/Travel Agency/i);
|
||||
|
||||
cy.findByText("Stock Market").click();
|
||||
cy.findByText(/ECorp/i);
|
||||
|
||||
cy.findByText("Milestones").click();
|
||||
cy.findByText(/don't reward you for/i);
|
||||
|
||||
cy.findByText("Tutorial").click();
|
||||
cy.findByText(/AKA Links to/i);
|
||||
|
||||
cy.findByText("Options").click();
|
||||
cy.findByText(/Netscript exec time/i);
|
||||
});
|
||||
});
|
@ -2,7 +2,7 @@ export {};
|
||||
|
||||
describe("netscript", () => {
|
||||
it("creates and runs a NetScript 2.0 script", () => {
|
||||
cy.findByRole("button", { name: "Exit Tutorial" }).click();
|
||||
cy.findByRole("button", { name: "SKIP TUTORIAL" }).click();
|
||||
cy.findByText("Got it!").click();
|
||||
|
||||
cy.findByRole("textbox").type("connect n00dles{enter}");
|
||||
@ -32,7 +32,7 @@ describe("netscript", () => {
|
||||
});
|
||||
|
||||
it("errors and shows a dialog box when static RAM !== dynamic RAM", () => {
|
||||
cy.findByRole("button", { name: "Exit Tutorial" }).click();
|
||||
cy.findByRole("button", { name: "SKIP TUTORIAL" }).click();
|
||||
cy.findByText("Got it!").click();
|
||||
|
||||
cy.findByRole("textbox").type("nano script.js{enter}");
|
||||
|
@ -3,19 +3,19 @@ export {};
|
||||
describe("tutorial", () => {
|
||||
it("completes the tutorial", () => {
|
||||
cy.findByText(/dark, dystopian future/);
|
||||
cy.findByRole("button", { name: "Next" }).click();
|
||||
cy.findByRole("button", { name: "next" }).click();
|
||||
|
||||
cy.findByText(/heading to the Stats page/);
|
||||
cy.findByRole("button", { name: "Stats" }).click();
|
||||
|
||||
cy.findByText(/lot of important information/);
|
||||
cy.findByRole("button", { name: "Next" }).click();
|
||||
cy.findByRole("button", { name: "next" }).click();
|
||||
|
||||
cy.findByText(/head to your computer's terminal/);
|
||||
cy.findByRole("button", { name: "Terminal" }).click();
|
||||
|
||||
cy.findByText(/is used to interface/);
|
||||
cy.findByRole("button", { name: "Next" }).click();
|
||||
cy.findByRole("button", { name: "next" }).click();
|
||||
|
||||
cy.findByText(/Let's try it out/i);
|
||||
cy.findByRole("textbox").type("help{enter}");
|
||||
@ -29,7 +29,7 @@ describe("tutorial", () => {
|
||||
cy.findByText(/that's great and all/i);
|
||||
cy.findByRole("textbox").type("scan-analyze{enter}");
|
||||
|
||||
cy.findByText(/this command shows more detailed information/i);
|
||||
cy.findByText(/shows more detailed information/i);
|
||||
cy.findByRole("textbox").type("scan-analyze 2{enter}");
|
||||
|
||||
cy.findByText(/now you can see information/i);
|
||||
@ -46,10 +46,11 @@ describe("tutorial", () => {
|
||||
cy.findByRole("textbox").type("hack{enter}");
|
||||
|
||||
cy.findByText(/now attempting to hack the server/i);
|
||||
cy.findByRole("button", { name: "Next" }).click();
|
||||
cy.findByRole("button", { name: "next" }).click();
|
||||
|
||||
cy.findByText(/hacking exp/i);
|
||||
cy.findByRole("textbox", { timeout: 15_000 }).should("not.be.disabled").type("nano n00dles.script{enter}");
|
||||
cy.findByRole("textbox", { timeout: 15_000 }).should("not.be.disabled").type("home{enter}");
|
||||
|
||||
cy.findByRole("textbox").type("nano n00dles.script{enter}");
|
||||
|
||||
// monaco can take a bit
|
||||
cy.findByRole("code", { timeout: 15_000 }).type("{selectall}{del}").type("while(true) {{}{enter}hack('n00dles');");
|
||||
@ -59,7 +60,7 @@ describe("tutorial", () => {
|
||||
cy.findByText(/now we'll run the script/i);
|
||||
cy.findByRole("textbox").type("free{enter}");
|
||||
|
||||
cy.findByText(/We have 4GB of free RAM on this machine/i);
|
||||
cy.findByText(/We have 8GB of free RAM on this machine/i);
|
||||
cy.findByRole("textbox").type("run n00dles.script{enter}");
|
||||
|
||||
cy.findByText(/Your script is now running/i);
|
||||
@ -72,7 +73,7 @@ describe("tutorial", () => {
|
||||
cy.findByRole("textbox").type("tail n00dles.script{enter}");
|
||||
|
||||
cy.findByText(/The log for this script won't show much/i);
|
||||
cy.findByRole("button", { name: "Next" }).click();
|
||||
cy.findByRole("button", { name: "next" }).click();
|
||||
|
||||
cy.findByText(/Hacking is not the only way to earn money/i);
|
||||
cy.findByRole("button", { name: "Hacknet" }).click();
|
||||
@ -87,7 +88,7 @@ describe("tutorial", () => {
|
||||
cy.findByRole("button", { name: "Tutorial" }).click();
|
||||
|
||||
cy.findByText(/a lot of different documentation about the game/i);
|
||||
cy.findByRole("button", { name: "Finish Tutorial" }).click();
|
||||
cy.findByRole("button", { name: "FINISH TUTORIAL" }).click();
|
||||
cy.findByText("Got it!").click();
|
||||
|
||||
cy.findByText(/Tutorial \(AKA Links to Documentation\)/i);
|
||||
|
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([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){}});
|
||||
!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([1281,0]),o()}({1281:function(n,t,o){"use strict";o.r(t);o(1282),o(1284),o(1286),o(1288),o(1290),o(1292),o(1294),o(1296),o(1298),o(1300),o(1302),o(1304),o(1306),o(1308),o(1310),o(1312),o(1314),o(1316),o(1318),o(1320),o(1322),o(1324),o(1326),o(1328),o(1330),o(1332),o(1334),o(1336),o(1338),o(1340)},1284:function(n,t,o){},1286:function(n,t,o){},1288:function(n,t,o){},1290:function(n,t,o){},1292:function(n,t,o){},1294:function(n,t,o){},1296:function(n,t,o){},1298:function(n,t,o){},1300:function(n,t,o){},1302:function(n,t,o){},1304:function(n,t,o){},1306:function(n,t,o){},1308:function(n,t,o){},1310:function(n,t,o){},1312:function(n,t,o){},1314:function(n,t,o){},1316:function(n,t,o){},1318:function(n,t,o){},1320:function(n,t,o){},1322:function(n,t,o){},1324:function(n,t,o){},1326:function(n,t,o){},1328:function(n,t,o){},1330:function(n,t,o){},1332:function(n,t,o){},1334:function(n,t,o){},1336:function(n,t,o){},1338:function(n,t,o){},1340:function(n,t,o){}});
|
||||
//# sourceMappingURL=engineStyle.bundle.js.map
|
119
dist/engineStyle.css
vendored
119
dist/engineStyle.css
vendored
@ -15,7 +15,7 @@
|
||||
vertical-align: middle; }
|
||||
|
||||
:root {
|
||||
--my-font-color: #6f3;
|
||||
--my-font-color: #0c0;
|
||||
--my-background-color: #000;
|
||||
--my-highlight-color: #fff;
|
||||
--my-prompt-color: #f92672; }
|
||||
@ -573,7 +573,7 @@ input[type="checkbox"] {
|
||||
vertical-align: middle; }
|
||||
|
||||
:root {
|
||||
--my-font-color: #6f3;
|
||||
--my-font-color: #0c0;
|
||||
--my-background-color: #000;
|
||||
--my-highlight-color: #fff;
|
||||
--my-prompt-color: #f92672; }
|
||||
@ -1374,115 +1374,13 @@ button {
|
||||
align-items: center;
|
||||
justify-content: start; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
.active-scripts-list {
|
||||
list-style-type: none; }
|
||||
|
||||
.active-scripts-container > p {
|
||||
width: 70%;
|
||||
margin: 6px;
|
||||
padding: 4px; }
|
||||
|
||||
.active-scripts-container .accordion-header > pre {
|
||||
color: white; }
|
||||
|
||||
.active-scripts-server-header {
|
||||
background-color: #444;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
margin: 6px 6px 0 6px;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
border: none;
|
||||
outline: none; }
|
||||
.active-scripts-server-header:after {
|
||||
content: "\2795";
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
.active-scripts-server-header.active, .active-scripts-server-header:hover {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-server-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
float: right;
|
||||
margin-left: 5px; }
|
||||
|
||||
.active-scripts-server-header.active:hover {
|
||||
background-color: #666; }
|
||||
|
||||
.active-scripts-server-panel {
|
||||
margin: 0 6px 6px 6px;
|
||||
padding: 0 6px 6px 6px;
|
||||
width: 55%;
|
||||
margin-left: 5%;
|
||||
display: none; }
|
||||
.active-scripts-server-panel div,
|
||||
.active-scripts-server-panel ul,
|
||||
.active-scripts-server-panel ul > li {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-header {
|
||||
background-color: #555;
|
||||
border: none;
|
||||
color: var(--my-font-color);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 4px 25px 4px 10px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: auto; }
|
||||
.active-scripts-script-header:after {
|
||||
content: "\2795";
|
||||
/* "plus" sign (+) */
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 var(--my-font-color);
|
||||
position: absolute;
|
||||
bottom: 4px; }
|
||||
.active-scripts-script-header.active:after {
|
||||
content: "\2796";
|
||||
/* "minus" sign (-) */ }
|
||||
.active-scripts-script-header:hover, .active-scripts-script-header.active:hover {
|
||||
background-color: #666; }
|
||||
.active-scripts-script-header.active {
|
||||
background-color: #555; }
|
||||
|
||||
.active-scripts-script-panel {
|
||||
background-color: #555;
|
||||
display: none;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
padding: 0 18px;
|
||||
width: auto; }
|
||||
.active-scripts-script-panel pre,
|
||||
.active-scripts-script-panel h2,
|
||||
.active-scripts-script-panel ul,
|
||||
.active-scripts-script-panel li {
|
||||
background-color: #555;
|
||||
width: auto;
|
||||
color: #fff;
|
||||
margin-left: 5%; }
|
||||
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
/**
|
||||
* Styling for the Hacknet Nodes UI Page
|
||||
*/
|
||||
.hacknet-general-info {
|
||||
margin: 10px;
|
||||
width: 70vw; }
|
||||
margin: 10px; }
|
||||
|
||||
#hacknet-nodes-container li {
|
||||
float: left;
|
||||
@ -1650,8 +1548,7 @@ button {
|
||||
/* COLORS */
|
||||
/* Attributes */
|
||||
.augmentations-content > p {
|
||||
font-size: 14px;
|
||||
width: 70%; }
|
||||
font-size: 14px; }
|
||||
|
||||
.augmentations-list button,
|
||||
.augmentations-list div {
|
||||
@ -1824,7 +1721,7 @@ button {
|
||||
vertical-align: middle; }
|
||||
|
||||
:root {
|
||||
--my-font-color: #6f3;
|
||||
--my-font-color: #0c0;
|
||||
--my-background-color: #000;
|
||||
--my-highlight-color: #fff;
|
||||
--my-prompt-color: #f92672; }
|
||||
@ -2691,11 +2588,11 @@ input[type="checkbox"] {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
color: #6f3; }
|
||||
color: #0c0; }
|
||||
.loaderoverlay .loaderspinner, .loaderoverlay .loaderspinner:before, .loaderoverlay .loaderspinner:after {
|
||||
border: 20px solid rgba(0, 0, 0, 0);
|
||||
border-top-color: #6f3;
|
||||
border-bottom-color: #6f3;
|
||||
border-top-color: #0c0;
|
||||
border-bottom-color: #0c0;
|
||||
border-radius: 1000px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
81
dist/vendor.bundle.js
vendored
81
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -3,6 +3,50 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v0.54.0 - 2021-09-20 One big react node (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
** UI **
|
||||
|
||||
* The UI is now completely(ish) in react and I'm starting to implement
|
||||
Material-UI everywhere. This will help make the game feel more consistent.
|
||||
* Major help from (@threehams)
|
||||
* New Terminal
|
||||
* New Active Scripts page
|
||||
* New sidebar.
|
||||
* New Character overview
|
||||
* New tutorial
|
||||
* New options page
|
||||
* New create program page (@Nolshine)
|
||||
|
||||
** Netscript **
|
||||
|
||||
* Add companyName to getPlayer
|
||||
|
||||
** Factions **
|
||||
|
||||
* Megacorp factions are no longer removed when installing.
|
||||
|
||||
** Corporation **
|
||||
|
||||
* All research tooltips are always visible.
|
||||
* Smart supply is enabled by default if purchased (@Nolshine)
|
||||
|
||||
** Misc. **
|
||||
|
||||
* Fix "Game saved" animation. (@Nolshine)
|
||||
* Update commitCrime documentation (@Tryneus)
|
||||
* Fix logbox scrolling weird (@Nolshine)
|
||||
* Fix weird scrolling in corporations (@BartKoppelmans)
|
||||
* Fix typo (@BartKoppelmans & @Nolshine)
|
||||
* Delete game now has a confirmation modal (@Nolshine)
|
||||
* Fix issue where skills would not get properly updated when entering new
|
||||
BN. (@Nolshine)
|
||||
* Convert create gang to popup (@vmesecher)
|
||||
* Fixed a bug that prevented travel to Sector-12 and New Tokyo when not using
|
||||
ASCII art.
|
||||
* nerf noodle bar
|
||||
|
||||
v0.53.0 - 2021-09-09 Way too many things. (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
|
@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.53'
|
||||
version = '0.54'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.53.0'
|
||||
release = '0.54.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -117,30 +117,6 @@ that are loaded.
|
||||
Examples
|
||||
--------
|
||||
|
||||
**DOM Manipulation (tprintColored.ns)**
|
||||
|
||||
Directly alter the game's terminal and print colored text::
|
||||
|
||||
export function tprintColored(txt, color) {
|
||||
let terminalInput = document.getElementById("terminal-input");
|
||||
let rowElement = document.createElement("tr");
|
||||
let cellElement = document.createElement("td");
|
||||
|
||||
rowElement.classList.add("posted");
|
||||
cellElement.classList.add("terminal-line");
|
||||
cellElement.style.color = color;
|
||||
cellElement.innerText = txt;
|
||||
|
||||
rowElement.appendChild(cellElement);
|
||||
terminalInput.before(rowElement);
|
||||
}
|
||||
|
||||
export async function main(ns) {
|
||||
tprintColored("Red Text!", "red");
|
||||
tprintColored("Blue Text!", "blue");
|
||||
tprintColored("Use Hex Codes!", "#3087E3");
|
||||
}
|
||||
|
||||
**Script Scheduler (scriptScheduler.ns)**
|
||||
|
||||
This script shows some of the new functionality that is available in NetscriptJS,
|
||||
|
@ -26,8 +26,8 @@ commitCrime() Netscript Function
|
||||
This function is used to automatically attempt to commit crimes. If you are already in the middle of some 'working' action
|
||||
(such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings.
|
||||
|
||||
This function returns the number of seconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the 'Rob Store' crime,
|
||||
so running ``commitCrime('rob store')`` will return 60).
|
||||
This function returns the number of milliseconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the 'Rob Store' crime,
|
||||
so running ``commitCrime('rob store')`` will return 60000).
|
||||
|
||||
Warning: I do not recommend using the time returned from this function to try and schedule your crime attempts.
|
||||
Instead, I would use the :doc:`isBusy<isBusy>` Singularity function to check whether you have finished attempting a crime.
|
||||
|
69
index.html
69
index.html
@ -36,46 +36,10 @@
|
||||
ga("send", "pageview");
|
||||
</script>
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico"><link href="dist/vendor.css" rel="stylesheet"><link href="dist/engineStyle.css" rel="stylesheet"></head>
|
||||
<link rel="shortcut icon" href="favicon.ico"><link href="dist/vendor.css" rel="stylesheet"><link href="main.css" rel="stylesheet"></head>
|
||||
<body>
|
||||
<div id="entire-game-container" style="visibility: hidden">
|
||||
<div id="mainmenu-container" style="display: flex; flex-direction: row">
|
||||
<!-- Main menu -->
|
||||
<div id="sidebar" style=""></div>
|
||||
<div id="generic-react-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="infiltration-container" class="generic-fullscreen-container"></div>
|
||||
<div id="mission-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Work in progress screen -->
|
||||
<div id="work-in-progress-container" class="generic-fullscreen-container">
|
||||
<p id="work-in-progress-text"></p>
|
||||
|
||||
<button id="work-in-progress-cancel-button" class="work-button">Cancel Work</button>
|
||||
<button id="work-in-progress-something-else-button" class="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Red Pill Container -->
|
||||
<div id="red-pill-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Cinematic Text Container -->
|
||||
<div id="cinematic-text-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Interactive Tutorial Text Screen -->
|
||||
<div id="interactive-tutorial-wrapper">
|
||||
<div id="interactive-tutorial-container">
|
||||
<p id="interactive-tutorial-text"></p>
|
||||
<button id="interactive-tutorial-exit">Exit Tutorial</button>
|
||||
<button id="interactive-tutorial-next">Next</button>
|
||||
<button id="interactive-tutorial-back">Back</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Character Overview Screen -->
|
||||
<div id="character-overview"></div>
|
||||
<div id="entire-game-container">
|
||||
<div id="mainmenu-container" style="display: flex; flex-direction: row"></div>
|
||||
|
||||
<!-- Status text -->
|
||||
<div id="status-text-container">
|
||||
@ -83,33 +47,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="file" id="import-game-file-selector" name="file"/>
|
||||
|
||||
<!-- Loader (Loading screen) -->
|
||||
<div id="loader" class="loaderoverlay">
|
||||
<div class="loaderspinner"></div>
|
||||
<div class="loaderlabel">Loading Bitburner...</div>
|
||||
<div id="killAllMessageWrapper" class="killAllMessage killAllMessageWrapperHidden">
|
||||
<script>
|
||||
setTimeout(function () {
|
||||
var w = document.getElementById("killAllMessageWrapper");
|
||||
if (w == null) {
|
||||
return;
|
||||
}
|
||||
w.classList.remove("killAllMessageWrapperHidden");
|
||||
w.classList.add("killAllMessageWrapperShow");
|
||||
}, 2000);
|
||||
</script>
|
||||
<p>
|
||||
If the game fails to load, consider
|
||||
<a href="?noScripts">killing all scripts</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="unclickable" style="display: none">Click on this to upgrade your Source-File -1!</div>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/engine.bundle.js"></script><script type="text/javascript" src="dist/engineStyle.bundle.js"></script></body>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body>
|
||||
|
||||
<!-- Misc Scripts -->
|
||||
<script src="src/ThirdParty/raphael.min.js"></script>
|
||||
</html>
|
||||
|
20
main.bundle.js
Normal file
20
main.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
main.bundle.js.map
Normal file
1
main.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
1
main.css.map
Normal file
1
main.css.map
Normal file
File diff suppressed because one or more lines are too long
540
package-lock.json
generated
540
package-lock.json
generated
@ -64,6 +64,7 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
|
||||
"@testing-library/cypress": "^8.0.1",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jest": "^27.0.1",
|
||||
@ -102,6 +103,7 @@
|
||||
"null-loader": "^1.0.0",
|
||||
"prettier": "^2.3.2",
|
||||
"raw-loader": "~0.5.0",
|
||||
"react-refresh": "^0.10.0",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"sass-loader": "^7.0.3",
|
||||
"script-loader": "~0.7.0",
|
||||
@ -2465,6 +2467,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@hapi/hoek": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz",
|
||||
@ -3914,6 +3925,240 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.1.tgz",
|
||||
"integrity": "sha512-ccap6o7+y5L8cnvkZ9h8UXCGyy2DqtwCD+/N3Yru6lxMvcdkPKtdx13qd7sAC9s5qZktOmWf9lfUjsGOvSdYhg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-html-community": "^0.0.8",
|
||||
"common-path-prefix": "^3.0.0",
|
||||
"core-js-pure": "^3.8.1",
|
||||
"error-stack-parser": "^2.0.6",
|
||||
"find-up": "^5.0.0",
|
||||
"html-entities": "^2.1.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/webpack": "4.x || 5.x",
|
||||
"react-refresh": "^0.10.0",
|
||||
"sockjs-client": "^1.4.0",
|
||||
"type-fest": ">=0.17.0 <3.0.0",
|
||||
"webpack": ">=4.43.0 <6.0.0",
|
||||
"webpack-dev-server": "3.x || 4.x",
|
||||
"webpack-hot-middleware": "2.x",
|
||||
"webpack-plugin-serve": "0.x || 1.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/webpack": {
|
||||
"optional": true
|
||||
},
|
||||
"sockjs-client": {
|
||||
"optional": true
|
||||
},
|
||||
"type-fest": {
|
||||
"optional": true
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
"optional": true
|
||||
},
|
||||
"webpack-hot-middleware": {
|
||||
"optional": true
|
||||
},
|
||||
"webpack-plugin-serve": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/html-entities": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
|
||||
"integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5"
|
||||
},
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-locate": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"p-limit": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/schema-utils": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz",
|
||||
@ -4204,9 +4449,9 @@
|
||||
"integrity": "sha512-crV/441NhrynLIclg94i1wV6nX/6rU9ByUyn4muCrsL0HPd3nBzrt6kpQ9MQOB+HeYgLcRARteNJcbnYkp5OwA=="
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
|
||||
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
@ -5266,6 +5511,18 @@
|
||||
"ansi-html": "bin/ansi-html"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-html-community": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
|
||||
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
|
||||
"dev": true,
|
||||
"engines": [
|
||||
"node >= 0.8.0"
|
||||
],
|
||||
"bin": {
|
||||
"ansi-html": "bin/ansi-html"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
@ -7633,6 +7890,12 @@
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/common-path-prefix": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
|
||||
"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/common-tags": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
|
||||
@ -9544,6 +9807,15 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/error-stack-parser": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz",
|
||||
"integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"stackframe": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
|
||||
@ -21846,6 +22118,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
|
||||
"integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@ -21951,6 +22232,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg-up/node_modules/type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg/node_modules/type-fest": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
|
||||
@ -23784,6 +24073,12 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/stackframe": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
||||
"integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/start-server-and-test": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz",
|
||||
@ -25917,11 +26212,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.3.2.tgz",
|
||||
"integrity": "sha512-cfvZ1nOC/VqAt8bVOIlFz8x+HdDASpiFYrSi0U0nzcAFlOnzzQ/gsPg2PP1uqjreO7sQCtraYJHMduXSewQsSA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=12.20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
@ -27969,6 +28270,18 @@
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -29655,6 +29968,12 @@
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -30651,6 +30970,154 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@pmmmwh/react-refresh-webpack-plugin": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.1.tgz",
|
||||
"integrity": "sha512-ccap6o7+y5L8cnvkZ9h8UXCGyy2DqtwCD+/N3Yru6lxMvcdkPKtdx13qd7sAC9s5qZktOmWf9lfUjsGOvSdYhg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-html-community": "^0.0.8",
|
||||
"common-path-prefix": "^3.0.0",
|
||||
"core-js-pure": "^3.8.1",
|
||||
"error-stack-parser": "^2.0.6",
|
||||
"find-up": "^5.0.0",
|
||||
"html-entities": "^2.1.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0",
|
||||
"source-map": "^0.7.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"dev": true
|
||||
},
|
||||
"emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"html-entities": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
|
||||
"integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.1.tgz",
|
||||
@ -30899,9 +31366,9 @@
|
||||
"integrity": "sha512-crV/441NhrynLIclg94i1wV6nX/6rU9ByUyn4muCrsL0HPd3nBzrt6kpQ9MQOB+HeYgLcRARteNJcbnYkp5OwA=="
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
|
||||
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==",
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
@ -31806,6 +32273,12 @@
|
||||
"integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-html-community": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
|
||||
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
@ -33744,6 +34217,12 @@
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"common-path-prefix": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
|
||||
"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
|
||||
"dev": true
|
||||
},
|
||||
"common-tags": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
|
||||
@ -35321,6 +35800,15 @@
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"error-stack-parser": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz",
|
||||
"integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"stackframe": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
|
||||
@ -45063,6 +45551,12 @@
|
||||
"warning": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"react-refresh": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
|
||||
"integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
|
||||
"dev": true
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@ -45144,6 +45638,11 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -46735,6 +47234,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"stackframe": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
||||
"integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==",
|
||||
"dev": true
|
||||
},
|
||||
"start-server-and-test": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz",
|
||||
@ -48442,9 +48947,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.3.2.tgz",
|
||||
"integrity": "sha512-cfvZ1nOC/VqAt8bVOIlFz8x+HdDASpiFYrSi0U0nzcAFlOnzzQ/gsPg2PP1uqjreO7sQCtraYJHMduXSewQsSA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
@ -50137,6 +50645,12 @@
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,7 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
|
||||
"@testing-library/cypress": "^8.0.1",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jest": "^27.0.1",
|
||||
@ -104,6 +105,7 @@
|
||||
"null-loader": "^1.0.0",
|
||||
"prettier": "^2.3.2",
|
||||
"raw-loader": "~0.5.0",
|
||||
"react-refresh": "^0.10.0",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"sass-loader": "^7.0.3",
|
||||
"script-loader": "~0.7.0",
|
||||
|
1
src/Augmentation/AugmentationHelpers.d.ts
vendored
1
src/Augmentation/AugmentationHelpers.d.ts
vendored
@ -1 +1,2 @@
|
||||
export declare function isRepeatableAug(aug: Augmentation): boolean;
|
||||
export declare function installAugmentations(): void;
|
||||
|
@ -1,16 +1,17 @@
|
||||
import React from "react";
|
||||
import { hackWorldDaemon } from "../../RedPill";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
export function BitFlumePopup(props: IProps): React.ReactElement {
|
||||
function flume(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true, false);
|
||||
props.router.toBitVerse(true, false);
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
return (
|
||||
|
@ -1,18 +1,22 @@
|
||||
import React, { useState } from "react";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { enterBitNode } from "../../RedPill";
|
||||
import { PortalPopup } from "./PortalPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IPortalProps {
|
||||
n: number;
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const bitNode = BitNodes[`BitNode${props.n}`];
|
||||
if (bitNode == null) {
|
||||
return <>O</>;
|
||||
@ -32,6 +36,7 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
n: props.n,
|
||||
level: props.level,
|
||||
enter: props.enter,
|
||||
router: router,
|
||||
destroyedBitNode: props.destroyedBitNode,
|
||||
flume: props.flume,
|
||||
popupId: popupId,
|
||||
@ -39,7 +44,11 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<a className={`bitnode ${cssClass} tooltip`} onClick={openPortalPopup}>
|
||||
<button
|
||||
className={`bitnode ${cssClass} tooltip`}
|
||||
aria-label={`enter-bitnode-${bitNode.number.toString()}`}
|
||||
onClick={openPortalPopup}
|
||||
>
|
||||
<strong>O</strong>
|
||||
<span className="tooltiptext">
|
||||
<strong>
|
||||
@ -51,24 +60,26 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
{bitNode.desc}
|
||||
<br />
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
flume: boolean;
|
||||
destroyedBitNodeNum: number;
|
||||
quick: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
|
||||
export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const enter = enterBitNode;
|
||||
const destroyed = player.bitNodeN;
|
||||
const [destroySequence, setDestroySequence] = useState(true && !props.quick);
|
||||
|
||||
// Update NextSourceFileFlags
|
||||
const nextSourceFileFlags = SourceFileFlags.slice();
|
||||
if (!props.flume) {
|
||||
if (nextSourceFileFlags[props.destroyedBitNodeNum] < 3) ++nextSourceFileFlags[props.destroyedBitNodeNum];
|
||||
if (nextSourceFileFlags[destroyed] < 3) ++nextSourceFileFlags[destroyed];
|
||||
}
|
||||
|
||||
if (destroySequence) {
|
||||
@ -84,7 +95,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
"0020 7124696B 0000FF69 74652E6F FFFF1111",
|
||||
"----------------------------------------",
|
||||
"Failsafe initiated...",
|
||||
`Restarting BitNode-${props.destroyedBitNodeNum}...`,
|
||||
`Restarting BitNode-${destroyed}...`,
|
||||
"...........",
|
||||
"...........",
|
||||
"[ERROR] FAILED TO AUTOMATICALLY REBOOT BITNODE",
|
||||
@ -96,6 +107,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
"..............................................",
|
||||
]}
|
||||
onDone={() => setDestroySequence(false)}
|
||||
auto={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -116,16 +128,16 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<pre> \| O | |_/ |\| \ O \__| \_| | O |/ </pre>
|
||||
<pre> | | |_/ | | \| / | \_| | | </pre>
|
||||
<pre> \| / \| | / / \ |/ </pre>
|
||||
<pre> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | </pre>
|
||||
<pre> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> </pre>
|
||||
<pre> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </pre>
|
||||
<pre> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </pre>
|
||||
<pre> | | | / / \ \ | | | </pre>
|
||||
<pre> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> \ | |/ </pre>
|
||||
<pre> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </pre>
|
||||
<pre> \ | / / | | \ \ | / </pre>
|
||||
<pre> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> PMUJ/ / </pre>
|
||||
<pre> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </pre>
|
||||
<pre> \|| | | | | | | | | ||/ </pre>
|
||||
<pre> \| \_ | | | | | | _/ |/ </pre>
|
||||
<pre> \ \| / \ / \ |/ / </pre>
|
||||
<pre> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> </pre>
|
||||
<pre> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </pre>
|
||||
<pre> | | | | | | | | </pre>
|
||||
<pre> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </pre>
|
||||
<br />
|
||||
|
@ -1,13 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
interface IProps {
|
||||
n: number;
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
router: IRouter;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
@ -33,7 +35,7 @@ export function PortalPopup(props: IProps): React.ReactElement {
|
||||
<button
|
||||
className="std-button"
|
||||
onClick={() => {
|
||||
props.enter(props.flume, props.destroyedBitNode, props.n);
|
||||
props.enter(props.router, props.flume, props.destroyedBitNode, props.n);
|
||||
removePopup(props.popupId);
|
||||
}}
|
||||
>
|
||||
|
@ -15,6 +15,7 @@ import { Skill } from "./Skill";
|
||||
import { City } from "./City";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { ConsoleHelpText } from "./data/Help";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
@ -25,7 +26,7 @@ import { addOffset } from "../../utils/helpers/addOffset";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { hackWorldDaemon, redPillFlag } from "../RedPill";
|
||||
import { redPillFlag } from "../RedPill";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
@ -1203,7 +1204,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
completeAction(player: IPlayer): void {
|
||||
completeAction(router: IRouter, player: IPlayer): void {
|
||||
switch (this.action.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]: {
|
||||
@ -1338,7 +1339,7 @@ export class Bladeburner implements IBladeburner {
|
||||
// Operation Daedalus
|
||||
if (action.name === "Operation Daedalus") {
|
||||
this.resetAction();
|
||||
return hackWorldDaemon(player.bitNodeN);
|
||||
return router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
if (this.logging.blackops) {
|
||||
@ -1540,7 +1541,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
processAction(player: IPlayer, seconds: number): void {
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void {
|
||||
if (this.action.type === ActionTypes["Idle"]) return;
|
||||
if (this.actionTimeToComplete <= 0) {
|
||||
throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
|
||||
@ -1555,7 +1556,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.actionTimeOverflow = 0;
|
||||
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
|
||||
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
|
||||
return this.completeAction(player);
|
||||
return this.completeAction(router, player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1888,10 +1889,10 @@ export class Bladeburner implements IBladeburner {
|
||||
});
|
||||
}
|
||||
|
||||
process(player: IPlayer): void {
|
||||
process(router: IRouter, player: IPlayer): void {
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (redPillFlag === false && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return hackWorldDaemon(player.bitNodeN);
|
||||
return router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
@ -1958,7 +1959,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.randomEventCounter += getRandomInt(240, 600);
|
||||
}
|
||||
|
||||
this.processAction(player, seconds);
|
||||
this.processAction(router, player, seconds);
|
||||
|
||||
// Automation
|
||||
if (this.automateEnabled) {
|
||||
|
@ -3,6 +3,7 @@ import { City } from "./City";
|
||||
import { Skill } from "./Skill";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
export interface IBladeburner {
|
||||
@ -103,11 +104,11 @@ export interface IBladeburner {
|
||||
completeOperation(success: boolean): void;
|
||||
getActionObject(actionId: IActionIdentifier): IAction | null;
|
||||
completeContract(success: boolean): void;
|
||||
completeAction(player: IPlayer): void;
|
||||
completeAction(router: IRouter, player: IPlayer): void;
|
||||
changeRank(player: IPlayer, change: number): void;
|
||||
processAction(player: IPlayer, seconds: number): void;
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void;
|
||||
calculateStaminaGainPerSecond(player: IPlayer): number;
|
||||
calculateMaxStamina(player: IPlayer): void;
|
||||
create(): void;
|
||||
process(player: IPlayer): void;
|
||||
process(router: IRouter, player: IPlayer): void;
|
||||
}
|
||||
|
42
src/Bladeburner/ui/BladeburnerCinematic.tsx
Normal file
42
src/Bladeburner/ui/BladeburnerCinematic.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React from "react";
|
||||
import { use } from "../../ui/Context";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
export function BladeburnerCinematic(): React.ReactElement {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<CinematicText
|
||||
lines={[
|
||||
"In the middle of the 21st century, OmniTek Incorporated advanced robot evolution ",
|
||||
"with their Synthoids (synthetic androids), a being virtually identical to a human.",
|
||||
"------",
|
||||
"Their sixth-generation Synthoids, called MK-VI, were stronger, faster, and more ",
|
||||
"intelligent than humans. Many argued that the MK-VI Synthoids were the first ",
|
||||
"example of sentient AI.",
|
||||
"------",
|
||||
"Unfortunately, in 2070 a terrorist group called Ascendis Totalis hacked into OmniTek and ",
|
||||
"uploaded a rogue AI into their Synthoid manufacturing facilities.",
|
||||
"------",
|
||||
"The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating ",
|
||||
"the deadliest conflict in human history. This dark chapter is now known as the Synthoid Uprising.",
|
||||
"------",
|
||||
"In the aftermath of the Uprising, further manufacturing of Synthoids with advanced AI ",
|
||||
"was banned. MK-VI Synthoids that did not have the rogue Ascendis Totalis AI were ",
|
||||
"allowed to continue their existence.",
|
||||
"------",
|
||||
"The intelligence community believes that not all of the rogue MK-VI Synthoids from the Uprising were ",
|
||||
"found and destroyed, and that many of them are blending in as normal humans in society today. ",
|
||||
"As a result, many nations have created Bladeburner divisions, special units that are tasked with ",
|
||||
"investigating and dealing with Synthoid threats.",
|
||||
]}
|
||||
onDone={() => {
|
||||
router.toTerminal();
|
||||
dialogBoxCreate(
|
||||
"Visit the National Security Agency (NSA) to apply for their Bladeburner " +
|
||||
"division! You will need 100 of each combat stat before doing this.",
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -3,17 +3,16 @@ import { Stats } from "./Stats";
|
||||
import { Console } from "./Console";
|
||||
import { AllPages } from "./AllPages";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
engine: IEngine;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
export function BladeburnerRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
return (
|
||||
<div className="bladeburner-container">
|
||||
<div style={{ height: "60%", display: "block", position: "relative" }}>
|
||||
@ -25,9 +24,9 @@ export function Root(props: IProps): React.ReactElement {
|
||||
border: "1px solid white",
|
||||
}}
|
||||
>
|
||||
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
|
||||
<Stats bladeburner={props.bladeburner} player={player} router={router} />
|
||||
</div>
|
||||
<Console bladeburner={props.bladeburner} player={props.player} />
|
||||
<Console bladeburner={props.bladeburner} player={player} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@ -39,7 +38,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<AllPages bladeburner={props.bladeburner} player={props.player} />
|
||||
<AllPages bladeburner={props.bladeburner} player={player} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -2,21 +2,21 @@ import React, { useState, useEffect } from "react";
|
||||
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { StatsTable } from "../../ui/React/StatsTable";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { joinFaction, displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { joinFaction } from "../../Faction/FactionHelpers";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
|
||||
import { TravelPopup } from "./TravelPopup";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
@ -72,8 +72,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
function openFaction(): void {
|
||||
const faction = Factions["Bladeburners"];
|
||||
if (faction.isMember) {
|
||||
props.engine.loadFactionContent();
|
||||
displayFactionContent("Bladeburners");
|
||||
props.router.toFaction(faction);
|
||||
} else {
|
||||
if (props.bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(faction);
|
||||
@ -148,12 +147,14 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
</p>
|
||||
<p>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</p>
|
||||
<br />
|
||||
{StatsTable([
|
||||
["Aug. Success Chance mult: ", formatNumber(props.player.bladeburner_success_chance_mult * 100, 1) + "%"],
|
||||
["Aug. Max Stamina mult: ", formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1) + "%"],
|
||||
["Aug. Stamina Gain mult: ", formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1) + "%"],
|
||||
["Aug. Field Analysis mult: ", formatNumber(props.player.bladeburner_analysis_mult * 100, 1) + "%"],
|
||||
])}
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Aug. Success Chance mult: ", formatNumber(props.player.bladeburner_success_chance_mult * 100, 1) + "%"],
|
||||
["Aug. Max Stamina mult: ", formatNumber(props.player.bladeburner_max_stamina_mult * 100, 1) + "%"],
|
||||
["Aug. Stamina Gain mult: ", formatNumber(props.player.bladeburner_stamina_gain_mult * 100, 1) + "%"],
|
||||
["Aug. Field Analysis mult: ", formatNumber(props.player.bladeburner_analysis_mult * 100, 1) + "%"],
|
||||
]}
|
||||
/>
|
||||
<br />
|
||||
<a onClick={openTravel} className="a-link-button" style={{ display: "inline-block" }}>
|
||||
Travel
|
||||
|
@ -340,15 +340,13 @@ export class Blackjack extends Game<Props, State> {
|
||||
{/* Buttons */}
|
||||
{!gameInProgress ? (
|
||||
<div>
|
||||
<MuiButton color="primary" onClick={this.startOnClick} disabled={wagerInvalid || !this.canStartGame()}>
|
||||
<MuiButton onClick={this.startOnClick} disabled={wagerInvalid || !this.canStartGame()}>
|
||||
Start
|
||||
</MuiButton>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<MuiButton color="primary" onClick={this.playerHit}>
|
||||
Hit
|
||||
</MuiButton>
|
||||
<MuiButton onClick={this.playerHit}>Hit</MuiButton>
|
||||
<MuiButton color="secondary" onClick={this.playerStay}>
|
||||
Stay
|
||||
</MuiButton>
|
||||
|
@ -121,7 +121,7 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: number;
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
Version: "0.53.0",
|
||||
Version: "0.54.0",
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
@ -344,83 +344,48 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
LatestUpdate: `
|
||||
v0.53.0 - 2021-09-09 Way too many things. (hydroflame & community)
|
||||
v0.54.0 - 2021-09-20 One big react node (hydroflame & community)
|
||||
-------------------------------------------
|
||||
|
||||
** Dev? **
|
||||
** UI **
|
||||
|
||||
* The entire codebase has been run through a code prettifier, hurray for consistency. (@threehams)
|
||||
* Lots of test. (@threehams)
|
||||
* Massive improvements to build speed. (@threehams)
|
||||
* Dev notes: This won't affect any players but is immensely useful for me.
|
||||
* The UI is now completely(ish) in react and I'm starting to implement
|
||||
Material-UI everywhere. This will help make the game feel more consistent.
|
||||
* Major help from (@threehams)
|
||||
* New Terminal
|
||||
* New Active Scripts page
|
||||
* New sidebar.
|
||||
* New Character overview
|
||||
* New tutorial
|
||||
* New options page
|
||||
* New create program page (@Nolshine)
|
||||
|
||||
** Hacknet **
|
||||
** Netscript **
|
||||
|
||||
* Converted to ts/react
|
||||
* Add companyName to getPlayer
|
||||
|
||||
** Resleeving **
|
||||
** Factions **
|
||||
|
||||
* Converted to ts/react
|
||||
* Megacorp factions are no longer removed when installing.
|
||||
|
||||
** Sleeves **
|
||||
** Corporation **
|
||||
|
||||
* Converted to ts/react. The ui should also have a better feel.
|
||||
* Fixed a bug that allowed players to recover shock much faster than intended.
|
||||
|
||||
** BN10 **
|
||||
|
||||
* You have access to Sleeves right away
|
||||
* In BN10 Sleeves start with 75 shock and 25 sync.
|
||||
|
||||
** MathJax **
|
||||
|
||||
* Several tooltips have been updated to display the relevant formula in Mathjax, e.g. Favor and reputation
|
||||
|
||||
** Corporation **
|
||||
|
||||
* Completely rewritten in React. Paving the way for bigger change.
|
||||
* Smart Supply is now smarter and won't deadlock the warehouse. It is also more configurable.
|
||||
* Several UI fixes.
|
||||
|
||||
** Bladeburner **
|
||||
|
||||
* Action count is no longer decided when joining the Bladeburners. Experiences for all players should be more similar.
|
||||
|
||||
** Factions **
|
||||
|
||||
* No factions have home computer ram requirement. This caused some confusion for new players.
|
||||
|
||||
** Gang **
|
||||
|
||||
* Made it clear when there's a new equipment coming up.
|
||||
|
||||
** Netscript **
|
||||
|
||||
* getActionCountRemaining now returns Infinity for bladeburner general actions. (@brubsy)
|
||||
* getActionEstimatedSuccessChance now returns 100% for Diplomacy and Hyperbolic Regeneration Chamber. (@brubsy)
|
||||
* disableLog('ALL') now disables all logs individually, meaning you can re-enable the ones you want after. (@Cass)
|
||||
* getPlayer returns numPeopleKilled.
|
||||
* Dynamic RAM calculation errors have a better error message.
|
||||
* Hide some functions from autocomplete.
|
||||
* Added getAugmentationPrice, getAugmentationRepReq, deprecated getAugmentationCost. (@TempFound)
|
||||
* Fixed bug where some crime API would return "assassinate" when that's not accepted in other functions.
|
||||
|
||||
** Coding Contract **
|
||||
|
||||
* Spiralize Matrix is easier to read.
|
||||
* All research tooltips are always visible.
|
||||
* Smart supply is enabled by default if purchased (@Nolshine)
|
||||
|
||||
** Misc. **
|
||||
|
||||
* The world map is now used in sleeve travel and bladeburner travel.
|
||||
* noselect a bunch of stuff.
|
||||
* Ascii maps letters are more contrasting
|
||||
* Updated documentation for infiltration.
|
||||
* Most money costs in the game will turn grey/cyan when you don't have enough money.
|
||||
* Donation textbox has better look & feel.
|
||||
* Tech vendors ram & cores buttons have better look and feels.
|
||||
* cores cost modified to be a formula instead of a semi-random array of numbers.
|
||||
* Tech vendors now give a hint about where to get bigger servers.
|
||||
* logboxes now displays whitespaces exactly. (@Cass)
|
||||
* Fix "Game saved" animation. (@Nolshine)
|
||||
* Update commitCrime documentation (@Tryneus)
|
||||
* Fix logbox scrolling weird (@Nolshine)
|
||||
* Fix weird scrolling in corporations (@BartKoppelmans)
|
||||
* Fix typo (@BartKoppelmans & @Nolshine)
|
||||
* Delete game now has a confirmation modal (@Nolshine)
|
||||
* Fix issue where skills would not get properly updated when entering new
|
||||
BN. (@Nolshine)
|
||||
* Convert create gang to popup (@vmesecher)
|
||||
* Fixed a bug that prevented travel to Sector-12 and New Tokyo when not using
|
||||
ASCII art.
|
||||
* nerf noodle bar
|
||||
`,
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
|
||||
import { IRouter } from "../ui/Router";
|
||||
|
||||
export interface IConstructorParams {
|
||||
hacking_success_weight?: number;
|
||||
@ -85,11 +86,12 @@ export class Crime {
|
||||
this.kills = params.kills ? params.kills : 0;
|
||||
}
|
||||
|
||||
commit(p: IPlayer, div = 1, singParams: any = null): number {
|
||||
commit(router: IRouter, p: IPlayer, div = 1, singParams: any = null): number {
|
||||
if (div <= 0) {
|
||||
div = 1;
|
||||
}
|
||||
p.startCrime(
|
||||
router,
|
||||
this.type,
|
||||
this.hacking_exp / div,
|
||||
this.strength_exp / div,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { IPlayer } from "./PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { IEngine } from "./IEngine";
|
||||
import { IRouter } from "./ui/Router";
|
||||
|
||||
import React from "react";
|
||||
import { TTheme as Theme } from "./ui/React/Theme";
|
||||
|
||||
import { General } from "./DevMenu/ui/General";
|
||||
import { Stats } from "./DevMenu/ui/Stats";
|
||||
@ -24,36 +24,35 @@ import { TimeSkip } from "./DevMenu/ui/TimeSkip";
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function DevMenuRoot(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<Theme>
|
||||
<>
|
||||
<h1>Development Menu - Only meant to be used for testing/debugging</h1>
|
||||
<General player={props.player} />
|
||||
<Stats player={props.player} />
|
||||
<Factions player={props.player} />
|
||||
<Augmentations player={props.player} />
|
||||
<SourceFiles player={props.player} />
|
||||
<Programs player={props.player} />
|
||||
<Servers />
|
||||
<Companies />
|
||||
<>
|
||||
<h1>Development Menu - Only meant to be used for testing/debugging</h1>
|
||||
<General player={props.player} router={props.router} />
|
||||
<Stats player={props.player} />
|
||||
<Factions player={props.player} />
|
||||
<Augmentations player={props.player} />
|
||||
<SourceFiles player={props.player} />
|
||||
<Programs player={props.player} />
|
||||
<Servers />
|
||||
<Companies />
|
||||
|
||||
{props.player.bladeburner instanceof Bladeburner && <BladeburnerElem player={props.player} />}
|
||||
{props.player.bladeburner instanceof Bladeburner && <BladeburnerElem player={props.player} />}
|
||||
|
||||
{props.player.inGang() && <Gang player={props.player} />}
|
||||
{props.player.inGang() && <Gang player={props.player} />}
|
||||
|
||||
{props.player.hasCorporation() && <Corporation player={props.player} />}
|
||||
{props.player.hasCorporation() && <Corporation player={props.player} />}
|
||||
|
||||
<CodingContracts />
|
||||
<CodingContracts />
|
||||
|
||||
{props.player.hasWseAccount && <StockMarket />}
|
||||
{props.player.hasWseAccount && <StockMarket />}
|
||||
|
||||
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
|
||||
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
|
||||
|
||||
<TimeSkip player={props.player} engine={props.engine} />
|
||||
</>
|
||||
</Theme>
|
||||
<TimeSkip player={props.player} engine={props.engine} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ export function Adjuster(props: IProps): React.ReactElement {
|
||||
startAdornment: (
|
||||
<>
|
||||
<Tooltip title="Add a lot">
|
||||
<IconButton color="primary" onClick={tons} size="large">
|
||||
<IconButton onClick={tons} size="large">
|
||||
<DoubleArrowIcon style={{ transform: "rotate(-90deg)" }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Add">
|
||||
<IconButton color="primary" onClick={() => add(typeof value !== "string" ? value : 0)} size="large">
|
||||
<IconButton onClick={() => add(typeof value !== "string" ? value : 0)} size="large">
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
@ -51,16 +51,12 @@ export function Adjuster(props: IProps): React.ReactElement {
|
||||
endAdornment: (
|
||||
<>
|
||||
<Tooltip title="Remove">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => subtract(typeof value !== "string" ? value : 0)}
|
||||
size="large"
|
||||
>
|
||||
<IconButton onClick={() => subtract(typeof value !== "string" ? value : 0)} size="large">
|
||||
<RemoveIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Reset">
|
||||
<IconButton color="primary" onClick={reset} size="large">
|
||||
<IconButton onClick={reset} size="large">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
@ -40,7 +40,7 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Augmentations</h2>
|
||||
</AccordionSummary>
|
||||
@ -53,23 +53,21 @@ export function Augmentations(props: IProps): React.ReactElement {
|
||||
</td>
|
||||
<td>
|
||||
<Select
|
||||
id="dev-augs-dropdown"
|
||||
className="dropdown"
|
||||
onChange={setAugmentationDropdown}
|
||||
value={augmentation}
|
||||
startAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={queueAllAugs} size="large">
|
||||
<IconButton onClick={queueAllAugs} size="large">
|
||||
<ReplyAllIcon />
|
||||
</IconButton>
|
||||
<IconButton color="primary" onClick={queueAug} size="large">
|
||||
<IconButton onClick={queueAug} size="large">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
endAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={clearAugs} size="large">
|
||||
<IconButton onClick={clearAugs} size="large">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
|
@ -55,7 +55,7 @@ export function Bladeburner(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Bladeburner</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -25,7 +25,7 @@ export function CodingContracts(): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Coding Contracts</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -69,7 +69,7 @@ export function Companies(): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Companies</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -67,7 +67,7 @@ export function Corporation(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Corporation</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -97,7 +97,7 @@ export function Factions(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Factions</h2>
|
||||
</AccordionSummary>
|
||||
@ -119,10 +119,10 @@ export function Factions(props: IProps): React.ReactElement {
|
||||
value={faction}
|
||||
startAdornment={
|
||||
<>
|
||||
<IconButton color="primary" onClick={receiveAllInvites} size="large">
|
||||
<IconButton onClick={receiveAllInvites} size="large" arial-label="receive-all-invitation">
|
||||
<ReplyAllIcon />
|
||||
</IconButton>
|
||||
<IconButton color="primary" onClick={receiveInvite} size="large">
|
||||
<IconButton onClick={receiveInvite} size="large" arial-label="receive-one-invitation">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
|
@ -36,7 +36,7 @@ export function Gang(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Gang</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -8,10 +8,11 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { hackWorldDaemon } from "../../RedPill";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function General(props: IProps): React.ReactElement {
|
||||
@ -26,23 +27,23 @@ export function General(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function quickB1tFlum3(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true, true);
|
||||
props.router.toBitVerse(true, true);
|
||||
}
|
||||
|
||||
function b1tflum3(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true);
|
||||
props.router.toBitVerse(true, false);
|
||||
}
|
||||
|
||||
function quickHackW0r1dD43m0n(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, false, true);
|
||||
props.router.toBitVerse(false, true);
|
||||
}
|
||||
|
||||
function hackW0r1dD43m0n(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN);
|
||||
props.router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>General</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -35,7 +35,7 @@ export function Programs(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Programs</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -75,7 +75,7 @@ export function Servers(): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Servers</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -38,7 +38,7 @@ export function Sleeves(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Sleeves</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -51,7 +51,7 @@ export function SourceFiles(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Source-Files</h2>
|
||||
</AccordionSummary>
|
||||
@ -72,10 +72,18 @@ export function SourceFiles(props: IProps): React.ReactElement {
|
||||
</td>
|
||||
<td>
|
||||
<ButtonGroup>
|
||||
<Button onClick={setAllSF(0)}>0</Button>
|
||||
<Button onClick={setAllSF(1)}>1</Button>
|
||||
<Button onClick={setAllSF(2)}>2</Button>
|
||||
<Button onClick={setAllSF(3)}>3</Button>
|
||||
<Button aria-label="all-sf-0" onClick={setAllSF(0)}>
|
||||
0
|
||||
</Button>
|
||||
<Button aria-label="all-sf-1" onClick={setAllSF(1)}>
|
||||
1
|
||||
</Button>
|
||||
<Button aria-label="all-sf-2" onClick={setAllSF(2)}>
|
||||
2
|
||||
</Button>
|
||||
<Button aria-label="all-sf-3" onClick={setAllSF(3)}>
|
||||
3
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -136,7 +136,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Experience / Stats</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -80,7 +80,7 @@ export function StockMarket(): React.ReactElement {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Stock Market</h2>
|
||||
</AccordionSummary>
|
||||
|
@ -28,9 +28,9 @@ export function TimeSkip(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Sleeves</h2>
|
||||
<h2>Time skip</h2>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Button onClick={timeskip(60 * 1000)}>1 minute</Button>
|
||||
|
2
src/Faction/FactionHelpers.d.ts
vendored
2
src/Faction/FactionHelpers.d.ts
vendored
@ -4,5 +4,5 @@ import { Faction } from "../Faction/Faction";
|
||||
export declare function getNextNeurofluxLevel(): number;
|
||||
export declare function hasAugmentationPrereqs(aug: Augmentation): boolean;
|
||||
export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void;
|
||||
export declare function displayFactionContent(factionName: string, initiallyOnAugmentationsPage: boolean = false);
|
||||
export declare function joinFaction(faction: Faction): void;
|
||||
export declare function startHackingMission(faction: Faction): void;
|
||||
|
@ -1,14 +1,9 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { FactionRoot } from "./ui/Root";
|
||||
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
@ -65,29 +60,6 @@ export function startHackingMission(faction) {
|
||||
mission.init();
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
export function displayFactionContent(factionName, initiallyOnAugmentationsPage = false) {
|
||||
const faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error(`Invalid factionName passed into displayFactionContent(): ${factionName}`);
|
||||
}
|
||||
|
||||
if (!faction.isMember) {
|
||||
throw new Error(`Not a member of this faction. Cannot display faction information`);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<FactionRoot
|
||||
engine={Engine}
|
||||
initiallyOnAugmentationsPage={initiallyOnAugmentationsPage}
|
||||
faction={faction}
|
||||
p={Player}
|
||||
startHackingMissionFn={startHackingMission}
|
||||
/>,
|
||||
Engine.Display.content,
|
||||
);
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug) {
|
||||
@ -187,9 +159,6 @@ export function purchaseAugmentation(aug, fac, sing = false) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Force a rerender of the Augmentations page
|
||||
displayFactionContent(fac.name, true);
|
||||
} else {
|
||||
dialogBoxCreate(
|
||||
"Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
|
@ -1,52 +1,37 @@
|
||||
/**
|
||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
routeToMainPage: () => void;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
sortOrder: PurchaseAugmentationsOrderSetting;
|
||||
};
|
||||
|
||||
const infoStyleMarkup = {
|
||||
width: "70%",
|
||||
};
|
||||
|
||||
export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// Flag for whether the player has a gang with this faction
|
||||
isPlayersGang: boolean;
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
const isPlayersGang = player.inGang() && player.getGangName() === props.faction.name;
|
||||
|
||||
this.isPlayersGang = props.p.inGang() && props.p.getGangName() === props.faction.name;
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
sortOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||
};
|
||||
|
||||
this.rerender = this.rerender.bind(this);
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
getAugs(): string[] {
|
||||
if (this.isPlayersGang) {
|
||||
function getAugs(): string[] {
|
||||
if (isPlayersGang) {
|
||||
const augs: string[] = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
@ -57,25 +42,25 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
|
||||
return augs;
|
||||
} else {
|
||||
return this.props.faction.augmentations.slice();
|
||||
return props.faction.augmentations.slice();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSorted(): string[] {
|
||||
function getAugsSorted(): string[] {
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost: {
|
||||
return this.getAugsSortedByCost();
|
||||
return getAugsSortedByCost();
|
||||
}
|
||||
case PurchaseAugmentationsOrderSetting.Reputation: {
|
||||
return this.getAugsSortedByReputation();
|
||||
return getAugsSortedByReputation();
|
||||
}
|
||||
default:
|
||||
return this.getAugsSortedByDefault();
|
||||
return getAugsSortedByDefault();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSortedByCost(): string[] {
|
||||
const augs = this.getAugs();
|
||||
function getAugsSortedByCost(): string[] {
|
||||
const augs = getAugs();
|
||||
augs.sort((augName1, augName2) => {
|
||||
const aug1 = Augmentations[augName1],
|
||||
aug2 = Augmentations[augName2];
|
||||
@ -89,8 +74,8 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByReputation(): string[] {
|
||||
const augs = this.getAugs();
|
||||
function getAugsSortedByReputation(): string[] {
|
||||
const augs = getAugs();
|
||||
augs.sort((augName1, augName2) => {
|
||||
const aug1 = Augmentations[augName1],
|
||||
aug2 = Augmentations[augName2];
|
||||
@ -103,88 +88,70 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByDefault(): string[] {
|
||||
return this.getAugs();
|
||||
function getAugsSortedByDefault(): string[] {
|
||||
return getAugs();
|
||||
}
|
||||
|
||||
switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void {
|
||||
function switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
this.rerender();
|
||||
rerender();
|
||||
}
|
||||
|
||||
rerender(): void {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
};
|
||||
});
|
||||
}
|
||||
const augs = getAugsSorted();
|
||||
const purchasable = augs.filter(
|
||||
(aug: string) =>
|
||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
|
||||
render(): React.ReactNode {
|
||||
const augs = this.getAugsSorted();
|
||||
const purchasable = augs.filter(
|
||||
(aug: string) => aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!this.props.p.augmentations.some((a) => a.name === aug) &&
|
||||
!this.props.p.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
const purchaseableAugmentation = (aug: string): React.ReactNode => {
|
||||
return <PurchaseableAugmentation augName={aug} faction={props.faction} key={aug} p={player} rerender={rerender} />;
|
||||
};
|
||||
|
||||
const purchaseableAugmentation = (aug: string): React.ReactNode => {
|
||||
return (
|
||||
<PurchaseableAugmentation
|
||||
augName={aug}
|
||||
faction={this.props.faction}
|
||||
key={aug}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||
|
||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||
|
||||
let ownedElem = <></>;
|
||||
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
|
||||
if (owned.length !== 0) {
|
||||
ownedElem = (
|
||||
<>
|
||||
<br />
|
||||
<h2>Purchased Augmentations</h2>
|
||||
<p style={infoStyleMarkup}>This factions also offers these augmentations but you already own them.</p>
|
||||
{owned.map((aug) => purchaseableAugmentation(aug))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={this.props.routeToMainPage} text={"Back"} />
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p style={infoStyleMarkup}>
|
||||
These are all of the Augmentations that are available to purchase from {this.props.faction.name}.
|
||||
Augmentations are powerful upgrades that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} />
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
let ownedElem = <></>;
|
||||
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
|
||||
if (owned.length !== 0) {
|
||||
ownedElem = (
|
||||
<>
|
||||
<br />
|
||||
{augListElems}
|
||||
{ownedElem}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<h2>Purchased Augmentations</h2>
|
||||
<p>This factions also offers these augmentations but you already own them.</p>
|
||||
{owned.map((aug) => purchaseableAugmentation(aug))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={props.routeToMainPage} text={"Back"} />
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p>
|
||||
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
||||
powerful upgrades that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} />
|
||||
<StdButton
|
||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
<br />
|
||||
{augListElems}
|
||||
{ownedElem}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,58 +1,69 @@
|
||||
/**
|
||||
* React Component for the popup used to create a new gang.
|
||||
*/
|
||||
import React from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
interface ICreateGangPopupProps {
|
||||
popupId: string;
|
||||
facName: string;
|
||||
p: IPlayer;
|
||||
engine: IEngine;
|
||||
}
|
||||
interface ICreateGangPopupProps {
|
||||
popupId: string;
|
||||
facName: string;
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement {
|
||||
|
||||
const combatGangText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement {
|
||||
const player = props.player;
|
||||
const router = props.router;
|
||||
const combatGangText =
|
||||
"This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.";
|
||||
|
||||
const hackingGangText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
const hackingGangText =
|
||||
"This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.";
|
||||
|
||||
function isHacking(): boolean {
|
||||
return ["NiteSec", "The Black Hand"].includes(props.facName);
|
||||
}
|
||||
function isHacking(): boolean {
|
||||
return ["NiteSec", "The Black Hand"].includes(props.facName);
|
||||
}
|
||||
|
||||
function createGang(): void {
|
||||
props.p.startGang(props.facName, isHacking());
|
||||
removePopup(props.popupId);
|
||||
props.engine.loadGangContent();
|
||||
}
|
||||
function createGang(): void {
|
||||
player.startGang(props.facName, isHacking());
|
||||
removePopup(props.popupId);
|
||||
router.toGang();
|
||||
}
|
||||
|
||||
function onKeyUp(event: React.KeyboardEvent): void {
|
||||
if (event.keyCode === 13) createGang();
|
||||
}
|
||||
function onKeyUp(event: React.KeyboardEvent): void {
|
||||
if (event.keyCode === 13) createGang();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
Would you like to create a new Gang with {props.facName}?
|
||||
<br/>
|
||||
<br/>
|
||||
Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It also resets your reputation with this faction.
|
||||
<br/>
|
||||
<br/>
|
||||
{ (isHacking()) ? hackingGangText : combatGangText }
|
||||
<br/>
|
||||
<br/>
|
||||
Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each of these Factions have all Augmentations available.
|
||||
<div className="popup-box-input-div" >
|
||||
<StdButton onClick={createGang} onKeyUp={onKeyUp} text="Create Gang" style={{float: "right"}} autoFocus={true}/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
Would you like to create a new Gang with {props.facName}?
|
||||
<br />
|
||||
<br />
|
||||
Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It
|
||||
also resets your reputation with this faction.
|
||||
<br />
|
||||
<br />
|
||||
{isHacking() ? hackingGangText : combatGangText}
|
||||
<br />
|
||||
<br />
|
||||
Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each
|
||||
of these Factions have all Augmentations available.
|
||||
<div className="popup-box-input-div">
|
||||
<StdButton
|
||||
onClick={createGang}
|
||||
onKeyUp={onKeyUp}
|
||||
text="Create Gang"
|
||||
style={{ float: "right" }}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { Factions } from "../Factions";
|
||||
import { displayFactionContent, joinFaction } from "../FactionHelpers";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
engine: IEngine;
|
||||
}
|
||||
|
||||
export function FactionList(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
function openFaction(faction: string): void {
|
||||
props.engine.loadFactionContent();
|
||||
displayFactionContent(faction);
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLElement>, faction: string): void {
|
||||
if (!event.isTrusted) return;
|
||||
joinFaction(Factions[faction]);
|
||||
setRerender((x) => !x);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Factions</h1>
|
||||
<p>Lists all factions you have joined</p>
|
||||
<br />
|
||||
<ul>
|
||||
{props.player.factions.map((faction: string) => (
|
||||
<li key={faction}>
|
||||
<a
|
||||
className="a-link-button"
|
||||
onClick={() => openFaction(faction)}
|
||||
style={{ padding: "4px", margin: "4px", display: "inline-block" }}
|
||||
>
|
||||
{faction}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<br />
|
||||
<h1>Outstanding Faction Invitations</h1>
|
||||
<p style={{ width: "70%" }}>
|
||||
Lists factions you have been invited to. You can accept these faction invitations at any time.
|
||||
</p>
|
||||
<ul>
|
||||
{props.player.factionInvitations.map((faction: string) => (
|
||||
<li key={faction} style={{ padding: "6px", margin: "6px" }}>
|
||||
<p style={{ display: "inline", margin: "4px", padding: "4px" }}>{faction}</p>
|
||||
<a
|
||||
className="a-link-button"
|
||||
onClick={(e) => acceptInvitation(e, faction)}
|
||||
style={{ display: "inline", margin: "4px", padding: "4px" }}
|
||||
>
|
||||
Accept Faction Invitation
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
* This is the component for displaying a single faction's UI, not the list of all
|
||||
* accessible factions
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { AugmentationsPage } from "./AugmentationsPage";
|
||||
import { DonateOption } from "./DonateOption";
|
||||
@ -11,28 +11,18 @@ import { Info } from "./Info";
|
||||
import { Option } from "./Option";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { use } from "../../ui/Context";
|
||||
import { CreateGangPopup } from "./CreateGangPopup";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
initiallyOnAugmentationsPage?: boolean;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
startHackingMissionFn: (faction: Faction) => void;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
purchasingAugs: boolean;
|
||||
};
|
||||
|
||||
// Info text for all options on the UI
|
||||
@ -72,89 +62,66 @@ const GangNames = [
|
||||
"The Black Hand",
|
||||
];
|
||||
|
||||
export class FactionRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
const faction = props.faction;
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
purchasingAugs: props.initiallyOnAugmentationsPage ? props.initiallyOnAugmentationsPage : false,
|
||||
};
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [, setRerenderFlag] = useState(false);
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(false);
|
||||
|
||||
this.manageGang = this.manageGang.bind(this);
|
||||
this.rerender = this.rerender.bind(this);
|
||||
this.routeToMain = this.routeToMain.bind(this);
|
||||
this.routeToPurchaseAugs = this.routeToPurchaseAugs.bind(this);
|
||||
this.sleevePurchases = this.sleevePurchases.bind(this);
|
||||
this.startFieldWork = this.startFieldWork.bind(this);
|
||||
this.startHackingContracts = this.startHackingContracts.bind(this);
|
||||
this.startHackingMission = this.startHackingMission.bind(this);
|
||||
this.startSecurityWork = this.startSecurityWork.bind(this);
|
||||
}
|
||||
|
||||
manageGang(): void {
|
||||
function manageGang(faction: Faction): void {
|
||||
// If player already has a gang, just go to the gang UI
|
||||
if (this.props.p.inGang()) {
|
||||
return this.props.engine.loadGangContent();
|
||||
if (player.inGang()) {
|
||||
return router.toGang();
|
||||
}
|
||||
|
||||
const popupId = "create-gang-popup";
|
||||
createPopup(popupId, CreateGangPopup, {
|
||||
popupId: popupId,
|
||||
facName: this.props.faction.name,
|
||||
p: this.props.p,
|
||||
engine: this.props.engine,
|
||||
facName: faction.name,
|
||||
player: player,
|
||||
router: router,
|
||||
});
|
||||
}
|
||||
|
||||
rerender(): void {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
};
|
||||
});
|
||||
function rerender(): void {
|
||||
setRerenderFlag((old) => !old);
|
||||
}
|
||||
|
||||
// Route to the main faction page
|
||||
routeToMain(): void {
|
||||
this.setState({ purchasingAugs: false });
|
||||
function routeToMain(): void {
|
||||
setPurchasingAugs(false);
|
||||
}
|
||||
|
||||
// Route to the purchase augmentation UI for this faction
|
||||
routeToPurchaseAugs(): void {
|
||||
this.setState({ purchasingAugs: true });
|
||||
function routeToPurchaseAugs(): void {
|
||||
setPurchasingAugs(true);
|
||||
}
|
||||
|
||||
sleevePurchases(): void {
|
||||
createSleevePurchasesFromCovenantPopup(this.props.p);
|
||||
function sleevePurchases(): void {
|
||||
createSleevePurchasesFromCovenantPopup(player);
|
||||
}
|
||||
|
||||
startFieldWork(): void {
|
||||
this.props.p.startFactionFieldWork(this.props.faction);
|
||||
function startFieldWork(faction: Faction): void {
|
||||
player.startFactionFieldWork(router, faction);
|
||||
}
|
||||
|
||||
startHackingContracts(): void {
|
||||
this.props.p.startFactionHackWork(this.props.faction);
|
||||
function startHackingContracts(faction: Faction): void {
|
||||
player.startFactionHackWork(router, faction);
|
||||
}
|
||||
|
||||
startHackingMission(): void {
|
||||
const fac = this.props.faction;
|
||||
this.props.p.singularityStopWork();
|
||||
this.props.engine.loadMissionContent();
|
||||
this.props.startHackingMissionFn(fac);
|
||||
function startHackingMission(faction: Faction): void {
|
||||
player.singularityStopWork();
|
||||
router.toHackingMission(faction);
|
||||
}
|
||||
|
||||
startSecurityWork(): void {
|
||||
this.props.p.startFactionSecurityWork(this.props.faction);
|
||||
function startSecurityWork(faction: Faction): void {
|
||||
player.startFactionSecurityWork(router, faction);
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return this.state.purchasingAugs ? this.renderAugmentationsPage() : this.renderMainPage();
|
||||
}
|
||||
|
||||
renderMainPage(): React.ReactNode {
|
||||
const p = this.props.p;
|
||||
const faction = this.props.faction;
|
||||
function MainPage({ faction }: { faction: Faction }): React.ReactElement {
|
||||
const p = player;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
@ -181,49 +148,51 @@ export class FactionRoot extends React.Component<IProps, IState> {
|
||||
<div className="faction-container">
|
||||
<h1>{faction.name}</h1>
|
||||
<Info faction={faction} factionInfo={factionInfo} />
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={this.manageGang} />}
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
||||
{!isPlayersGang && factionInfo.offerHackingMission && (
|
||||
<Option buttonText={"Hacking Mission"} infoText={hackingMissionInfo} onClick={this.startHackingMission} />
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={() => startHackingMission(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={this.startHackingContracts}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={this.startFieldWork} />
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerSecurityWork && (
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={this.startSecurityWork} />
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offersWork() && (
|
||||
<DonateOption
|
||||
faction={this.props.faction}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
faction={faction}
|
||||
p={player}
|
||||
rerender={rerender}
|
||||
favorToDonate={favorToDonate}
|
||||
disabled={!canDonate}
|
||||
/>
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={this.routeToPurchaseAugs} />
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={routeToPurchaseAugs} />
|
||||
{canPurchaseSleeves && (
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={this.sleevePurchases}
|
||||
onClick={sleevePurchases}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderAugmentationsPage(): React.ReactNode {
|
||||
return (
|
||||
<>
|
||||
<AugmentationsPage faction={this.props.faction} p={this.props.p} routeToMainPage={this.routeToMain} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={routeToMain} />
|
||||
) : (
|
||||
<MainPage faction={faction} />
|
||||
);
|
||||
}
|
81
src/Faction/ui/FactionsRoot.tsx
Normal file
81
src/Faction/ui/FactionsRoot.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { Factions } from "../Factions";
|
||||
import { Faction } from "../Faction";
|
||||
import { joinFaction } from "../FactionHelpers";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import Link from "@mui/material/Link";
|
||||
import Button from "@mui/material/Button";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import { Table, TableCell } from "../../ui/React/Table";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
function openFaction(faction: Faction): void {
|
||||
props.router.toFaction(faction);
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, faction: string): void {
|
||||
if (!event.isTrusted) return;
|
||||
joinFaction(Factions[faction]);
|
||||
setRerender((x) => !x);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h5" color="primary">
|
||||
Factions
|
||||
</Typography>
|
||||
<Typography>Lists all factions you have joined</Typography>
|
||||
<br />
|
||||
<Box display="flex" flexDirection="column">
|
||||
{props.player.factions.map((faction: string) => (
|
||||
<Link key={faction} variant="h6" onClick={() => openFaction(Factions[faction])}>
|
||||
{faction}
|
||||
</Link>
|
||||
))}
|
||||
</Box>
|
||||
<br />
|
||||
{props.player.factionInvitations.length > 0 && (
|
||||
<>
|
||||
<Typography variant="h5" color="primary">
|
||||
Outstanding Faction Invitations
|
||||
</Typography>
|
||||
<Typography>
|
||||
Lists factions you have been invited to. You can accept these faction invitations at any time.
|
||||
</Typography>
|
||||
<Table size="small" padding="none">
|
||||
<TableBody>
|
||||
{props.player.factionInvitations.map((faction: string) => (
|
||||
<TableRow key={faction}>
|
||||
<TableCell>
|
||||
<Typography noWrap>{faction}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Button onClick={(e) => acceptInvitation(e, faction)}>Join!</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -12,6 +12,7 @@ interface IProps {
|
||||
player: IPlayer;
|
||||
faction: Faction;
|
||||
aug: Augmentation;
|
||||
rerender: () => void;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
@ -24,6 +25,7 @@ export function PurchaseAugmentationPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
purchaseAugmentation(props.aug, props.faction);
|
||||
props.rerender();
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import * as React from "react";
|
||||
import { getNextNeurofluxLevel, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||
import { PurchaseAugmentationPopup } from "./PurchaseAugmentationPopup";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
@ -28,63 +27,56 @@ type IProps = {
|
||||
rerender: () => void;
|
||||
};
|
||||
|
||||
export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
aug: Augmentation;
|
||||
export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
||||
const aug = Augmentations[props.augName];
|
||||
if (aug == null) throw new Error(`aug ${props.augName} does not exists`);
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
const aug = Augmentations[this.props.augName];
|
||||
if (aug == null) throw new Error(`aug ${this.props.augName} does not exists`);
|
||||
this.aug = aug;
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
function getMoneyCost(): number {
|
||||
return aug.baseCost * props.faction.getInfo().augmentationPriceMult;
|
||||
}
|
||||
|
||||
getMoneyCost(): number {
|
||||
return this.aug.baseCost * this.props.faction.getInfo().augmentationPriceMult;
|
||||
function getRepCost(): number {
|
||||
return aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
getRepCost(): number {
|
||||
return this.aug.baseRepRequirement * this.props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
handleClick(): void {
|
||||
function handleClick(): void {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
const popupId = "purchase-augmentation-popup";
|
||||
createPopup(popupId, PurchaseAugmentationPopup, {
|
||||
aug: this.aug,
|
||||
faction: this.props.faction,
|
||||
player: this.props.p,
|
||||
aug: aug,
|
||||
faction: props.faction,
|
||||
player: props.p,
|
||||
rerender: props.rerender,
|
||||
popupId: popupId,
|
||||
});
|
||||
} else {
|
||||
purchaseAugmentation(this.aug, this.props.faction);
|
||||
purchaseAugmentation(aug, props.faction);
|
||||
props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the player has the prerequisite Augmentations
|
||||
hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(this.aug);
|
||||
function hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(aug);
|
||||
}
|
||||
|
||||
// Whether the player has enough rep for this Augmentation
|
||||
hasReputation(): boolean {
|
||||
return this.props.faction.playerReputation >= this.getRepCost();
|
||||
function hasReputation(): boolean {
|
||||
return props.faction.playerReputation >= getRepCost();
|
||||
}
|
||||
|
||||
// Whether the player has this augmentations (purchased OR installed)
|
||||
owned(): boolean {
|
||||
function owned(): boolean {
|
||||
let owned = false;
|
||||
for (const queuedAug of this.props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === this.props.augName) {
|
||||
for (const queuedAug of props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const installedAug of this.props.p.augmentations) {
|
||||
if (installedAug.name === this.props.augName) {
|
||||
for (const installedAug of props.p.augmentations) {
|
||||
if (installedAug.name === props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
@ -93,96 +85,94 @@ export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
return owned;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.aug == null) {
|
||||
console.error(
|
||||
`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${this.props.augName}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const moneyCost = this.getMoneyCost();
|
||||
const repCost = this.getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled = false;
|
||||
let status: JSX.Element = <></>;
|
||||
let color = "";
|
||||
if (!this.hasPrereqs()) {
|
||||
disabled = true;
|
||||
status = <>LOCKED (Requires {this.aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite)</>;
|
||||
color = "red";
|
||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||
disabled = true;
|
||||
} else if (this.hasReputation()) {
|
||||
status = (
|
||||
<>
|
||||
UNLOCKED (at {Reputation(repCost)} faction reputation) - <Money money={moneyCost} player={this.props.p} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
disabled = true;
|
||||
status = (
|
||||
<>
|
||||
LOCKED (Requires {Reputation(repCost)} faction reputation - <Money money={moneyCost} player={this.props.p} />)
|
||||
</>
|
||||
);
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
};
|
||||
if (color !== "") {
|
||||
txtStyle.color = color;
|
||||
}
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = this.aug.name;
|
||||
if (this.aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
let tooltip = <></>;
|
||||
if (typeof this.aug.info === "string")
|
||||
tooltip = (
|
||||
<>
|
||||
<span dangerouslySetInnerHTML={{ __html: this.aug.info }} />
|
||||
<br />
|
||||
<br />
|
||||
{this.aug.stats}
|
||||
</>
|
||||
);
|
||||
else
|
||||
tooltip = (
|
||||
<>
|
||||
{this.aug.info}
|
||||
<br />
|
||||
<br />
|
||||
{this.aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={this.aug.name}>
|
||||
<span
|
||||
style={{
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}}
|
||||
>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
text={btnTxt}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<p style={txtStyle}>{status}</p>
|
||||
</span>
|
||||
</li>
|
||||
if (aug == null) {
|
||||
console.error(
|
||||
`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${props.augName}`,
|
||||
);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const moneyCost = getMoneyCost();
|
||||
const repCost = getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled = false;
|
||||
let status: JSX.Element = <></>;
|
||||
let color = "";
|
||||
if (!hasPrereqs()) {
|
||||
disabled = true;
|
||||
status = <>LOCKED (Requires {aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite)</>;
|
||||
color = "red";
|
||||
} else if (aug.name !== AugmentationNames.NeuroFluxGovernor && (aug.owned || owned())) {
|
||||
disabled = true;
|
||||
} else if (hasReputation()) {
|
||||
status = (
|
||||
<>
|
||||
UNLOCKED (at {Reputation(repCost)} faction reputation) - <Money money={moneyCost} player={props.p} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
disabled = true;
|
||||
status = (
|
||||
<>
|
||||
LOCKED (Requires {Reputation(repCost)} faction reputation - <Money money={moneyCost} player={props.p} />)
|
||||
</>
|
||||
);
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
};
|
||||
if (color !== "") {
|
||||
txtStyle.color = color;
|
||||
}
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = aug.name;
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
let tooltip = <></>;
|
||||
if (typeof aug.info === "string")
|
||||
tooltip = (
|
||||
<>
|
||||
<span dangerouslySetInnerHTML={{ __html: aug.info }} />
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
else
|
||||
tooltip = (
|
||||
<>
|
||||
{aug.info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={aug.name}>
|
||||
<span
|
||||
style={{
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}}
|
||||
>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
text={btnTxt}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<p style={txtStyle}>{status}</p>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
@ -207,10 +207,10 @@ function setTheme() {
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_BACKGROUND_COLOR) &&
|
||||
/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(FconfSettings.THEME_PROMPT_COLOR)
|
||||
) {
|
||||
document.body.style.setProperty("--my-highlight-color", FconfSettings.THEME_HIGHLIGHT_COLOR);
|
||||
document.body.style.setProperty("--my-font-color", FconfSettings.THEME_FONT_COLOR);
|
||||
document.body.style.setProperty("--my-background-color", FconfSettings.THEME_BACKGROUND_COLOR);
|
||||
document.body.style.setProperty("--my-prompt-color", FconfSettings.THEME_PROMPT_COLOR);
|
||||
// document.body.style.setProperty("--my-highlight-color", FconfSettings.THEME_HIGHLIGHT_COLOR);
|
||||
// document.body.style.setProperty("--my-font-color", FconfSettings.THEME_FONT_COLOR);
|
||||
// document.body.style.setProperty("--my-background-color", FconfSettings.THEME_BACKGROUND_COLOR);
|
||||
// document.body.style.setProperty("--my-prompt-color", FconfSettings.THEME_PROMPT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { GangMemberUpgrade } from "./GangMemberUpgrade";
|
||||
import { GangMember } from "./GangMember";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IAscensionResult } from "./IAscensionResult";
|
||||
|
||||
export interface IGang {
|
||||
facName: string;
|
||||
@ -37,8 +38,9 @@ export interface IGang {
|
||||
getWantedPenalty(): number;
|
||||
calculatePower(): number;
|
||||
killMember(member: GangMember): void;
|
||||
ascendMember(member: GangMember, workerScript: WorkerScript): void;
|
||||
ascendMember(member: GangMember, workerScript: WorkerScript): IAscensionResult;
|
||||
getDiscount(): number;
|
||||
getAllTaskNames(): string[];
|
||||
getUpgradeCost(upg: GangMemberUpgrade): number;
|
||||
toJSON(): any;
|
||||
}
|
||||
|
@ -2,20 +2,19 @@
|
||||
* React Component for all the gang stuff.
|
||||
*/
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { ManagementSubpage } from "./ManagementSubpage";
|
||||
import { TerritorySubpage } from "./TerritorySubpage";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../Gang";
|
||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
|
||||
interface IProps {
|
||||
gang: Gang;
|
||||
player: IPlayer;
|
||||
engine: IEngine;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
export function GangRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [management, setManagement] = useState(true);
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
@ -25,8 +24,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
}, []);
|
||||
|
||||
function back(): void {
|
||||
props.engine.loadFactionContent();
|
||||
displayFactionContent(props.gang.facName);
|
||||
router.toFaction(Factions[props.gang.facName]);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -48,11 +46,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
>
|
||||
Gang Territory
|
||||
</a>
|
||||
{management ? (
|
||||
<ManagementSubpage gang={props.gang} player={props.player} />
|
||||
) : (
|
||||
<TerritorySubpage gang={props.gang} />
|
||||
)}
|
||||
{management ? <ManagementSubpage gang={props.gang} player={player} /> : <TerritorySubpage gang={props.gang} />}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -55,7 +55,9 @@ export function GangStats(props: IProps): React.ReactElement {
|
||||
</p>
|
||||
<br />
|
||||
<div>
|
||||
<p style={{ display: "inline-block" }}>Money gain rate: {MoneyRate(5 * props.gang.moneyGainRate)}</p>
|
||||
<p style={{ display: "inline-block" }}>
|
||||
Money gain rate: <MoneyRate money={5 * props.gang.moneyGainRate} />
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<p className="tooltip" style={{ display: "inline-block" }}>
|
||||
|
@ -28,7 +28,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
|
||||
const tasks = props.gang.getAllTaskNames();
|
||||
|
||||
const data = [
|
||||
[`Money:`, MoneyRate(5 * props.member.calculateMoneyGain(props.gang))],
|
||||
[`Money:`, <MoneyRate money={5 * props.member.calculateMoneyGain(props.gang)} />],
|
||||
[`Respect:`, `${numeralWrapper.formatRespect(5 * props.member.calculateRespectGain(props.gang))} / sec`],
|
||||
[`Wanted Level:`, `${numeralWrapper.formatWanted(5 * props.member.calculateWantedLevelGain(props.gang))} / sec`],
|
||||
[`Total Respect:`, `${numeralWrapper.formatRespect(props.member.earnedRespect)}`],
|
||||
@ -46,7 +46,9 @@ export function TaskSelector(props: IProps): React.ReactElement {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div>{StatsTable(data)}</div>
|
||||
<div>
|
||||
<StatsTable rows={data} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
13
src/HackingMission/ui/HackingMissionRoot.tsx
Normal file
13
src/HackingMission/ui/HackingMissionRoot.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { startHackingMission } from "../../Faction/FactionHelpers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
|
||||
interface IProps {
|
||||
faction: Faction;
|
||||
}
|
||||
|
||||
export function HackingMissionRoot(props: IProps): React.ReactElement {
|
||||
useEffect(() => startHackingMission(props.faction));
|
||||
return <div id="mission-container"></div>;
|
||||
}
|
@ -144,7 +144,8 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
|
||||
<div className={"row"}>
|
||||
<p>Production:</p>
|
||||
<span className={"text money-gold"}>
|
||||
<Money money={node.totalMoneyGenerated} player={props.player} /> ({MoneyRate(node.moneyGainRatePerSecond)})
|
||||
<Money money={node.totalMoneyGenerated} player={props.player} /> (
|
||||
<MoneyRate money={node.moneyGainRatePerSecond} />)
|
||||
</span>
|
||||
</div>
|
||||
<div className={"row"}>
|
||||
|
@ -25,7 +25,7 @@ export function PlayerInfo(props: IProps): React.ReactElement {
|
||||
if (hasServers) {
|
||||
prod = HashRate(props.totalProduction);
|
||||
} else {
|
||||
prod = MoneyRate(props.totalProduction);
|
||||
prod = <MoneyRate money={props.totalProduction} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -30,4 +30,5 @@ export interface IEngine {
|
||||
loadMissionContent: () => void;
|
||||
loadResleevingContent: () => void;
|
||||
loadGameOptionsContent: () => void;
|
||||
load: (save: string) => void;
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
import { Page, routing } from ".././ui/navigationTracking";
|
||||
import { Root } from "./ui/Root";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../IEngine";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
let container: HTMLElement;
|
||||
|
||||
(function () {
|
||||
function setContainer(): void {
|
||||
const c = document.getElementById("infiltration-container");
|
||||
if (c === null) throw new Error("huh?");
|
||||
container = c;
|
||||
document.removeEventListener("DOMContentLoaded", setContainer);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", setContainer);
|
||||
})();
|
||||
|
||||
function calcDifficulty(player: IPlayer, startingDifficulty: number): number {
|
||||
const totalStats = player.strength + player.defense + player.dexterity + player.agility + player.charisma;
|
||||
const difficulty = startingDifficulty - Math.pow(totalStats, 0.9) / 250 - player.intelligence / 1600;
|
||||
if (difficulty < 0) return 0;
|
||||
if (difficulty > 3) return 3;
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
export function displayInfiltrationContent(
|
||||
engine: IEngine,
|
||||
player: IPlayer,
|
||||
location: string,
|
||||
startingDifficulty: number,
|
||||
maxLevel: number,
|
||||
): void {
|
||||
if (!routing.isOn(Page.Infiltration)) return;
|
||||
|
||||
const difficulty = calcDifficulty(player, startingDifficulty);
|
||||
|
||||
ReactDOM.render(
|
||||
<Root
|
||||
Engine={engine}
|
||||
Player={player}
|
||||
Location={location}
|
||||
StartingDifficulty={startingDifficulty}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={maxLevel}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Countdown } from "./Countdown";
|
||||
@ -14,8 +13,6 @@ import { WireCuttingGame } from "./WireCuttingGame";
|
||||
import { Victory } from "./Victory";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
@ -40,6 +37,8 @@ const minigames = [
|
||||
];
|
||||
|
||||
export function Game(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [level, setLevel] = useState(1);
|
||||
const [stage, setStage] = useState(Stage.Countdown);
|
||||
const [results, setResults] = useState("");
|
||||
@ -89,12 +88,10 @@ export function Game(props: IProps): React.ReactElement {
|
||||
pushResult(false);
|
||||
// Kill the player immediately if they use automation, so
|
||||
// it's clear they're not meant to
|
||||
const damage = options?.automated ? props.Player.hp : props.StartingDifficulty * 3;
|
||||
if (props.Player.takeDamage(damage)) {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (menu === null) throw new Error("mainmenu-container not found");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
const damage = options?.automated ? player.hp : props.StartingDifficulty * 3;
|
||||
if (player.takeDamage(damage)) {
|
||||
router.toCity();
|
||||
return;
|
||||
}
|
||||
setupNextGame();
|
||||
}
|
||||
@ -112,8 +109,6 @@ export function Game(props: IProps): React.ReactElement {
|
||||
case Stage.Sell:
|
||||
stageComponent = (
|
||||
<Victory
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
StartingDifficulty={props.StartingDifficulty}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
|
51
src/Infiltration/ui/InfiltrationRoot.tsx
Normal file
51
src/Infiltration/ui/InfiltrationRoot.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import React, { useState } from "react";
|
||||
import { Intro } from "./Intro";
|
||||
import { Game } from "./Game";
|
||||
import { Location } from "../../Locations/Location";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IProps {
|
||||
location: Location;
|
||||
}
|
||||
function calcDifficulty(player: IPlayer, startingDifficulty: number): number {
|
||||
const totalStats = player.strength + player.defense + player.dexterity + player.agility + player.charisma;
|
||||
const difficulty = startingDifficulty - Math.pow(totalStats, 0.9) / 250 - player.intelligence / 1600;
|
||||
if (difficulty < 0) return 0;
|
||||
if (difficulty > 3) return 3;
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
export function InfiltrationRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [start, setStart] = useState(false);
|
||||
|
||||
if (props.location.infiltrationData === undefined) throw new Error("Trying to do infiltration on invalid location.");
|
||||
const startingDifficulty = props.location.infiltrationData.startingSecurityLevel;
|
||||
const difficulty = calcDifficulty(player, startingDifficulty);
|
||||
|
||||
function cancel(): void {
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
return (
|
||||
<Intro
|
||||
Location={props.location}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
||||
start={() => setStart(true)}
|
||||
cancel={cancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Game
|
||||
StartingDifficulty={startingDifficulty}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={props.location.infiltrationData.maxClearanceLevel}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { Location } from "../../Locations/Location";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
Location: string;
|
||||
Location: Location;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
start: () => void;
|
||||
@ -51,11 +48,12 @@ function coloredArrow(difficulty: number): JSX.Element {
|
||||
}
|
||||
|
||||
export function Intro(props: IProps): React.ReactElement {
|
||||
console.log(props);
|
||||
return (
|
||||
<>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={10}>
|
||||
<h1>Infiltrating {props.Location}</h1>
|
||||
<h1>Infiltrating {props.Location.name}</h1>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<h2>Maximum level: {props.MaxLevel}</h2>
|
||||
|
@ -1,49 +0,0 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React, { useState } from "react";
|
||||
import { Intro } from "./Intro";
|
||||
import { Game } from "./Game";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
Location: string;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
const [start, setStart] = useState(false);
|
||||
|
||||
function cancel(): void {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (menu === null) throw new Error("mainmenu-container not found");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
return (
|
||||
<Intro
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
Location={props.Location}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
start={() => setStart(true)}
|
||||
cancel={cancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Game
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
StartingDifficulty={props.StartingDifficulty}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import React, { useState } from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
@ -7,23 +5,21 @@ import Grid from "@mui/material/Grid";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
}
|
||||
|
||||
export function Victory(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [faction, setFaction] = useState("none");
|
||||
|
||||
function quitInfiltration(): void {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (!menu) throw new Error("mainmenu-container somehow null");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
const levelBonus = props.MaxLevel * Math.pow(1.01, props.MaxLevel);
|
||||
@ -43,8 +39,8 @@ export function Victory(props: IProps): React.ReactElement {
|
||||
BitNodeMultipliers.InfiltrationMoney;
|
||||
|
||||
function sell(): void {
|
||||
props.Player.gainMoney(moneyGain);
|
||||
props.Player.recordMoneySource(moneyGain, "infiltration");
|
||||
player.gainMoney(moneyGain);
|
||||
player.recordMoneySource(moneyGain, "infiltration");
|
||||
quitInfiltration();
|
||||
}
|
||||
|
||||
@ -70,7 +66,7 @@ export function Victory(props: IProps): React.ReactElement {
|
||||
<option key={"none"} value={"none"}>
|
||||
{"none"}
|
||||
</option>
|
||||
{props.Player.factions
|
||||
{player.factions
|
||||
.filter((f) => Factions[f].getInfo().offersWork())
|
||||
.map((f) => (
|
||||
<option key={f} value={f}>
|
||||
|
3
src/InteractiveTutorial.d.ts
vendored
3
src/InteractiveTutorial.d.ts
vendored
@ -1,3 +0,0 @@
|
||||
export declare function iTutorialNextStep(): void;
|
||||
export declare const ITutorial: { isRunning: boolean; currStep: number };
|
||||
export declare const iTutorialSteps: { [key: string]: number };
|
@ -1,494 +0,0 @@
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
|
||||
import { LiteratureNames } from "./Literature/data/LiteratureNames";
|
||||
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
// Ordered array of keys to Interactive Tutorial Steps
|
||||
const orderedITutorialSteps = [
|
||||
"Start",
|
||||
"GoToCharacterPage", // Click on 'Stats' page
|
||||
"CharacterPage", // Introduction to 'Stats' page
|
||||
"CharacterGoToTerminalPage", // Go back to Terminal
|
||||
"TerminalIntro", // Introduction to Terminal
|
||||
"TerminalHelp", // Using 'help' Terminal command
|
||||
"TerminalLs", // Using 'ls' Terminal command
|
||||
"TerminalScan", // Using 'scan' Terminal command
|
||||
"TerminalScanAnalyze1", // Using 'scan-analyze' Terminal command
|
||||
"TerminalScanAnalyze2", // Using 'scan-analyze 3' Terminal command
|
||||
"TerminalConnect", // Connecting to n00dles
|
||||
"TerminalAnalyze", // Analyzing n00dles
|
||||
"TerminalNuke", // NUKE n00dles
|
||||
"TerminalManualHack", // Hack n00dles
|
||||
"TerminalHackingMechanics", // Explanation of hacking mechanics
|
||||
"TerminalCreateScript", // Create a script using 'nano'
|
||||
"TerminalTypeScript", // Script Editor page - Type script and then save & close
|
||||
"TerminalFree", // Using 'Free' Terminal command
|
||||
"TerminalRunScript", // Running script using 'run' Terminal command
|
||||
"TerminalGoToActiveScriptsPage",
|
||||
"ActiveScriptsPage",
|
||||
"ActiveScriptsToTerminal",
|
||||
"TerminalTailScript",
|
||||
"GoToHacknetNodesPage",
|
||||
"HacknetNodesIntroduction",
|
||||
"HacknetNodesGoToWorldPage",
|
||||
"WorldDescription",
|
||||
"TutorialPageInfo",
|
||||
"End",
|
||||
];
|
||||
|
||||
// Create an 'enum' for the Steps
|
||||
const iTutorialSteps = {};
|
||||
for (let i = 0; i < orderedITutorialSteps.length; ++i) {
|
||||
iTutorialSteps[orderedITutorialSteps[i]] = i;
|
||||
}
|
||||
|
||||
const ITutorial = {
|
||||
currStep: 0, // iTutorialSteps.Start
|
||||
isRunning: false,
|
||||
|
||||
// Keeps track of whether each step has been done
|
||||
stepIsDone: {},
|
||||
};
|
||||
|
||||
function iTutorialStart() {
|
||||
// Initialize Interactive Tutorial state by settings 'done' for each state to false
|
||||
ITutorial.stepIsDone = {};
|
||||
for (let i = 0; i < orderedITutorialSteps.length; ++i) {
|
||||
ITutorial.stepIsDone[i] = false;
|
||||
}
|
||||
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
// Don't autosave during this interactive tutorial
|
||||
Engine.Counters.autoSaveCounter = Infinity;
|
||||
ITutorial.currStep = 0;
|
||||
ITutorial.isRunning = true;
|
||||
|
||||
document.getElementById("interactive-tutorial-container").style.display = "block";
|
||||
|
||||
// Exit tutorial button
|
||||
const exitButton = clearEventListeners("interactive-tutorial-exit");
|
||||
exitButton.addEventListener("click", function () {
|
||||
iTutorialEnd();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Back button
|
||||
const backButton = clearEventListeners("interactive-tutorial-back");
|
||||
backButton.addEventListener("click", function () {
|
||||
iTutorialPrevStep();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Next button
|
||||
const nextButton = clearEventListeners("interactive-tutorial-next");
|
||||
nextButton.addEventListener("click", function () {
|
||||
iTutorialNextStep();
|
||||
return false;
|
||||
});
|
||||
|
||||
iTutorialEvaluateStep();
|
||||
}
|
||||
|
||||
function iTutorialEvaluateStep() {
|
||||
if (!ITutorial.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable and clear main menu
|
||||
// const terminalMainMenu = clearEventListeners("terminal-menu-link");
|
||||
// const statsMainMenu = clearEventListeners("stats-menu-link");
|
||||
// const activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link");
|
||||
// const hacknetMainMenu = clearEventListeners("hacknet-nodes-menu-link");
|
||||
// const cityMainMenu = clearEventListeners("city-menu-link");
|
||||
// const tutorialMainMenu = clearEventListeners("tutorial-menu-link");
|
||||
// terminalMainMenu.removeAttribute("class");
|
||||
// statsMainMenu.removeAttribute("class");
|
||||
// activeScriptsMainMenu.removeAttribute("class");
|
||||
// hacknetMainMenu.removeAttribute("class");
|
||||
// cityMainMenu.removeAttribute("class");
|
||||
// tutorialMainMenu.removeAttribute("class");
|
||||
|
||||
// Interactive Tutorial Next button
|
||||
const nextBtn = document.getElementById("interactive-tutorial-next");
|
||||
|
||||
switch (ITutorial.currStep) {
|
||||
case iTutorialSteps.Start:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Welcome to Bitburner, a cyberpunk-themed incremental RPG! " +
|
||||
"The game takes place in a dark, dystopian future... The year is 2077...<br><br>" +
|
||||
"This tutorial will show you the basics of the game. " +
|
||||
"You may skip the tutorial at any time.",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
break;
|
||||
case iTutorialSteps.GoToCharacterPage:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Let's start by heading to the Stats page. Click the <code class='interactive-tutorial-tab flashing-button'>Stats</code> tab on " +
|
||||
"the main navigation menu (left-hand side of the screen)",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.CharacterPage:
|
||||
Engine.loadCharacterContent();
|
||||
iTutorialSetText(
|
||||
"The <code class='interactive-tutorial-tab'>Stats</code> page shows a lot of important information about your progress, " +
|
||||
"such as your skills, money, and bonuses. ",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
break;
|
||||
case iTutorialSteps.CharacterGoToTerminalPage:
|
||||
Engine.loadCharacterContent();
|
||||
iTutorialSetText(
|
||||
"Let's head to your computer's terminal by clicking the <code class='interactive-tutorial-tab flashing-button'>Terminal</code> tab on the " +
|
||||
"main navigation menu.",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.TerminalIntro:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"The <code class='interactive-tutorial-tab'>Terminal</code> is used to interface with your home computer as well as " +
|
||||
"all of the other machines around the world.",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
break;
|
||||
case iTutorialSteps.TerminalHelp:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Let's try it out. Start by entering the <code class='interactive-tutorial-command'>help</code> command into the <code class='interactive-tutorial-tab'>Terminal</code> " +
|
||||
"(Don't forget to press Enter after typing the command)",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalLs:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"The <code class='interactive-tutorial-command'>help</code> command displays a list of all available <code class='interactive-tutorial-tab'>Terminal</code> commands, how to use them, " +
|
||||
"and a description of what they do. <br><br>Let's try another command. Enter the <code class='interactive-tutorial-command'>ls</code> command.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalScan:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
" <code class='interactive-tutorial-command'>ls</code> is a basic command that shows files " +
|
||||
"on the computer. Right now, it shows that you have a program called <code class='interactive-tutorial-command'>NUKE.exe</code> on your computer. " +
|
||||
"We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " +
|
||||
"to other machines throughout the world. Let's do that now by first entering " +
|
||||
"the <code class='interactive-tutorial-command'>scan</code> command.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalScanAnalyze1:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"The <code class='interactive-tutorial-command'>scan</code> command shows all available network connections. In other words, " +
|
||||
"it displays a list of all servers that can be connected to from your " +
|
||||
"current machine. A server is identified by its hostname. <br><br> " +
|
||||
"That's great and all, but there's so many servers. Which one should you go to? " +
|
||||
"The <code class='interactive-tutorial-command'>scan-analyze</code> command gives some more detailed information about servers on the " +
|
||||
"network. Try it now!",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalScanAnalyze2:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"You just ran <code class='interactive-tutorial-command'>scan-analyze</code> with a depth of one. This command shows more detailed " +
|
||||
"information about each server that you can connect to (servers that are a distance of " +
|
||||
"one node away). <br><br> It is also possible to run <code class='interactive-tutorial-command'>scan-analyze</code> with " +
|
||||
"a higher depth. Let's try a depth of two with the following command: <code class='interactive-tutorial-command'>scan-analyze 2</code>.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalConnect:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Now you can see information about all servers that are up to two nodes away, as well " +
|
||||
"as figure out how to navigate to those servers through the network. You can only connect to " +
|
||||
"a server that is one node away. To connect to a machine, use the <code class='interactive-tutorial-command'>connect [hostname]</code> command.<br><br>" +
|
||||
"From the results of the <code class='interactive-tutorial-command'>scan-analyze</code> command, we can see that the <code class='interactive-tutorial-command'>n00dles</code> server is " +
|
||||
"only one node away. Let's connect so it now using: <code class='interactive-tutorial-command'>connect n00dles</code>",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalAnalyze:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"You are now connected to another machine! What can you do now? You can hack it!<br><br> In the year 2077, currency has " +
|
||||
"become digital and decentralized. People and corporations store their money " +
|
||||
"on servers and computers. Using your hacking abilities, you can hack servers " +
|
||||
"to steal money and gain experience. <br><br> " +
|
||||
"Before you try to hack a server, you should run diagnostics using the <code class='interactive-tutorial-command'>analyze</code> command.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalNuke:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"When the <code class='interactive-tutorial-command'>analyze</code> command finishes running it will show useful information " +
|
||||
"about hacking the server. <br><br> For this server, the required hacking skill is only <span class='character-hack-cell'>1</span>, " +
|
||||
"which means you can hack it right now. However, in order to hack a server " +
|
||||
"you must first gain root access. The <code class='interactive-tutorial-command'>NUKE.exe</code> program that we saw earlier on your " +
|
||||
"home computer is a virus that will grant you root access to a machine if there are enough " +
|
||||
"open ports.<br><br> The <code class='interactive-tutorial-command'>analyze</code> results shows that there do not need to be any open ports " +
|
||||
"on this machine for the NUKE virus to work, so go ahead and run the virus using the " +
|
||||
"<code class='interactive-tutorial-command'>run NUKE.exe</code> command.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalManualHack:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"You now have root access! You can hack the server using the <code class='interactive-tutorial-command'>hack</code> command. " +
|
||||
"Try doing that now.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalHackingMechanics:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"You are now attempting to hack the server. Performing a hack takes time and " +
|
||||
"only has a certain percentage chance " +
|
||||
"of success. This time and success chance is determined by a variety of factors, including " +
|
||||
"your hacking skill and the server's security level.<br><br>" +
|
||||
"If your attempt to hack the server is successful, you will steal a certain percentage " +
|
||||
"of the server's total money. This percentage is affected by your hacking skill and " +
|
||||
"the server's security level.<br><br>The amount of money on a server is not limitless. So, if " +
|
||||
"you constantly hack a server and deplete its money, then you will encounter " +
|
||||
"diminishing returns in your hacking.",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
break;
|
||||
case iTutorialSteps.TerminalCreateScript:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Hacking is the core mechanic of the game and is necessary for progressing. However, " +
|
||||
"you don't want to be hacking manually the entire time. You can automate your hacking " +
|
||||
"by writing scripts!<br><br>To create a new script or edit an existing one, you can use the <code class='interactive-tutorial-command'>nano</code> " +
|
||||
"command. Scripts must end with the <code class='interactive-tutorial-command'>.script</code> extension. Let's make a script now by " +
|
||||
"entering <code class='interactive-tutorial-command'>nano n00dles.script</code> after the hack command finishes running (Sidenote: Pressing ctrl + c" +
|
||||
" will end a command like hack early)",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalTypeScript:
|
||||
Engine.loadScriptEditorContent("n00dles.script", "");
|
||||
iTutorialSetText(
|
||||
"This is the script editor. You can use it to program your scripts. Scripts are " +
|
||||
"written in a simplified version of javascript. Copy and paste the following code into the script editor: <br><br>" +
|
||||
"<pre class='interactive-tutorial-code'>" +
|
||||
"while(true) {\n" +
|
||||
" hack('n00dles');\n" +
|
||||
"}</pre>" +
|
||||
"For anyone with basic programming experience, this code should be straightforward. " +
|
||||
"This script will continuously hack the <code class='interactive-tutorial-command'>n00dles</code> server.<br><br>" +
|
||||
"To save and close the script editor, press the button in the bottom left, or press ctrl + b.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js)
|
||||
break;
|
||||
case iTutorialSteps.TerminalFree:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Now we'll run the script. Scripts require a certain amount of RAM to run, and can be " +
|
||||
"run on any machine which you have root access to. Different servers have different " +
|
||||
"amounts of RAM. You can also purchase more RAM for your home server.<br><br>To check how much " +
|
||||
"RAM is available on this machine, enter the <code class='interactive-tutorial-command'>free</code> command.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal commmand
|
||||
break;
|
||||
case iTutorialSteps.TerminalRunScript:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"We have 4GB of free RAM on this machine, which is enough to run our " +
|
||||
"script. Let's run our script using <code class='interactive-tutorial-command'>run n00dles.script</code>.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal commmand
|
||||
break;
|
||||
case iTutorialSteps.TerminalGoToActiveScriptsPage:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Your script is now running! " +
|
||||
"It will continuously run in the background and will automatically stop if " +
|
||||
"the code ever completes (the <code class='interactive-tutorial-command'>n00dles.script</code> will never complete because it " +
|
||||
"runs an infinite loop). <br><br>These scripts can passively earn you income and hacking experience. " +
|
||||
"Your scripts will also earn money and experience while you are offline, although at a " +
|
||||
"slightly slower rate. <br><br> " +
|
||||
"Let's check out some statistics for our running scripts by clicking the " +
|
||||
"<code class='interactive-tutorial-tab flashing-button'>Active Scripts</code> link in the main navigation menu.",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.ActiveScriptsPage:
|
||||
Engine.loadActiveScriptsContent();
|
||||
iTutorialSetText(
|
||||
"This page displays information about all of your scripts that are " +
|
||||
"running across every server. You can use this to gauge how well " +
|
||||
"your scripts are doing. Let's go back to the <code class='interactive-tutorial-tab flashing-button'>Terminal</code>",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.ActiveScriptsToTerminal:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"One last thing about scripts, each active script contains logs that detail " +
|
||||
"what it's doing. We can check these logs using the <code class='interactive-tutorial-command'>tail</code> command. Do that " +
|
||||
"now for the script we just ran by typing <code class='interactive-tutorial-command'>tail n00dles.script</code>",
|
||||
);
|
||||
nextBtn.style.display = "none"; // next step triggered by terminal command
|
||||
break;
|
||||
case iTutorialSteps.TerminalTailScript:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"The log for this script won't show much right now (it might show nothing at all) because it " +
|
||||
"just started running...but check back again in a few minutes! <br><br>" +
|
||||
"This covers the basics of hacking. To learn more about writing " +
|
||||
"scripts, select the <code class='interactive-tutorial-tab'>Tutorial</code> link in the " +
|
||||
"main navigation menu to look at the documentation. " +
|
||||
"<strong style='background-color:#444;'>If you are an experienced JavaScript " +
|
||||
"developer, I would highly suggest you check out the section on " +
|
||||
"NetscriptJS/Netscript 2.0, it's faster and more powerful.</strong><br><br>For now, let's move on to something else!",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
break;
|
||||
case iTutorialSteps.GoToHacknetNodesPage:
|
||||
Engine.loadTerminalContent();
|
||||
iTutorialSetText(
|
||||
"Hacking is not the only way to earn money. One other way to passively " +
|
||||
"earn money is by purchasing and upgrading Hacknet Nodes. Let's go to " +
|
||||
"the <code class='interactive-tutorial-tab flashing-button'>Hacknet</code> page through the main navigation menu now.",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.HacknetNodesIntroduction:
|
||||
Engine.loadHacknetNodesContent();
|
||||
iTutorialSetText(
|
||||
"here you can purchase new Hacknet Nodes and upgrade your " + "existing ones. Let's purchase a new one now.",
|
||||
);
|
||||
nextBtn.style.display = "none"; // Next step triggered by purchaseHacknet() (HacknetNode.js)
|
||||
break;
|
||||
case iTutorialSteps.HacknetNodesGoToWorldPage:
|
||||
Engine.loadHacknetNodesContent();
|
||||
iTutorialSetText(
|
||||
"You just purchased a Hacknet Node! This Hacknet Node will passively " +
|
||||
"earn you money over time, both online and offline. When you get enough " +
|
||||
" money, you can upgrade " +
|
||||
"your newly-purchased Hacknet Node below.<br><br>" +
|
||||
"Let's go to the <code class='interactive-tutorial-tab flashing-button'>City</code> page through the main navigation menu.",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.WorldDescription:
|
||||
Engine.loadLocationContent();
|
||||
iTutorialSetText(
|
||||
"This page lists all of the different locations you can currently " +
|
||||
"travel to. Each location has something that you can do. " +
|
||||
"There's a lot of content out in the world, make sure " +
|
||||
"you explore and discover!<br><br>" +
|
||||
"Lastly, click on the <code class='interactive-tutorial-tab flashing-button'>Tutorial</code> link in the main navigation menu.",
|
||||
);
|
||||
nextBtn.style.display = "none";
|
||||
break;
|
||||
case iTutorialSteps.TutorialPageInfo:
|
||||
Engine.loadTutorialContent();
|
||||
iTutorialSetText(
|
||||
"This page contains a lot of different documentation about the game's " +
|
||||
"content and mechanics. <strong style='background-color:#444;'> I know it's a lot, but I highly suggest you read " +
|
||||
"(or at least skim) through this before you start playing</strong>. That's the end of the tutorial. " +
|
||||
"Hope you enjoy the game!",
|
||||
);
|
||||
nextBtn.style.display = "inline-block";
|
||||
nextBtn.innerHTML = "Finish Tutorial";
|
||||
break;
|
||||
case iTutorialSteps.End:
|
||||
iTutorialEnd();
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid tutorial step");
|
||||
}
|
||||
|
||||
if (ITutorial.stepIsDone[ITutorial.currStep] === true) {
|
||||
nextBtn.style.display = "inline-block";
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the next step and evaluate it
|
||||
function iTutorialNextStep() {
|
||||
ITutorial.stepIsDone[ITutorial.currStep] = true;
|
||||
if (ITutorial.currStep < iTutorialSteps.End) {
|
||||
ITutorial.currStep += 1;
|
||||
}
|
||||
iTutorialEvaluateStep();
|
||||
}
|
||||
|
||||
// Go to previous step and evaluate
|
||||
function iTutorialPrevStep() {
|
||||
if (ITutorial.currStep > iTutorialSteps.Start) {
|
||||
ITutorial.currStep -= 1;
|
||||
}
|
||||
iTutorialEvaluateStep();
|
||||
}
|
||||
|
||||
function iTutorialEnd() {
|
||||
// Re-enable auto save
|
||||
if (Settings.AutosaveInterval === 0) {
|
||||
Engine.Counters.autoSaveCounter = Infinity;
|
||||
} else {
|
||||
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
||||
}
|
||||
|
||||
Engine.init();
|
||||
|
||||
ITutorial.currStep = iTutorialSteps.End;
|
||||
ITutorial.isRunning = false;
|
||||
document.getElementById("interactive-tutorial-container").style.display = "none";
|
||||
|
||||
// Create a popup with final introductory stuff
|
||||
const popupId = "interactive-tutorial-ending-popup";
|
||||
const txt = createElement("p", {
|
||||
innerHTML:
|
||||
"If you are new to the game, the following links may be useful for you!<br><br>" +
|
||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html' target='_blank'>Getting Started Guide</a>" +
|
||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/' target='_blank'>Documentation</a><br><br>" +
|
||||
"The Beginner's Guide to Hacking was added to your home computer! It contains some tips/pointers for starting out with the game. " +
|
||||
"To read it, go to Terminal and enter<br><br>cat " +
|
||||
LiteratureNames.HackersStartingHandbook,
|
||||
});
|
||||
const gotitBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
float: "right",
|
||||
padding: "6px",
|
||||
innerText: "Got it!",
|
||||
clickListener: () => {
|
||||
removeElementById(popupId);
|
||||
},
|
||||
});
|
||||
createPopup(popupId, [txt, gotitBtn]);
|
||||
|
||||
Player.getHomeComputer().messages.push(LiteratureNames.HackersStartingHandbook);
|
||||
}
|
||||
|
||||
let textBox = null;
|
||||
(function () {
|
||||
function set() {
|
||||
textBox = document.getElementById("interactive-tutorial-text");
|
||||
document.removeEventListener("DOMContentLoaded", set);
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", set);
|
||||
})();
|
||||
|
||||
function iTutorialSetText(txt) {
|
||||
textBox.innerHTML = txt;
|
||||
textBox.parentElement.scrollTop = 0; // this resets scroll position
|
||||
}
|
||||
|
||||
export { iTutorialSteps, iTutorialEnd, iTutorialStart, iTutorialNextStep, ITutorial };
|
170
src/InteractiveTutorial.ts
Normal file
170
src/InteractiveTutorial.ts
Normal file
@ -0,0 +1,170 @@
|
||||
import { Player } from "./Player";
|
||||
|
||||
import { LiteratureNames } from "./Literature/data/LiteratureNames";
|
||||
|
||||
import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents";
|
||||
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
|
||||
// Ordered array of keys to Interactive Tutorial Steps
|
||||
enum iTutorialSteps {
|
||||
Start,
|
||||
GoToCharacterPage, // Click on 'Stats' page
|
||||
CharacterPage, // Introduction to 'Stats' page
|
||||
CharacterGoToTerminalPage, // Go back to Terminal
|
||||
TerminalIntro, // Introduction to Terminal
|
||||
TerminalHelp, // Using 'help' Terminal command
|
||||
TerminalLs, // Using 'ls' Terminal command
|
||||
TerminalScan, // Using 'scan' Terminal command
|
||||
TerminalScanAnalyze1, // Using 'scan-analyze' Terminal command
|
||||
TerminalScanAnalyze2, // Using 'scan-analyze 3' Terminal command
|
||||
TerminalConnect, // Connecting to n00dles
|
||||
TerminalAnalyze, // Analyzing n00dles
|
||||
TerminalNuke, // NUKE n00dles
|
||||
TerminalManualHack, // Hack n00dles
|
||||
TerminalHackingMechanics, // Explanation of hacking mechanics
|
||||
TerminalGoHome, // Go home before creating a script.
|
||||
TerminalCreateScript, // Create a script using 'nano'
|
||||
TerminalTypeScript, // Script Editor page - Type script and then save & close
|
||||
TerminalFree, // Using 'Free' Terminal command
|
||||
TerminalRunScript, // Running script using 'run' Terminal command
|
||||
TerminalGoToActiveScriptsPage,
|
||||
ActiveScriptsPage,
|
||||
ActiveScriptsToTerminal,
|
||||
TerminalTailScript,
|
||||
GoToHacknetNodesPage,
|
||||
HacknetNodesIntroduction,
|
||||
HacknetNodesGoToWorldPage,
|
||||
WorldDescription,
|
||||
TutorialPageInfo,
|
||||
End,
|
||||
}
|
||||
|
||||
const ITutorial: {
|
||||
currStep: iTutorialSteps;
|
||||
isRunning: boolean;
|
||||
stepIsDone: {
|
||||
[iTutorialSteps.Start]: boolean;
|
||||
[iTutorialSteps.GoToCharacterPage]: boolean;
|
||||
[iTutorialSteps.CharacterPage]: boolean;
|
||||
[iTutorialSteps.CharacterGoToTerminalPage]: boolean;
|
||||
[iTutorialSteps.TerminalIntro]: boolean;
|
||||
[iTutorialSteps.TerminalHelp]: boolean;
|
||||
[iTutorialSteps.TerminalLs]: boolean;
|
||||
[iTutorialSteps.TerminalScan]: boolean;
|
||||
[iTutorialSteps.TerminalScanAnalyze1]: boolean;
|
||||
[iTutorialSteps.TerminalScanAnalyze2]: boolean;
|
||||
[iTutorialSteps.TerminalConnect]: boolean;
|
||||
[iTutorialSteps.TerminalAnalyze]: boolean;
|
||||
[iTutorialSteps.TerminalNuke]: boolean;
|
||||
[iTutorialSteps.TerminalManualHack]: boolean;
|
||||
[iTutorialSteps.TerminalHackingMechanics]: boolean;
|
||||
[iTutorialSteps.TerminalGoHome]: boolean;
|
||||
[iTutorialSteps.TerminalCreateScript]: boolean;
|
||||
[iTutorialSteps.TerminalTypeScript]: boolean;
|
||||
[iTutorialSteps.TerminalFree]: boolean;
|
||||
[iTutorialSteps.TerminalRunScript]: boolean;
|
||||
[iTutorialSteps.TerminalGoToActiveScriptsPage]: boolean;
|
||||
[iTutorialSteps.ActiveScriptsPage]: boolean;
|
||||
[iTutorialSteps.ActiveScriptsToTerminal]: boolean;
|
||||
[iTutorialSteps.TerminalTailScript]: boolean;
|
||||
[iTutorialSteps.GoToHacknetNodesPage]: boolean;
|
||||
[iTutorialSteps.HacknetNodesIntroduction]: boolean;
|
||||
[iTutorialSteps.HacknetNodesGoToWorldPage]: boolean;
|
||||
[iTutorialSteps.WorldDescription]: boolean;
|
||||
[iTutorialSteps.TutorialPageInfo]: boolean;
|
||||
[iTutorialSteps.End]: boolean;
|
||||
};
|
||||
} = {
|
||||
currStep: iTutorialSteps.Start,
|
||||
isRunning: false,
|
||||
|
||||
// Keeps track of whether each step has been done
|
||||
stepIsDone: {
|
||||
[iTutorialSteps.Start]: false,
|
||||
[iTutorialSteps.GoToCharacterPage]: false,
|
||||
[iTutorialSteps.CharacterPage]: false,
|
||||
[iTutorialSteps.CharacterGoToTerminalPage]: false,
|
||||
[iTutorialSteps.TerminalIntro]: false,
|
||||
[iTutorialSteps.TerminalHelp]: false,
|
||||
[iTutorialSteps.TerminalLs]: false,
|
||||
[iTutorialSteps.TerminalScan]: false,
|
||||
[iTutorialSteps.TerminalScanAnalyze1]: false,
|
||||
[iTutorialSteps.TerminalScanAnalyze2]: false,
|
||||
[iTutorialSteps.TerminalConnect]: false,
|
||||
[iTutorialSteps.TerminalAnalyze]: false,
|
||||
[iTutorialSteps.TerminalNuke]: false,
|
||||
[iTutorialSteps.TerminalManualHack]: false,
|
||||
[iTutorialSteps.TerminalHackingMechanics]: false,
|
||||
[iTutorialSteps.TerminalGoHome]: false,
|
||||
[iTutorialSteps.TerminalCreateScript]: false,
|
||||
[iTutorialSteps.TerminalTypeScript]: false,
|
||||
[iTutorialSteps.TerminalFree]: false,
|
||||
[iTutorialSteps.TerminalRunScript]: false,
|
||||
[iTutorialSteps.TerminalGoToActiveScriptsPage]: false,
|
||||
[iTutorialSteps.ActiveScriptsPage]: false,
|
||||
[iTutorialSteps.ActiveScriptsToTerminal]: false,
|
||||
[iTutorialSteps.TerminalTailScript]: false,
|
||||
[iTutorialSteps.GoToHacknetNodesPage]: false,
|
||||
[iTutorialSteps.HacknetNodesIntroduction]: false,
|
||||
[iTutorialSteps.HacknetNodesGoToWorldPage]: false,
|
||||
[iTutorialSteps.WorldDescription]: false,
|
||||
[iTutorialSteps.TutorialPageInfo]: false,
|
||||
[iTutorialSteps.End]: false,
|
||||
},
|
||||
};
|
||||
|
||||
function iTutorialStart(): void {
|
||||
ITutorial.isRunning = true;
|
||||
}
|
||||
|
||||
// Go to the next step and evaluate it
|
||||
function iTutorialNextStep(): void {
|
||||
ITutorial.stepIsDone[ITutorial.currStep] = true;
|
||||
if (ITutorial.currStep < iTutorialSteps.End) {
|
||||
ITutorial.currStep += 1;
|
||||
}
|
||||
if (ITutorial.currStep === iTutorialSteps.End) iTutorialEnd();
|
||||
ITutorialEvents.emit();
|
||||
}
|
||||
|
||||
// Go to previous step and evaluate
|
||||
function iTutorialPrevStep(): void {
|
||||
if (ITutorial.currStep > iTutorialSteps.Start) {
|
||||
ITutorial.currStep -= 1;
|
||||
}
|
||||
ITutorialEvents.emit();
|
||||
}
|
||||
|
||||
function iTutorialEnd(): void {
|
||||
ITutorial.isRunning = false;
|
||||
|
||||
// Create a popup with final introductory stuff
|
||||
const popupId = "interactive-tutorial-ending-popup";
|
||||
const txt = createElement("p", {
|
||||
innerHTML:
|
||||
"If you are new to the game, the following links may be useful for you!<br><br>" +
|
||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html' target='_blank'>Getting Started Guide</a>" +
|
||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/' target='_blank'>Documentation</a><br><br>" +
|
||||
"The Beginner's Guide to Hacking was added to your home computer! It contains some tips/pointers for starting out with the game. " +
|
||||
"To read it, go to Terminal and enter<br><br>cat " +
|
||||
LiteratureNames.HackersStartingHandbook,
|
||||
});
|
||||
const gotitBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
float: "right",
|
||||
padding: "6px",
|
||||
innerText: "Got it!",
|
||||
clickListener: () => {
|
||||
removeElementById(popupId);
|
||||
},
|
||||
});
|
||||
createPopup(popupId, [txt, gotitBtn]);
|
||||
|
||||
Player.getHomeComputer().messages.push(LiteratureNames.HackersStartingHandbook);
|
||||
ITutorialEvents.emit();
|
||||
}
|
||||
|
||||
export { iTutorialSteps, iTutorialEnd, iTutorialStart, iTutorialNextStep, ITutorial, iTutorialPrevStep };
|
@ -6,114 +6,135 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { City } from "../City";
|
||||
import { Cities } from "../Cities";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
import { Locations } from "../Locations";
|
||||
import { Location } from "../Location";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
type IProps = {
|
||||
city: City;
|
||||
enterLocation: (to: LocationName) => void;
|
||||
};
|
||||
|
||||
export class LocationCity extends React.Component<IProps, any> {
|
||||
asciiCity(): React.ReactNode {
|
||||
const LocationLetter = (location: LocationName): JSX.Element => {
|
||||
if (location)
|
||||
return (
|
||||
<span
|
||||
key={location}
|
||||
className="tooltip"
|
||||
style={{
|
||||
color: "white",
|
||||
whiteSpace: "nowrap",
|
||||
margin: "0px",
|
||||
padding: "0px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={this.props.enterLocation.bind(this, location)}
|
||||
>
|
||||
<b>X</b>
|
||||
</span>
|
||||
);
|
||||
return <span>*</span>;
|
||||
};
|
||||
|
||||
const locationLettersRegex = /[A-Z]/g;
|
||||
const letterMap: any = {
|
||||
A: 0,
|
||||
B: 1,
|
||||
C: 2,
|
||||
D: 3,
|
||||
E: 4,
|
||||
F: 5,
|
||||
G: 6,
|
||||
H: 7,
|
||||
I: 8,
|
||||
J: 9,
|
||||
K: 10,
|
||||
L: 11,
|
||||
M: 12,
|
||||
N: 13,
|
||||
O: 14,
|
||||
P: 15,
|
||||
Q: 16,
|
||||
R: 17,
|
||||
S: 18,
|
||||
T: 19,
|
||||
U: 20,
|
||||
V: 21,
|
||||
W: 22,
|
||||
X: 23,
|
||||
Y: 24,
|
||||
Z: 25,
|
||||
};
|
||||
|
||||
const lineElems = (s: string): JSX.Element[] => {
|
||||
const elems: any[] = [];
|
||||
const matches: any[] = [];
|
||||
let match: any;
|
||||
while ((match = locationLettersRegex.exec(s)) !== null) {
|
||||
matches.push(match);
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
elems.push(s);
|
||||
return elems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const startI = i === 0 ? 0 : matches[i - 1].index + 1;
|
||||
const endI = matches[i].index;
|
||||
elems.push(s.slice(startI, endI));
|
||||
const locationI = letterMap[s[matches[i].index]];
|
||||
elems.push(LocationLetter(this.props.city.locations[locationI]));
|
||||
}
|
||||
elems.push(s.slice(matches[matches.length - 1].index + 1));
|
||||
return elems;
|
||||
};
|
||||
|
||||
const elems: JSX.Element[] = [];
|
||||
const lines = this.props.city.asciiArt.split("\n");
|
||||
for (const i in lines) {
|
||||
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>);
|
||||
}
|
||||
|
||||
return <div className="noselect">{elems}</div>;
|
||||
}
|
||||
|
||||
listCity(): React.ReactNode {
|
||||
const locationButtons = this.props.city.locations.map((locName) => {
|
||||
return (
|
||||
<li key={locName}>
|
||||
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} />
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return <ul>{locationButtons}</ul>;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <>{Settings.DisableASCIIArt ? this.listCity() : this.asciiCity()}</>;
|
||||
function toLocation(router: IRouter, location: Location): void {
|
||||
if (location.name === LocationName.TravelAgency) {
|
||||
router.toTravel();
|
||||
} else if (location.name === LocationName.WorldStockExchange) {
|
||||
router.toStockMarket();
|
||||
} else {
|
||||
router.toLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
function LocationLetter(location: Location): React.ReactElement {
|
||||
const router = use.Router();
|
||||
if (!location) return <span>*</span>;
|
||||
return (
|
||||
<span
|
||||
aria-label={location.name}
|
||||
key={location.name}
|
||||
className="tooltip"
|
||||
style={{
|
||||
color: "white",
|
||||
whiteSpace: "nowrap",
|
||||
margin: "0px",
|
||||
padding: "0px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => toLocation(router, location)}
|
||||
>
|
||||
<b>X</b>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function ASCIICity(props: IProps): React.ReactElement {
|
||||
const locationLettersRegex = /[A-Z]/g;
|
||||
const letterMap: any = {
|
||||
A: 0,
|
||||
B: 1,
|
||||
C: 2,
|
||||
D: 3,
|
||||
E: 4,
|
||||
F: 5,
|
||||
G: 6,
|
||||
H: 7,
|
||||
I: 8,
|
||||
J: 9,
|
||||
K: 10,
|
||||
L: 11,
|
||||
M: 12,
|
||||
N: 13,
|
||||
O: 14,
|
||||
P: 15,
|
||||
Q: 16,
|
||||
R: 17,
|
||||
S: 18,
|
||||
T: 19,
|
||||
U: 20,
|
||||
V: 21,
|
||||
W: 22,
|
||||
X: 23,
|
||||
Y: 24,
|
||||
Z: 25,
|
||||
};
|
||||
|
||||
const lineElems = (s: string): JSX.Element[] => {
|
||||
const elems: any[] = [];
|
||||
const matches: any[] = [];
|
||||
let match: any;
|
||||
while ((match = locationLettersRegex.exec(s)) !== null) {
|
||||
matches.push(match);
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
elems.push(s);
|
||||
return elems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const startI = i === 0 ? 0 : matches[i - 1].index + 1;
|
||||
const endI = matches[i].index;
|
||||
elems.push(s.slice(startI, endI));
|
||||
const locationI = letterMap[s[matches[i].index]];
|
||||
elems.push(LocationLetter(Locations[props.city.locations[locationI]]));
|
||||
}
|
||||
elems.push(s.slice(matches[matches.length - 1].index + 1));
|
||||
return elems;
|
||||
};
|
||||
|
||||
const elems: JSX.Element[] = [];
|
||||
const lines = props.city.asciiArt.split("\n");
|
||||
for (const i in lines) {
|
||||
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>);
|
||||
}
|
||||
|
||||
return <div className="noselect">{elems}</div>;
|
||||
}
|
||||
|
||||
function ListCity(props: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const locationButtons = props.city.locations.map((locName) => {
|
||||
return (
|
||||
<li key={locName}>
|
||||
<StdButton onClick={() => toLocation(router, Locations[locName])} text={locName} />
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return <ul>{locationButtons}</ul>;
|
||||
}
|
||||
|
||||
export function LocationCity(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const city = Cities[player.city];
|
||||
return (
|
||||
<div className="noselect">
|
||||
<h2>{city.name}</h2>
|
||||
{Settings.DisableASCIIArt ? <ListCity city={city} /> : <ASCIICity city={city} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -3,418 +3,347 @@
|
||||
*
|
||||
* This subcomponent renders all of the buttons for applying to jobs at a company
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { ApplyToJobButton } from "./ApplyToJobButton";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { Locations } from "../Locations";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
import { Companies } from "../../Company/Companies";
|
||||
import { Company } from "../../Company/Company";
|
||||
import { CompanyPosition } from "../../Company/CompanyPosition";
|
||||
import { CompanyPositions } from "../../Company/CompanyPositions";
|
||||
import * as posNames from "../../Company/data/companypositionnames";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { use } from "../../ui/Context";
|
||||
import { QuitJobPopup } from "../../Company/ui/QuitJobPopup";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
locName: LocationName;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
employedHere: boolean;
|
||||
};
|
||||
|
||||
const blockStyleMarkup = {
|
||||
display: "block",
|
||||
};
|
||||
|
||||
export class CompanyLocation extends React.Component<IProps, IState> {
|
||||
export function CompanyLocation(props: IProps): React.ReactElement {
|
||||
const p = use.Player();
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
/**
|
||||
* We'll keep a reference to the Company that this component is being rendered for,
|
||||
* so we don't have to look it up every time
|
||||
*/
|
||||
company: Company;
|
||||
const company = Companies[props.locName];
|
||||
if (company == null) throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
|
||||
|
||||
/**
|
||||
* Reference to the Location that this component is being rendered for
|
||||
*/
|
||||
const location = Locations[props.locName];
|
||||
if (location == null) {
|
||||
throw new Error(`CompanyLocation component constructed with invalid location: ${props.locName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of company position that player holds, if applicable
|
||||
*/
|
||||
const jobTitle = p.jobs[props.locName] ? p.jobs[props.locName] : null;
|
||||
|
||||
/**
|
||||
* CompanyPosition object for the job that the player holds at this company
|
||||
* (if he has one)
|
||||
*/
|
||||
companyPosition: CompanyPosition | null = null;
|
||||
const companyPosition = jobTitle ? CompanyPositions[jobTitle] : null;
|
||||
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
p.location = props.locName;
|
||||
|
||||
/**
|
||||
* Reference to the Location that this component is being rendered for
|
||||
*/
|
||||
location: Location;
|
||||
|
||||
/**
|
||||
* Name of company position that player holds, if applicable
|
||||
*/
|
||||
jobTitle: string | null = null;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
|
||||
this.quit = this.quit.bind(this);
|
||||
this.applyForAgentJob = this.applyForAgentJob.bind(this);
|
||||
this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this);
|
||||
this.applyForBusinessJob = this.applyForBusinessJob.bind(this);
|
||||
this.applyForEmployeeJob = this.applyForEmployeeJob.bind(this);
|
||||
this.applyForItJob = this.applyForItJob.bind(this);
|
||||
this.applyForPartTimeEmployeeJob = this.applyForPartTimeEmployeeJob.bind(this);
|
||||
this.applyForPartTimeWaiterJob = this.applyForPartTimeWaiterJob.bind(this);
|
||||
this.applyForSecurityJob = this.applyForSecurityJob.bind(this);
|
||||
this.applyForSoftwareConsultantJob = this.applyForSoftwareConsultantJob.bind(this);
|
||||
this.applyForSoftwareJob = this.applyForSoftwareJob.bind(this);
|
||||
this.applyForWaiterJob = this.applyForWaiterJob.bind(this);
|
||||
this.startInfiltration = this.startInfiltration.bind(this);
|
||||
this.work = this.work.bind(this);
|
||||
|
||||
this.location = Locations[props.locName];
|
||||
if (this.location == null) {
|
||||
throw new Error(`CompanyLocation component constructed with invalid location: ${props.locName}`);
|
||||
}
|
||||
|
||||
this.company = Companies[props.locName];
|
||||
if (this.company == null) {
|
||||
throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
employedHere: false,
|
||||
};
|
||||
|
||||
this.props.p.location = props.locName;
|
||||
|
||||
this.checkIfEmployedHere(false);
|
||||
}
|
||||
|
||||
applyForAgentJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForAgentJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForAgentJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForAgentJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForBusinessConsultantJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForBusinessConsultantJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForBusinessJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForBusinessJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForBusinessJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForBusinessJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForEmployeeJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForEmployeeJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForItJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForItJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForItJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForItJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForPartTimeEmployeeJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForPartTimeEmployeeJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForPartTimeWaiterJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForPartTimeWaiterJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSecurityJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSecurityJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSecurityJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSecurityJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSoftwareConsultantJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSoftwareConsultantJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSoftwareJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSoftwareJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSoftwareJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSoftwareJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForWaiterJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForWaiterJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
checkIfEmployedHere(updateState = false): void {
|
||||
this.jobTitle = this.props.p.jobs[this.props.locName];
|
||||
if (this.jobTitle != null) {
|
||||
this.companyPosition = CompanyPositions[this.jobTitle];
|
||||
}
|
||||
|
||||
if (updateState) {
|
||||
this.setState({
|
||||
employedHere: this.jobTitle != null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
startInfiltration(e: React.MouseEvent<HTMLElement>): void {
|
||||
function startInfiltration(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
const loc = this.location;
|
||||
if (!loc.infiltrationData) {
|
||||
console.error(`trying to start infiltration at ${this.props.locName} but the infiltrationData is null`);
|
||||
return;
|
||||
}
|
||||
const loc = location;
|
||||
if (!loc.infiltrationData)
|
||||
throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`);
|
||||
|
||||
this.props.engine.loadInfiltrationContent(
|
||||
this.props.locName,
|
||||
loc.infiltrationData.startingSecurityLevel,
|
||||
loc.infiltrationData.maxClearanceLevel,
|
||||
);
|
||||
|
||||
const data = loc.infiltrationData;
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
router.toInfiltration(loc);
|
||||
}
|
||||
|
||||
work(e: React.MouseEvent<HTMLElement>): void {
|
||||
function work(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pos = this.companyPosition;
|
||||
const pos = companyPosition;
|
||||
if (pos instanceof CompanyPosition) {
|
||||
if (pos.isPartTimeJob() || pos.isSoftwareConsultantJob() || pos.isBusinessConsultantJob()) {
|
||||
this.props.p.startWorkPartTime(this.props.locName);
|
||||
p.startWorkPartTime(router, props.locName);
|
||||
} else {
|
||||
this.props.p.startWork(this.props.locName);
|
||||
p.startWork(router, props.locName);
|
||||
}
|
||||
router.toWork();
|
||||
}
|
||||
}
|
||||
|
||||
quit(e: React.MouseEvent<HTMLElement>): void {
|
||||
function quit(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) return;
|
||||
const popupId = `quit-job-popup`;
|
||||
createPopup(popupId, QuitJobPopup, {
|
||||
locName: this.props.locName,
|
||||
company: this.company,
|
||||
player: this.props.p,
|
||||
onQuit: () => this.checkIfEmployedHere(true),
|
||||
locName: props.locName,
|
||||
company: company,
|
||||
player: p,
|
||||
onQuit: rerender,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const isEmployedHere = this.jobTitle != null;
|
||||
const favorGain = this.company.getFavorGain();
|
||||
const isEmployedHere = jobTitle != null;
|
||||
const favorGain = company.getFavorGain();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isEmployedHere && (
|
||||
<div>
|
||||
<p>Job Title: {this.jobTitle}</p>
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company reputation: {Reputation(this.company.playerReputation)}
|
||||
<span className={"tooltiptext"}>
|
||||
You will earn {Favor(favorGain[0])} company favor upon resetting after installing Augmentations
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company Favor: {Favor(this.company.favor)}
|
||||
<span className={"tooltiptext"}>
|
||||
Company favor increases the rate at which you earn reputation for this company by 1% per favor. Company
|
||||
favor is gained whenever you reset after installing Augmentations. The amount of favor you gain depends
|
||||
on how much reputation you have with the comapny.
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<StdButton onClick={this.work} text={"Work"} />
|
||||
|
||||
<StdButton onClick={this.quit} text={"Quit"} />
|
||||
</div>
|
||||
)}
|
||||
{this.company.hasAgentPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]}
|
||||
onClick={this.applyForAgentJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Agent Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasBusinessConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]}
|
||||
onClick={this.applyForBusinessConsultantJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Business Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasBusinessPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]}
|
||||
onClick={this.applyForBusinessJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Business Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]}
|
||||
onClick={this.applyForEmployeeJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be an Employee"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]}
|
||||
onClick={this.applyForPartTimeEmployeeJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a part-time Employee"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasITPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]}
|
||||
onClick={this.applyForItJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for IT Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSecurityPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]}
|
||||
onClick={this.applyForSecurityJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Security Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSoftwareConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]}
|
||||
onClick={this.applyForSoftwareConsultantJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Software Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSoftwarePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]}
|
||||
onClick={this.applyForSoftwareJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Software Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]}
|
||||
onClick={this.applyForWaiterJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a Waiter"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]}
|
||||
onClick={this.applyForPartTimeWaiterJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a part-time Waiter"}
|
||||
/>
|
||||
)}
|
||||
{this.location.infiltrationData != null && (
|
||||
<StdButton onClick={this.startInfiltration} style={this.btnStyle} text={"Infiltrate Company"} />
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{isEmployedHere && (
|
||||
<div>
|
||||
<p>Job Title: {jobTitle}</p>
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company reputation: {Reputation(company.playerReputation)}
|
||||
<span className={"tooltiptext"}>
|
||||
You will earn {Favor(favorGain[0])} company favor upon resetting after installing Augmentations
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company Favor: {Favor(company.favor)}
|
||||
<span className={"tooltiptext"}>
|
||||
Company favor increases the rate at which you earn reputation for this company by 1% per favor. Company
|
||||
favor is gained whenever you reset after installing Augmentations. The amount of favor you gain depends on
|
||||
how much reputation you have with the comapny.
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<StdButton onClick={work} text={"Work"} />
|
||||
|
||||
<StdButton onClick={quit} text={"Quit"} />
|
||||
</div>
|
||||
)}
|
||||
{company.hasAgentPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]}
|
||||
onClick={applyForAgentJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Agent Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasBusinessConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]}
|
||||
onClick={applyForBusinessConsultantJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Business Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasBusinessPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]}
|
||||
onClick={applyForBusinessJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Business Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]}
|
||||
onClick={applyForEmployeeJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be an Employee"}
|
||||
/>
|
||||
)}
|
||||
{company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]}
|
||||
onClick={applyForPartTimeEmployeeJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a part-time Employee"}
|
||||
/>
|
||||
)}
|
||||
{company.hasITPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]}
|
||||
onClick={applyForItJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for IT Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSecurityPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]}
|
||||
onClick={applyForSecurityJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Security Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSoftwareConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]}
|
||||
onClick={applyForSoftwareConsultantJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Software Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSoftwarePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]}
|
||||
onClick={applyForSoftwareJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Software Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]}
|
||||
onClick={applyForWaiterJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a Waiter"}
|
||||
/>
|
||||
)}
|
||||
{company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]}
|
||||
onClick={applyForPartTimeWaiterJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a part-time Waiter"}
|
||||
/>
|
||||
)}
|
||||
{location.infiltrationData != null && (
|
||||
<StdButton onClick={startInfiltration} style={{ display: "block" }} text={"Infiltrate Company"} />
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -12,16 +12,13 @@ import { HospitalLocation } from "./HospitalLocation";
|
||||
import { SlumsLocation } from "./SlumsLocation";
|
||||
import { SpecialLocation } from "./SpecialLocation";
|
||||
import { TechVendorLocation } from "./TechVendorLocation";
|
||||
import { TravelAgencyLocation } from "./TravelAgencyLocation";
|
||||
import { TravelAgencyRoot } from "./TravelAgencyRoot";
|
||||
import { UniversityLocation } from "./UniversityLocation";
|
||||
import { CasinoLocation } from "./CasinoLocation";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { LocationType } from "../LocationTypeEnum";
|
||||
import { CityName } from "../data/CityNames";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
@ -29,100 +26,73 @@ import { getServer, isBackdoorInstalled } from "../../Server/ServerHelpers";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
returnToCity: () => void;
|
||||
travel: (to: CityName) => void;
|
||||
};
|
||||
|
||||
export class GenericLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
}
|
||||
|
||||
export function GenericLocation({ loc }: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const player = use.Player();
|
||||
/**
|
||||
* Determine what needs to be rendered for this location based on the locations
|
||||
* type. Returns an array of React components that should be rendered
|
||||
*/
|
||||
getLocationSpecificContent(): React.ReactNode[] {
|
||||
function getLocationSpecificContent(): React.ReactNode[] {
|
||||
const content: React.ReactNode[] = [];
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Company)) {
|
||||
content.push(
|
||||
<CompanyLocation
|
||||
engine={this.props.engine}
|
||||
key={"companylocation"}
|
||||
locName={this.props.loc.name}
|
||||
p={this.props.p}
|
||||
/>,
|
||||
);
|
||||
if (loc.types.includes(LocationType.Company)) {
|
||||
content.push(<CompanyLocation key={"companylocation"} locName={loc.name} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key={"gymlocation"} loc={this.props.loc} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key={"gymlocation"} router={router} loc={loc} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key={"hospitallocation"} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key={"hospitallocation"} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Slums)) {
|
||||
content.push(<SlumsLocation key={"slumslocation"} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Slums)) {
|
||||
content.push(<SlumsLocation key={"slumslocation"} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Special)) {
|
||||
content.push(
|
||||
<SpecialLocation engine={this.props.engine} key={"speciallocation"} loc={this.props.loc} p={this.props.p} />,
|
||||
);
|
||||
if (loc.types.includes(LocationType.Special)) {
|
||||
content.push(<SpecialLocation key={"speciallocation"} loc={loc} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key={"techvendorlocation"} loc={this.props.loc} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key={"techvendorlocation"} loc={loc} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyLocation key={"travelagencylocation"} p={this.props.p} travel={this.props.travel} />);
|
||||
if (loc.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyRoot key={"travelagencylocation"} p={player} router={router} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key={"universitylocation"} loc={this.props.loc} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key={"universitylocation"} loc={loc} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key={"casinoLocation"} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key={"casinoLocation"} p={player} />);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
|
||||
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||
const server = getServer(ip);
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
const locContent: React.ReactNode[] = getLocationSpecificContent();
|
||||
const ip = SpecialServerIps.getIp(loc.name);
|
||||
const server = getServer(ip);
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
|
||||
<h1 className="noselect">
|
||||
{backdoorInstalled && !Settings.DisableTextEffects ? (
|
||||
<CorruptableText content={this.props.loc.name} />
|
||||
) : (
|
||||
this.props.loc.name
|
||||
)}
|
||||
</h1>
|
||||
{locContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={() => router.toCity()} style={{ display: "block" }} text={"Return to World"} />
|
||||
<h1 className="noselect">
|
||||
{backdoorInstalled && !Settings.DisableTextEffects ? <CorruptableText content={loc.name} /> : loc.name}
|
||||
</h1>
|
||||
{locContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -15,10 +15,12 @@ import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
type IProps = {
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
router: IRouter;
|
||||
};
|
||||
|
||||
export class GymLocation extends React.Component<IProps, any> {
|
||||
@ -50,7 +52,7 @@ export class GymLocation extends React.Component<IProps, any> {
|
||||
|
||||
train(stat: string): void {
|
||||
const loc = this.props.loc;
|
||||
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||
this.props.p.startClass(this.props.router, this.calculateCost(), loc.expMult, stat);
|
||||
}
|
||||
|
||||
trainStrength(): void {
|
||||
|
@ -1,152 +0,0 @@
|
||||
/**
|
||||
* Root React Component for displaying overall Location UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { LocationCity } from "./City";
|
||||
import { GenericLocation } from "./GenericLocation";
|
||||
|
||||
import { Cities } from "../Cities";
|
||||
import { Locations } from "../Locations";
|
||||
import { LocationType } from "../LocationTypeEnum";
|
||||
|
||||
import { CityName } from "../data/CityNames";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
initiallyInCity?: boolean;
|
||||
engine: IEngine;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
city: CityName;
|
||||
inCity: boolean;
|
||||
location: LocationName;
|
||||
};
|
||||
|
||||
export class LocationRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
city: props.p.city,
|
||||
inCity: props.initiallyInCity == null ? true : props.initiallyInCity,
|
||||
location: props.p.location,
|
||||
};
|
||||
|
||||
this.enterLocation = this.enterLocation.bind(this);
|
||||
this.returnToCity = this.returnToCity.bind(this);
|
||||
this.travel = this.travel.bind(this);
|
||||
}
|
||||
|
||||
enterLocation(to: LocationName): void {
|
||||
this.props.p.gotoLocation(to);
|
||||
this.setState({
|
||||
inCity: false,
|
||||
location: to,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Click listener for a button that lets the player go from a specific location
|
||||
* back to the city
|
||||
*/
|
||||
returnToCity(): void {
|
||||
this.setState({
|
||||
inCity: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI for a city
|
||||
*/
|
||||
renderCity(): React.ReactNode {
|
||||
const city = Cities[this.state.city];
|
||||
if (city == null) {
|
||||
throw new Error(`Invalid city when rendering UI: ${this.state.city}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="noselect">
|
||||
<h2>{this.state.city}</h2>
|
||||
<LocationCity city={city} enterLocation={this.enterLocation} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI for a specific location
|
||||
*/
|
||||
renderLocation(): React.ReactNode {
|
||||
const loc = Locations[this.state.location];
|
||||
|
||||
if (loc == null) {
|
||||
throw new Error(`Invalid location when rendering UI: ${this.state.location}`);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.StockMarket)) {
|
||||
this.props.engine.loadStockMarketContent();
|
||||
}
|
||||
|
||||
return (
|
||||
<GenericLocation
|
||||
engine={this.props.engine}
|
||||
loc={loc}
|
||||
p={this.props.p}
|
||||
returnToCity={this.returnToCity}
|
||||
travel={this.travel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Travel to a different city
|
||||
* @param {CityName} to - Destination city
|
||||
*/
|
||||
travel(to: CityName): void {
|
||||
const p = this.props.p;
|
||||
const cost = CONSTANTS.TravelCost;
|
||||
if (!p.canAfford(cost)) {
|
||||
dialogBoxCreate(`You cannot afford to travel to ${to}`);
|
||||
return;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
p.travel(to);
|
||||
dialogBoxCreate(<span className="noselect">You are now in {to}!</span>);
|
||||
|
||||
// Dynamically update main menu
|
||||
if (p.firstTimeTraveled === false) {
|
||||
p.firstTimeTraveled = true;
|
||||
const travelTab = document.getElementById("travel-tab");
|
||||
const worldHeader = document.getElementById("world-menu-header");
|
||||
if (travelTab != null && worldHeader !== null) {
|
||||
travelTab.style.display = "list-item";
|
||||
worldHeader.click();
|
||||
worldHeader.click();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.p.travel(to)) {
|
||||
this.setState({
|
||||
inCity: true,
|
||||
city: to,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.state.inCity) {
|
||||
return this.renderCity();
|
||||
} else {
|
||||
return this.renderLocation();
|
||||
}
|
||||
}
|
||||
}
|
@ -6,225 +6,209 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
export class SlumsLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
|
||||
this.shoplift = this.shoplift.bind(this);
|
||||
this.robStore = this.robStore.bind(this);
|
||||
this.mug = this.mug.bind(this);
|
||||
this.larceny = this.larceny.bind(this);
|
||||
this.dealDrugs = this.dealDrugs.bind(this);
|
||||
this.bondForgery = this.bondForgery.bind(this);
|
||||
this.traffickArms = this.traffickArms.bind(this);
|
||||
this.homicide = this.homicide.bind(this);
|
||||
this.grandTheftAuto = this.grandTheftAuto.bind(this);
|
||||
this.kidnap = this.kidnap.bind(this);
|
||||
this.assassinate = this.assassinate.bind(this);
|
||||
this.heist = this.heist.bind(this);
|
||||
}
|
||||
|
||||
shoplift(e: React.MouseEvent<HTMLElement>): void {
|
||||
export function SlumsLocation(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
function shoplift(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Shoplift.commit(this.props.p);
|
||||
Crimes.Shoplift.commit(router, player);
|
||||
}
|
||||
|
||||
robStore(e: React.MouseEvent<HTMLElement>): void {
|
||||
function robStore(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.RobStore.commit(this.props.p);
|
||||
Crimes.RobStore.commit(router, player);
|
||||
}
|
||||
|
||||
mug(e: React.MouseEvent<HTMLElement>): void {
|
||||
function mug(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Mug.commit(this.props.p);
|
||||
Crimes.Mug.commit(router, player);
|
||||
}
|
||||
|
||||
larceny(e: React.MouseEvent<HTMLElement>): void {
|
||||
function larceny(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Larceny.commit(this.props.p);
|
||||
Crimes.Larceny.commit(router, player);
|
||||
}
|
||||
|
||||
dealDrugs(e: React.MouseEvent<HTMLElement>): void {
|
||||
function dealDrugs(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.DealDrugs.commit(this.props.p);
|
||||
Crimes.DealDrugs.commit(router, player);
|
||||
}
|
||||
|
||||
bondForgery(e: React.MouseEvent<HTMLElement>): void {
|
||||
function bondForgery(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.BondForgery.commit(this.props.p);
|
||||
Crimes.BondForgery.commit(router, player);
|
||||
}
|
||||
|
||||
traffickArms(e: React.MouseEvent<HTMLElement>): void {
|
||||
function traffickArms(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.TraffickArms.commit(this.props.p);
|
||||
Crimes.TraffickArms.commit(router, player);
|
||||
}
|
||||
|
||||
homicide(e: React.MouseEvent<HTMLElement>): void {
|
||||
function homicide(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Homicide.commit(this.props.p);
|
||||
Crimes.Homicide.commit(router, player);
|
||||
}
|
||||
|
||||
grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
|
||||
function grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.GrandTheftAuto.commit(this.props.p);
|
||||
Crimes.GrandTheftAuto.commit(router, player);
|
||||
}
|
||||
|
||||
kidnap(e: React.MouseEvent<HTMLElement>): void {
|
||||
function kidnap(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Kidnap.commit(this.props.p);
|
||||
Crimes.Kidnap.commit(router, player);
|
||||
}
|
||||
|
||||
assassinate(e: React.MouseEvent<HTMLElement>): void {
|
||||
function assassinate(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Assassination.commit(this.props.p);
|
||||
Crimes.Assassination.commit(router, player);
|
||||
}
|
||||
|
||||
heist(e: React.MouseEvent<HTMLElement>): void {
|
||||
function heist(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Heist.commit(this.props.p);
|
||||
Crimes.Heist.commit(router, player);
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const shopliftChance = Crimes.Shoplift.successRate(this.props.p);
|
||||
const robStoreChance = Crimes.RobStore.successRate(this.props.p);
|
||||
const mugChance = Crimes.Mug.successRate(this.props.p);
|
||||
const larcenyChance = Crimes.Larceny.successRate(this.props.p);
|
||||
const drugsChance = Crimes.DealDrugs.successRate(this.props.p);
|
||||
const bondChance = Crimes.BondForgery.successRate(this.props.p);
|
||||
const armsChance = Crimes.TraffickArms.successRate(this.props.p);
|
||||
const homicideChance = Crimes.Homicide.successRate(this.props.p);
|
||||
const gtaChance = Crimes.GrandTheftAuto.successRate(this.props.p);
|
||||
const kidnapChance = Crimes.Kidnap.successRate(this.props.p);
|
||||
const assassinateChance = Crimes.Assassination.successRate(this.props.p);
|
||||
const heistChance = Crimes.Heist.successRate(this.props.p);
|
||||
const shopliftChance = Crimes.Shoplift.successRate(player);
|
||||
const robStoreChance = Crimes.RobStore.successRate(player);
|
||||
const mugChance = Crimes.Mug.successRate(player);
|
||||
const larcenyChance = Crimes.Larceny.successRate(player);
|
||||
const drugsChance = Crimes.DealDrugs.successRate(player);
|
||||
const bondChance = Crimes.BondForgery.successRate(player);
|
||||
const armsChance = Crimes.TraffickArms.successRate(player);
|
||||
const homicideChance = Crimes.Homicide.successRate(player);
|
||||
const gtaChance = Crimes.GrandTheftAuto.successRate(player);
|
||||
const kidnapChance = Crimes.Kidnap.successRate(player);
|
||||
const assassinateChance = Crimes.Assassination.successRate(player);
|
||||
const heistChance = Crimes.Heist.successRate(player);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.shoplift}
|
||||
style={this.btnStyle}
|
||||
text={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
|
||||
tooltip={"Attempt to shoplift from a low-end retailer"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.robStore}
|
||||
style={this.btnStyle}
|
||||
text={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit armed robbery on a high-end store"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.mug}
|
||||
style={this.btnStyle}
|
||||
text={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
|
||||
tooltip={"Attempt to mug a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.larceny}
|
||||
style={this.btnStyle}
|
||||
text={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
|
||||
tooltip={"Attempt to rob property from someone's house"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.dealDrugs}
|
||||
style={this.btnStyle}
|
||||
text={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
|
||||
tooltip={"Attempt to deal drugs"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.bondForgery}
|
||||
style={this.btnStyle}
|
||||
text={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
|
||||
tooltip={"Attempt to forge corporate bonds"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.traffickArms}
|
||||
style={this.btnStyle}
|
||||
text={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
|
||||
tooltip={"Attempt to smuggle illegal arms into the city"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.homicide}
|
||||
style={this.btnStyle}
|
||||
text={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
|
||||
tooltip={"Attempt to murder a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.grandTheftAuto}
|
||||
style={this.btnStyle}
|
||||
text={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit grand theft auto"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.kidnap}
|
||||
style={this.btnStyle}
|
||||
text={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
|
||||
tooltip={"Attempt to kidnap and ransom a high-profile-target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.assassinate}
|
||||
style={this.btnStyle}
|
||||
text={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
|
||||
tooltip={"Attempt to assassinate a high-profile target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={this.heist}
|
||||
style={this.btnStyle}
|
||||
text={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
|
||||
tooltip={"Attempt to pull off the ultimate heist"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<AutoupdatingStdButton
|
||||
label={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={shoplift}
|
||||
style={{ display: "block" }}
|
||||
text={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
|
||||
tooltip={"Attempt to shoplift from a low-end retailer"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={robStore}
|
||||
style={{ display: "block" }}
|
||||
text={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit armed robbery on a high-end store"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={mug}
|
||||
style={{ display: "block" }}
|
||||
text={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
|
||||
tooltip={"Attempt to mug a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={larceny}
|
||||
style={{ display: "block" }}
|
||||
text={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
|
||||
tooltip={"Attempt to rob property from someone's house"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={dealDrugs}
|
||||
style={{ display: "block" }}
|
||||
text={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
|
||||
tooltip={"Attempt to deal drugs"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={bondForgery}
|
||||
style={{ display: "block" }}
|
||||
text={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
|
||||
tooltip={"Attempt to forge corporate bonds"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={traffickArms}
|
||||
style={{ display: "block" }}
|
||||
text={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
|
||||
tooltip={"Attempt to smuggle illegal arms into the city"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={homicide}
|
||||
style={{ display: "block" }}
|
||||
text={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
|
||||
tooltip={"Attempt to murder a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={grandTheftAuto}
|
||||
style={{ display: "block" }}
|
||||
text={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit grand theft auto"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={kidnap}
|
||||
style={{ display: "block" }}
|
||||
text={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
|
||||
tooltip={"Attempt to kidnap and ransom a high-profile-target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={assassinate}
|
||||
style={{ display: "block" }}
|
||||
text={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
|
||||
tooltip={"Attempt to assassinate a high-profile target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
label={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
|
||||
intervalTime={5e3}
|
||||
onClick={heist}
|
||||
style={{ display: "block" }}
|
||||
text={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
|
||||
tooltip={"Attempt to pull off the ultimate heist"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -10,15 +10,14 @@
|
||||
* This subcomponent creates all of the buttons for interacting with those special
|
||||
* properties
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { CreateCorporationPopup } from "../../Corporation/ui/CreateCorporationPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
@ -26,43 +25,21 @@ import { StdButton } from "../../ui/React/StdButton";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
inBladeburner: boolean;
|
||||
};
|
||||
|
||||
export class SpecialLocation extends React.Component<IProps, IState> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
|
||||
this.renderNoodleBar = this.renderNoodleBar.bind(this);
|
||||
this.createCorporationPopup = this.createCorporationPopup.bind(this);
|
||||
this.handleBladeburner = this.handleBladeburner.bind(this);
|
||||
this.handleResleeving = this.handleResleeving.bind(this);
|
||||
|
||||
this.state = {
|
||||
inBladeburner: this.props.p.inBladeburner(),
|
||||
};
|
||||
}
|
||||
|
||||
export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
const inBladeburner = player.inBladeburner();
|
||||
/**
|
||||
* Click handler for "Create Corporation" button at Sector-12 City Hall
|
||||
*/
|
||||
createCorporationPopup(): void {
|
||||
function createCorporationPopup(): void {
|
||||
const popupId = `create-start-corporation-popup`;
|
||||
createPopup(popupId, CreateCorporationPopup, {
|
||||
player: this.props.p,
|
||||
player: player,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
@ -70,19 +47,17 @@ export class SpecialLocation extends React.Component<IProps, IState> {
|
||||
/**
|
||||
* Click handler for Bladeburner button at Sector-12 NSA
|
||||
*/
|
||||
handleBladeburner(): void {
|
||||
const p = this.props.p;
|
||||
function handleBladeburner(): void {
|
||||
const p = player;
|
||||
if (p.inBladeburner()) {
|
||||
// Enter Bladeburner division
|
||||
this.props.engine.loadBladeburnerContent();
|
||||
router.toBladeburner();
|
||||
} else {
|
||||
// Apply for Bladeburner division
|
||||
if (p.strength >= 100 && p.defense >= 100 && p.dexterity >= 100 && p.agility >= 100) {
|
||||
p.startBladeburner({ new: true });
|
||||
dialogBoxCreate("You have been accepted into the Bladeburner division!");
|
||||
this.setState({
|
||||
inBladeburner: true,
|
||||
});
|
||||
setRerender((old) => !old);
|
||||
|
||||
const worldHeader = document.getElementById("world-menu-header");
|
||||
if (worldHeader instanceof HTMLElement) {
|
||||
@ -98,28 +73,28 @@ export class SpecialLocation extends React.Component<IProps, IState> {
|
||||
/**
|
||||
* Click handler for Resleeving button at New Tokyo VitaLife
|
||||
*/
|
||||
handleResleeving(): void {
|
||||
this.props.engine.loadResleevingContent();
|
||||
function handleResleeving(): void {
|
||||
router.toResleeves();
|
||||
}
|
||||
|
||||
renderBladeburner(): React.ReactNode {
|
||||
if (!this.props.p.canAccessBladeburner()) {
|
||||
return null;
|
||||
function renderBladeburner(): React.ReactElement {
|
||||
if (!player.canAccessBladeburner()) {
|
||||
return <></>;
|
||||
}
|
||||
const text = this.state.inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
|
||||
return <StdButton onClick={this.handleBladeburner} style={this.btnStyle} text={text} />;
|
||||
const text = inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
|
||||
return <StdButton onClick={handleBladeburner} style={{ display: "block" }} text={text} />;
|
||||
}
|
||||
|
||||
renderNoodleBar(): React.ReactNode {
|
||||
function renderNoodleBar(): React.ReactElement {
|
||||
function EatNoodles(): void {
|
||||
dialogBoxCreate(<>You ate some delicious noodles and feel refreshed.</>);
|
||||
}
|
||||
|
||||
return <StdButton onClick={EatNoodles} style={this.btnStyle} text={"Eat noodles"} />;
|
||||
return <StdButton onClick={EatNoodles} style={{ display: "block" }} text={"Eat noodles"} />;
|
||||
}
|
||||
|
||||
renderCreateCorporation(): React.ReactNode {
|
||||
if (!this.props.p.canAccessCorporation()) {
|
||||
function renderCreateCorporation(): React.ReactElement {
|
||||
if (!player.canAccessCorporation()) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
@ -130,38 +105,36 @@ export class SpecialLocation extends React.Component<IProps, IState> {
|
||||
}
|
||||
return (
|
||||
<AutoupdatingStdButton
|
||||
disabled={!this.props.p.canAccessCorporation() || this.props.p.hasCorporation()}
|
||||
onClick={this.createCorporationPopup}
|
||||
style={this.btnStyle}
|
||||
disabled={!player.canAccessCorporation() || player.hasCorporation()}
|
||||
onClick={createCorporationPopup}
|
||||
style={{ display: "block" }}
|
||||
text={"Create a Corporation"}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderResleeving(): React.ReactNode {
|
||||
if (!this.props.p.canAccessResleeving()) {
|
||||
return null;
|
||||
function renderResleeving(): React.ReactElement {
|
||||
if (!player.canAccessResleeving()) {
|
||||
return <></>;
|
||||
}
|
||||
return <StdButton onClick={this.handleResleeving} style={this.btnStyle} text={"Re-Sleeve"} />;
|
||||
return <StdButton onClick={handleResleeving} style={{ display: "block" }} text={"Re-Sleeve"} />;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
switch (this.props.loc.name) {
|
||||
case LocationName.NewTokyoVitaLife: {
|
||||
return this.renderResleeving();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return this.renderCreateCorporation();
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return this.renderBladeburner();
|
||||
}
|
||||
case LocationName.NewTokyoNoodleBar: {
|
||||
return this.renderNoodleBar();
|
||||
}
|
||||
default:
|
||||
console.error(`Location ${this.props.loc.name} doesn't have any special properties`);
|
||||
break;
|
||||
switch (props.loc.name) {
|
||||
case LocationName.NewTokyoVitaLife: {
|
||||
return renderResleeving();
|
||||
}
|
||||
case LocationName.Sector12CityHall: {
|
||||
return renderCreateCorporation();
|
||||
}
|
||||
case LocationName.Sector12NSA: {
|
||||
return renderBladeburner();
|
||||
}
|
||||
case LocationName.NewTokyoNoodleBar: {
|
||||
return renderNoodleBar();
|
||||
}
|
||||
default:
|
||||
console.error(`Location ${props.loc.name} doesn't have any special properties`);
|
||||
return <></>;
|
||||
}
|
||||
}
|
||||
|
@ -10,28 +10,43 @@ import { TravelConfirmationPopup } from "./TravelConfirmationPopup";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { WorldMap } from "../../ui/React/WorldMap";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
travel: (to: CityName) => void;
|
||||
router: IRouter;
|
||||
};
|
||||
|
||||
function createTravelPopup(p: IPlayer, city: string, travel: () => void): void {
|
||||
function travel(p: IPlayer, router: IRouter, to: CityName): void {
|
||||
const cost = CONSTANTS.TravelCost;
|
||||
if (!p.canAfford(cost)) {
|
||||
dialogBoxCreate(`You cannot afford to travel to ${to}`);
|
||||
return;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
p.travel(to);
|
||||
dialogBoxCreate(<span className="noselect">You are now in {to}!</span>);
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
function createTravelPopup(p: IPlayer, router: IRouter, city: CityName): void {
|
||||
if (Settings.SuppressTravelConfirmation) {
|
||||
travel();
|
||||
travel(p, router, city);
|
||||
return;
|
||||
}
|
||||
const popupId = `travel-confirmation`;
|
||||
createPopup(popupId, TravelConfirmationPopup, {
|
||||
player: p,
|
||||
city: city,
|
||||
travel: travel,
|
||||
travel: () => travel(p, router, city),
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
@ -45,7 +60,7 @@ function ASCIIWorldMap(props: IProps): React.ReactElement {
|
||||
</p>
|
||||
<WorldMap
|
||||
currentCity={props.p.city}
|
||||
onTravel={(city: CityName) => createTravelPopup(props.p, city, () => props.travel(city))}
|
||||
onTravel={(city: CityName) => createTravelPopup(props.p, props.router, city)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@ -66,7 +81,7 @@ function ListWorldMap(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<StdButton
|
||||
key={city}
|
||||
onClick={() => createTravelPopup(props.p, city, () => props.travel(match[1]))}
|
||||
onClick={() => createTravelPopup(props.p, props.router, city as CityName)}
|
||||
style={{ display: "block" }}
|
||||
text={`Travel to ${city}`}
|
||||
/>
|
||||
@ -76,10 +91,15 @@ function ListWorldMap(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
export function TravelAgencyLocation(props: IProps): React.ReactElement {
|
||||
if (Settings.DisableASCIIArt) {
|
||||
return <ListWorldMap p={props.p} travel={props.travel} />;
|
||||
} else {
|
||||
return <ASCIIWorldMap p={props.p} travel={props.travel} />;
|
||||
}
|
||||
export function TravelAgencyRoot(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<h1>Travel Agency</h1>
|
||||
{Settings.DisableASCIIArt ? (
|
||||
<ListWorldMap p={props.p} router={props.router} />
|
||||
) : (
|
||||
<ASCIIWorldMap p={props.p} router={props.router} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
@ -8,154 +8,133 @@ import * as React from "react";
|
||||
import { Location } from "../Location";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { getServer } from "../../Server/ServerHelpers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
export class UniversityLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
export function UniversityLocation(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
|
||||
this.take = this.take.bind(this);
|
||||
this.study = this.study.bind(this);
|
||||
this.dataStructures = this.dataStructures.bind(this);
|
||||
this.networks = this.networks.bind(this);
|
||||
this.algorithms = this.algorithms.bind(this);
|
||||
this.management = this.management.bind(this);
|
||||
this.leadership = this.leadership.bind(this);
|
||||
|
||||
this.calculateCost = this.calculateCost.bind(this);
|
||||
}
|
||||
|
||||
calculateCost(): number {
|
||||
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||
function calculateCost(): number {
|
||||
const ip = SpecialServerIps.getIp(props.loc.name);
|
||||
const server = getServer(ip);
|
||||
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return this.props.loc.costMult;
|
||||
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return props.loc.costMult;
|
||||
const discount = (server as Server).backdoorInstalled ? 0.9 : 1;
|
||||
return this.props.loc.costMult * discount;
|
||||
return props.loc.costMult * discount;
|
||||
}
|
||||
|
||||
take(stat: string): void {
|
||||
const loc = this.props.loc;
|
||||
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||
function take(stat: string): void {
|
||||
const loc = props.loc;
|
||||
player.startClass(router, calculateCost(), loc.expMult, stat);
|
||||
}
|
||||
|
||||
study(): void {
|
||||
this.take(CONSTANTS.ClassStudyComputerScience);
|
||||
function study(): void {
|
||||
take(CONSTANTS.ClassStudyComputerScience);
|
||||
}
|
||||
|
||||
dataStructures(): void {
|
||||
this.take(CONSTANTS.ClassDataStructures);
|
||||
function dataStructures(): void {
|
||||
take(CONSTANTS.ClassDataStructures);
|
||||
}
|
||||
|
||||
networks(): void {
|
||||
this.take(CONSTANTS.ClassNetworks);
|
||||
function networks(): void {
|
||||
take(CONSTANTS.ClassNetworks);
|
||||
}
|
||||
|
||||
algorithms(): void {
|
||||
this.take(CONSTANTS.ClassAlgorithms);
|
||||
function algorithms(): void {
|
||||
take(CONSTANTS.ClassAlgorithms);
|
||||
}
|
||||
|
||||
management(): void {
|
||||
this.take(CONSTANTS.ClassManagement);
|
||||
function management(): void {
|
||||
take(CONSTANTS.ClassManagement);
|
||||
}
|
||||
|
||||
leadership(): void {
|
||||
this.take(CONSTANTS.ClassLeadership);
|
||||
function leadership(): void {
|
||||
take(CONSTANTS.ClassLeadership);
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const costMult: number = this.calculateCost();
|
||||
const costMult: number = calculateCost();
|
||||
|
||||
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
||||
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
||||
const algorithmsCost = CONSTANTS.ClassAlgorithmsBaseCost * costMult;
|
||||
const managementCost = CONSTANTS.ClassManagementBaseCost * costMult;
|
||||
const leadershipCost = CONSTANTS.ClassLeadershipBaseCost * costMult;
|
||||
const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult;
|
||||
const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult;
|
||||
const algorithmsCost = CONSTANTS.ClassAlgorithmsBaseCost * costMult;
|
||||
const managementCost = CONSTANTS.ClassManagementBaseCost * costMult;
|
||||
const leadershipCost = CONSTANTS.ClassLeadershipBaseCost * costMult;
|
||||
|
||||
const earnHackingExpTooltip = `Gain hacking experience!`;
|
||||
const earnCharismaExpTooltip = `Gain charisma experience!`;
|
||||
const earnHackingExpTooltip = `Gain hacking experience!`;
|
||||
const earnCharismaExpTooltip = `Gain charisma experience!`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={this.study}
|
||||
style={this.btnStyle}
|
||||
text={`Study Computer Science (free)`}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.dataStructures}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Data Structures course (
|
||||
<Money money={dataStructuresCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.networks}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Networks course (
|
||||
<Money money={networksCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.algorithms}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Algorithms course (
|
||||
<Money money={algorithmsCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.management}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Management course (
|
||||
<Money money={managementCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.leadership}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Leadership course (
|
||||
<Money money={leadershipCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={study}
|
||||
style={{ display: "block" }}
|
||||
text={`Study Computer Science (free)`}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={dataStructures}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Data Structures course (
|
||||
<Money money={dataStructuresCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={networks}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Networks course (
|
||||
<Money money={networksCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={algorithms}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Algorithms course (
|
||||
<Money money={algorithmsCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={management}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Management course (
|
||||
<Money money={managementCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={leadership}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Leadership course (
|
||||
<Money money={leadershipCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
import { Player } from "./Player";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
@ -12,6 +10,7 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { isString } from "../utils/helpers/isString";
|
||||
|
||||
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
|
||||
// For some reason `jsplumb` needs to be imported exactly like this,
|
||||
// lowercase p, and later in the code used as `jsPlumb` uppercase P. wtf.
|
||||
@ -1187,7 +1186,7 @@ HackingMission.prototype.process = function (numCycles = 1) {
|
||||
});
|
||||
|
||||
// Update timer and check if player lost
|
||||
this.time -= storedCycles * Engine._idleSpeed;
|
||||
this.time -= storedCycles * CONSTANTS._idleSpeed;
|
||||
if (this.time <= 0) {
|
||||
this.finishMission(false);
|
||||
return;
|
||||
@ -1595,18 +1594,7 @@ HackingMission.prototype.finishMission = function (win) {
|
||||
} else {
|
||||
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
|
||||
}
|
||||
|
||||
// Clear mission container
|
||||
var container = document.getElementById("mission-container");
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
// Return to Faction page
|
||||
document.getElementById("mainmenu-container").style.visibility = "visible";
|
||||
document.getElementById("character-overview-wrapper").style.visibility = "visible";
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(this.faction.name);
|
||||
Router.toFaction();
|
||||
};
|
||||
|
||||
export { HackingMission, inMission, setInMission, currMission };
|
||||
|
@ -3,4 +3,4 @@
|
||||
*/
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
|
||||
export const WorkerScriptStartStopEventEmitter = new EventEmitter();
|
||||
export const WorkerScriptStartStopEventEmitter = new EventEmitter<[]>();
|
||||
|
@ -116,7 +116,7 @@ function removeWorkerScript(workerScript: WorkerScript, rerenderUi = true): void
|
||||
}
|
||||
|
||||
if (rerenderUi) {
|
||||
WorkerScriptStartStopEventEmitter.emitEvent();
|
||||
WorkerScriptStartStopEventEmitter.emit();
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid argument passed into removeWorkerScript():`);
|
||||
|
@ -119,13 +119,7 @@ import { SpecialServerIps } from "./Server/SpecialServerIps";
|
||||
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { buyStock, sellStock, shortStock, sellShort } from "./StockMarket/BuyingAndSelling";
|
||||
import { influenceStockThroughServerHack, influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing";
|
||||
import {
|
||||
StockMarket,
|
||||
SymbolToStockMap,
|
||||
placeOrder,
|
||||
cancelOrder,
|
||||
displayStockMarketContent,
|
||||
} from "./StockMarket/StockMarket";
|
||||
import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder } from "./StockMarket/StockMarket";
|
||||
import { getBuyTransactionCost, getSellTransactionGain } from "./StockMarket/StockMarketHelpers";
|
||||
import { OrderTypes } from "./StockMarket/data/OrderTypes";
|
||||
import { PositionTypes } from "./StockMarket/data/PositionTypes";
|
||||
@ -142,7 +136,8 @@ import { Interpreter } from "./JSInterpreter";
|
||||
import { NetscriptPort } from "./NetscriptPort";
|
||||
import { SleeveTaskType } from "./PersonObjects/Sleeve/SleeveTaskTypesEnum";
|
||||
import { findSleevePurchasableAugs } from "./PersonObjects/Sleeve/SleeveHelpers";
|
||||
import { Exploit } from "./Exploits/Exploit.ts";
|
||||
import { Exploit } from "./Exploits/Exploit";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
|
||||
import { numeralWrapper } from "./ui/numeralFormat";
|
||||
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
||||
@ -1365,7 +1360,7 @@ function NetscriptFunctions(workerScript) {
|
||||
for (let i = server.runningScripts.length - 1; i >= 0; --i) {
|
||||
killWorkerScript(server.runningScripts[i], server.ip, false);
|
||||
}
|
||||
WorkerScriptStartStopEventEmitter.emitEvent();
|
||||
WorkerScriptStartStopEventEmitter.emit();
|
||||
workerScript.log(
|
||||
"killall",
|
||||
`Killing all scripts on '${server.hostname}'. May take a few minutes for the scripts to die.`,
|
||||
@ -1964,18 +1959,14 @@ function NetscriptFunctions(workerScript) {
|
||||
updateDynamicRam("buyStock", getRamCost("buyStock"));
|
||||
checkTixApiAccess("buyStock");
|
||||
const stock = getStockFromSymbol(symbol, "buyStock");
|
||||
const res = buyStock(stock, shares, workerScript, {
|
||||
rerenderFn: displayStockMarketContent,
|
||||
});
|
||||
const res = buyStock(stock, shares, workerScript, {});
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
sellStock: function (symbol, shares) {
|
||||
updateDynamicRam("sellStock", getRamCost("sellStock"));
|
||||
checkTixApiAccess("sellStock");
|
||||
const stock = getStockFromSymbol(symbol, "sellStock");
|
||||
const res = sellStock(stock, shares, workerScript, {
|
||||
rerenderFn: displayStockMarketContent,
|
||||
});
|
||||
const res = sellStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
@ -1991,9 +1982,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "shortStock");
|
||||
const res = shortStock(stock, shares, workerScript, {
|
||||
rerenderFn: displayStockMarketContent,
|
||||
});
|
||||
const res = shortStock(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
@ -2009,9 +1998,7 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
}
|
||||
const stock = getStockFromSymbol(symbol, "sellShort");
|
||||
const res = sellShort(stock, shares, workerScript, {
|
||||
rerenderFn: displayStockMarketContent,
|
||||
});
|
||||
const res = sellShort(stock, shares, workerScript, {});
|
||||
|
||||
return res ? stock.price : 0;
|
||||
},
|
||||
@ -2168,7 +2155,6 @@ function NetscriptFunctions(workerScript) {
|
||||
Player.has4SData = true;
|
||||
Player.loseMoney(getStockMarket4SDataCost());
|
||||
workerScript.log("purchase4SMarketData", "Purchased 4S Market Data");
|
||||
displayStockMarketContent();
|
||||
return true;
|
||||
},
|
||||
purchase4SMarketDataTixApi: function () {
|
||||
@ -2188,7 +2174,6 @@ function NetscriptFunctions(workerScript) {
|
||||
Player.has4SDataTixApi = true;
|
||||
Player.loseMoney(getStockMarket4STixApiCost());
|
||||
workerScript.log("purchase4SMarketDataTixApi", "Purchased 4S Market Data TIX API");
|
||||
displayStockMarketContent();
|
||||
return true;
|
||||
},
|
||||
getPurchasedServerLimit: function () {
|
||||
@ -2910,7 +2895,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.log("universityCourse", `Invalid class name: ${className}.`);
|
||||
return false;
|
||||
}
|
||||
Player.startClass(costMult, expMult, task);
|
||||
Player.startClass(Router, costMult, expMult, task);
|
||||
workerScript.log("universityCourse", `Started ${task} at ${universityName}`);
|
||||
return true;
|
||||
},
|
||||
@ -2987,19 +2972,19 @@ function NetscriptFunctions(workerScript) {
|
||||
switch (stat.toLowerCase()) {
|
||||
case "strength".toLowerCase():
|
||||
case "str".toLowerCase():
|
||||
Player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength);
|
||||
Player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymStrength);
|
||||
break;
|
||||
case "defense".toLowerCase():
|
||||
case "def".toLowerCase():
|
||||
Player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense);
|
||||
Player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymDefense);
|
||||
break;
|
||||
case "dexterity".toLowerCase():
|
||||
case "dex".toLowerCase():
|
||||
Player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity);
|
||||
Player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymDexterity);
|
||||
break;
|
||||
case "agility".toLowerCase():
|
||||
case "agi".toLowerCase():
|
||||
Player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility);
|
||||
Player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymAgility);
|
||||
break;
|
||||
default:
|
||||
workerScript.log("gymWorkout", `Invalid stat: ${stat}.`);
|
||||
@ -3435,9 +3420,9 @@ function NetscriptFunctions(workerScript) {
|
||||
}
|
||||
|
||||
if (companyPosition.isPartTimeJob()) {
|
||||
Player.startWorkPartTime(companyName);
|
||||
Player.startWorkPartTime(Router, companyName);
|
||||
} else {
|
||||
Player.startWork(companyName);
|
||||
Player.startWork(Router, companyName);
|
||||
}
|
||||
workerScript.log("workForCompany", `Began working at '${Player.companyName}' as a '${companyPositionName}'`);
|
||||
return true;
|
||||
@ -3676,7 +3661,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with hacking contracts.`);
|
||||
return false;
|
||||
}
|
||||
Player.startFactionHackWork(fac);
|
||||
Player.startFactionHackWork(Router, fac);
|
||||
workerScript.log("workForFaction", `Started carrying out hacking contracts for '${fac.name}'`);
|
||||
return true;
|
||||
case "field":
|
||||
@ -3686,7 +3671,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with field missions.`);
|
||||
return false;
|
||||
}
|
||||
Player.startFactionFieldWork(fac);
|
||||
Player.startFactionFieldWork(Router, fac);
|
||||
workerScript.log("workForFaction", `Started carrying out field missions for '${fac.name}'`);
|
||||
return true;
|
||||
case "security":
|
||||
@ -3696,7 +3681,7 @@ function NetscriptFunctions(workerScript) {
|
||||
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with security work.`);
|
||||
return false;
|
||||
}
|
||||
Player.startFactionSecurityWork(fac);
|
||||
Player.startFactionSecurityWork(Router, fac);
|
||||
workerScript.log("workForFaction", `Started carrying out security work for '${fac.name}'`);
|
||||
return true;
|
||||
default:
|
||||
@ -3797,7 +3782,7 @@ function NetscriptFunctions(workerScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.startCreateProgramWork(p.name, p.create.time, p.create.level);
|
||||
Player.startCreateProgramWork(Router, p.name, p.create.time, p.create.level);
|
||||
workerScript.log("createProgram", `Began creating program: '${name}'`);
|
||||
return true;
|
||||
},
|
||||
@ -3822,7 +3807,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`);
|
||||
}
|
||||
workerScript.log("commitCrime", `Attempting to commit ${crime.name}...`);
|
||||
return crime.commit(Player, 1, { workerscript: workerScript });
|
||||
return crime.commit(Router, Player, 1, { workerscript: workerScript });
|
||||
},
|
||||
getCrimeChance: function (crimeRoughName) {
|
||||
updateDynamicRam("getCrimeChance", getRamCost("getCrimeChance"));
|
||||
|
@ -9,7 +9,6 @@ import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStart
|
||||
import { generateNextPid } from "./Netscript/Pid";
|
||||
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { Interpreter } from "./JSInterpreter";
|
||||
import { isScriptErrorMessage, makeRuntimeRejectMsg } from "./NetscriptEvaluator";
|
||||
import { NetscriptFunctions } from "./NetscriptFunctions";
|
||||
@ -45,7 +44,7 @@ export function prestigeWorkerScripts() {
|
||||
killWorkerScript(ws);
|
||||
}
|
||||
|
||||
WorkerScriptStartStopEventEmitter.emitEvent();
|
||||
WorkerScriptStartStopEventEmitter.emit();
|
||||
workerScripts.clear();
|
||||
}
|
||||
|
||||
@ -501,7 +500,7 @@ export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
|
||||
// Add the WorkerScript to the global pool
|
||||
workerScripts.set(pid, s);
|
||||
WorkerScriptStartStopEventEmitter.emitEvent();
|
||||
WorkerScriptStartStopEventEmitter.emit();
|
||||
|
||||
// Start the script's execution
|
||||
let p = null; // Script's resulting promise
|
||||
@ -586,7 +585,7 @@ export function createAndAddWorkerScript(runningScriptObj, server, parent) {
|
||||
* Updates the online running time stat of all running scripts
|
||||
*/
|
||||
export function updateOnlineScriptTimes(numCycles = 1) {
|
||||
var time = (numCycles * Engine._idleSpeed) / 1000; //seconds
|
||||
var time = (numCycles * CONSTANTS._idleSpeed) / 1000; //seconds
|
||||
for (const ws of workerScripts.values()) {
|
||||
ws.scriptRef.onlineRunningTime += time;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import { ICorporation } from "../Corporation/ICorporation";
|
||||
import { IGang } from "../Gang/IGang";
|
||||
import { IBladeburner } from "../Bladeburner/IBladeburner";
|
||||
import { ICodingContractReward } from "../CodingContracts";
|
||||
import { IRouter } from "../ui/Router";
|
||||
|
||||
export interface IPlayer {
|
||||
// Class members
|
||||
@ -121,8 +122,33 @@ export interface IPlayer {
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
|
||||
workRepGained: number;
|
||||
createProgramName: string;
|
||||
timeWorkedCreateProgram: number;
|
||||
crimeType: string;
|
||||
timeNeededToCompleteWork: number;
|
||||
focus: boolean;
|
||||
className: string;
|
||||
currentWorkFactionName: string;
|
||||
workType: string;
|
||||
currentWorkFactionDescription: string;
|
||||
timeWorked: number;
|
||||
workMoneyGained: number;
|
||||
workMoneyGainRate: number;
|
||||
workRepGained: number;
|
||||
workRepGainRate: number;
|
||||
workHackExpGained: number;
|
||||
workHackExpGainRate: number;
|
||||
workStrExpGained: number;
|
||||
workStrExpGainRate: number;
|
||||
workDefExpGained: number;
|
||||
workDefExpGainRate: number;
|
||||
workDexExpGained: number;
|
||||
workDexExpGainRate: number;
|
||||
workAgiExpGained: number;
|
||||
workAgiExpGainRate: number;
|
||||
workChaExpGained: number;
|
||||
workChaExpGainRate: number;
|
||||
workMoneyLossRate: number;
|
||||
|
||||
// Methods
|
||||
applyForAgentJob(sing?: boolean): boolean | void;
|
||||
@ -175,9 +201,10 @@ export interface IPlayer {
|
||||
setMoney(amt: number): void;
|
||||
singularityStopWork(): void;
|
||||
startBladeburner(p: any): void;
|
||||
startClass(costMult: number, expMult: number, className: string): void;
|
||||
startClass(router: IRouter, costMult: number, expMult: number, className: string): void;
|
||||
startCorporation(corpName: string, additionalShares?: number): void;
|
||||
startCrime(
|
||||
router: IRouter,
|
||||
crimeType: string,
|
||||
hackExp: number,
|
||||
strExp: number,
|
||||
@ -189,13 +216,13 @@ export interface IPlayer {
|
||||
time: number,
|
||||
singParams: any,
|
||||
): void;
|
||||
startFactionFieldWork(faction: Faction): void;
|
||||
startFactionHackWork(faction: Faction): void;
|
||||
startFactionSecurityWork(faction: Faction): void;
|
||||
startFactionFieldWork(router: IRouter, faction: Faction): void;
|
||||
startFactionHackWork(router: IRouter, faction: Faction): void;
|
||||
startFactionSecurityWork(router: IRouter, faction: Faction): void;
|
||||
startFocusing(): void;
|
||||
startGang(facName: string, isHacking: boolean): void;
|
||||
startWork(companyName: string): void;
|
||||
startWorkPartTime(companyName: string): void;
|
||||
startWork(router: IRouter, companyName: string): void;
|
||||
startWorkPartTime(router: IRouter, companyName: string): void;
|
||||
takeDamage(amt: number): boolean;
|
||||
travel(to: CityName): boolean;
|
||||
giveExploit(exploit: Exploit): void;
|
||||
@ -204,9 +231,17 @@ export interface IPlayer {
|
||||
getCasinoWinnings(): number;
|
||||
quitJob(company: string): void;
|
||||
createHacknetServer(): void;
|
||||
startCreateProgramWork(programName: string, time: number, reqLevel: number): void;
|
||||
startCreateProgramWork(router: IRouter, programName: string, time: number, reqLevel: number): void;
|
||||
queueAugmentation(augmentationName: string): void;
|
||||
receiveInvite(factionName: string): void;
|
||||
updateSkillLevels(): void;
|
||||
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
|
||||
stopFocusing(): void;
|
||||
finishFactionWork(cancelled: boolean, sing?: boolean): void;
|
||||
finishClass(sing?: boolean): void;
|
||||
finishWork(cancelled: boolean, sing?: boolean): void;
|
||||
cancelationPenalty(): number;
|
||||
finishWorkPartTime(sing?: boolean): void;
|
||||
finishCrime(cancelled: boolean): void;
|
||||
finishCreateProgramWork(cancelled: boolean): void;
|
||||
}
|
||||
|
@ -14,10 +14,8 @@ import { CONSTANTS } from "../../Constants";
|
||||
import { Programs } from "../../Programs/Programs";
|
||||
import { determineCrimeSuccess } from "../../Crime/CrimeHelpers";
|
||||
import { Crimes } from "../../Crime/Crimes";
|
||||
import { Engine } from "../../engine";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
import { resetGangs } from "../../Gang/AllGangs";
|
||||
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
@ -48,18 +46,12 @@ import Decimal from "decimal.js";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { clearEventListeners } from "../../../utils/uiHelpers/clearEventListeners";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { ReputationRate } from "../../ui/React/ReputationRate";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
|
||||
|
||||
export function init() {
|
||||
/* Initialize Player's home computer */
|
||||
@ -518,8 +510,6 @@ export function resetWorkStatus(generalType, group, workType) {
|
||||
this.currentWorkFactionDescription = "";
|
||||
this.createProgramName = "";
|
||||
this.className = "";
|
||||
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("work-in-progress-text"));
|
||||
}
|
||||
|
||||
export function processWorkEarnings(numCycles = 1) {
|
||||
@ -556,7 +546,7 @@ export function processWorkEarnings(numCycles = 1) {
|
||||
}
|
||||
|
||||
/* Working for Company */
|
||||
export function startWork(companyName) {
|
||||
export function startWork(router, companyName) {
|
||||
this.resetWorkStatus(CONSTANTS.WorkTypeCompany, companyName);
|
||||
this.isWorking = true;
|
||||
this.focus = true;
|
||||
@ -573,25 +563,7 @@ export function startWork(companyName) {
|
||||
this.workMoneyGainRate = this.getWorkMoneyGain();
|
||||
|
||||
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours;
|
||||
|
||||
//Remove all old event listeners from Cancel button
|
||||
var newCancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
newCancelButton.innerHTML = "Cancel Work";
|
||||
newCancelButton.addEventListener("click", () => {
|
||||
this.finishWork(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "visible";
|
||||
focusButton.innerHTML = "Do something else simultaneously";
|
||||
focusButton.addEventListener("click", () => {
|
||||
this.stopFocusing();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function cancelationPenalty() {
|
||||
@ -607,78 +579,24 @@ export function work(numCycles) {
|
||||
// Cap the number of cycles being processed to whatever would put you at
|
||||
// the work time limit (8 hours)
|
||||
var overMax = false;
|
||||
if (this.timeWorked + Engine._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.workRepGainRate = this.getWorkRepGain();
|
||||
this.processWorkEarnings(numCycles);
|
||||
|
||||
const comp = Companies[this.companyName];
|
||||
influenceStockThroughCompanyWork(comp, this.workRepGainRate, numCycles);
|
||||
|
||||
// If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money
|
||||
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
return this.finishWork(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const comp = Companies[this.companyName];
|
||||
let companyRep = "0";
|
||||
if (comp == null || !(comp instanceof Company)) {
|
||||
console.error(`Could not find Company: ${this.companyName}`);
|
||||
} else {
|
||||
companyRep = comp.playerReputation;
|
||||
}
|
||||
|
||||
influenceStockThroughCompanyWork(comp, this.workRepGainRate, numCycles);
|
||||
|
||||
const position = this.jobs[this.companyName];
|
||||
|
||||
const penalty = this.cancelationPenalty();
|
||||
|
||||
const penaltyString = penalty === 0.5 ? "half" : "three-quarters";
|
||||
|
||||
var elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} ({ReputationRate(this.workRepGainRate * CYCLES_PER_SEC)}) reputation for this
|
||||
company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, but you will only
|
||||
gain {penaltyString} of the reputation you've earned so far.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function finishWork(cancelled, sing = false) {
|
||||
@ -731,10 +649,7 @@ export function finishWork(cancelled, sing = false) {
|
||||
dialogBoxCreate(content);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
Engine.loadLocationContent(false);
|
||||
|
||||
if (sing) {
|
||||
var res =
|
||||
@ -764,7 +679,7 @@ export function finishWork(cancelled, sing = false) {
|
||||
this.resetWorkStatus();
|
||||
}
|
||||
|
||||
export function startWorkPartTime(companyName) {
|
||||
export function startWorkPartTime(router, companyName) {
|
||||
this.resetWorkStatus(CONSTANTS.WorkTypeCompanyPartTime, companyName);
|
||||
this.isWorking = true;
|
||||
this.focus = true;
|
||||
@ -781,27 +696,18 @@ export function startWorkPartTime(companyName) {
|
||||
this.workMoneyGainRate = this.getWorkMoneyGain();
|
||||
|
||||
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours;
|
||||
|
||||
var newCancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
newCancelButton.innerHTML = "Stop Working";
|
||||
newCancelButton.addEventListener("click", () => {
|
||||
this.finishWorkPartTime();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function workPartTime(numCycles) {
|
||||
//Cap the number of cycles being processed to whatever would put you at the
|
||||
//work time limit (8 hours)
|
||||
var overMax = false;
|
||||
if (this.timeWorked + Engine._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.workRepGainRate = this.getWorkRepGain();
|
||||
this.processWorkEarnings(numCycles);
|
||||
@ -809,61 +715,9 @@ export function workPartTime(numCycles) {
|
||||
//If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money
|
||||
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
return this.finishWorkPartTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
var comp = Companies[this.companyName],
|
||||
companyRep = "0";
|
||||
if (comp == null || !(comp instanceof Company)) {
|
||||
console.error(`Could not find Company: ${this.companyName}`);
|
||||
} else {
|
||||
companyRep = comp.playerReputation;
|
||||
}
|
||||
|
||||
const position = this.jobs[this.companyName];
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} (
|
||||
{Reputation(`${numeralWrapper.formatExp(this.workRepGainRate * CYCLES_PER_SEC)} / sec`)}
|
||||
) reputation for this company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, and there will be no
|
||||
penalty because this is a part-time job.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function finishWorkPartTime(sing = false) {
|
||||
@ -894,10 +748,7 @@ export function finishWorkPartTime(sing = false) {
|
||||
dialogBoxCreate(content);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
Engine.loadLocationContent(false);
|
||||
if (sing) {
|
||||
var res =
|
||||
"You worked for " +
|
||||
@ -928,21 +779,15 @@ export function finishWorkPartTime(sing = false) {
|
||||
}
|
||||
|
||||
export function startFocusing() {
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
this.focus = true;
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function stopFocusing() {
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.focus = false;
|
||||
Engine.loadTerminalContent();
|
||||
}
|
||||
|
||||
/* Working for Faction */
|
||||
export function startFactionWork(faction) {
|
||||
export function startFactionWork(router, faction) {
|
||||
//Update reputation gain rate to account for faction favor
|
||||
var favorMult = 1 + faction.favor / 100;
|
||||
if (isNaN(favorMult)) {
|
||||
@ -957,27 +802,10 @@ export function startFactionWork(faction) {
|
||||
this.currentWorkFactionName = faction.name;
|
||||
|
||||
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
|
||||
|
||||
const cancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
cancelButton.innerHTML = "Stop Faction Work";
|
||||
cancelButton.addEventListener("click", () => {
|
||||
this.finishFactionWork(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "visible";
|
||||
focusButton.innerHTML = "Do something else simultaneously";
|
||||
focusButton.addEventListener("click", () => {
|
||||
this.stopFocusing();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function startFactionHackWork(faction) {
|
||||
export function startFactionHackWork(router, faction) {
|
||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
|
||||
|
||||
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
@ -989,10 +817,10 @@ export function startFactionHackWork(faction) {
|
||||
this.factionWorkType = CONSTANTS.FactionWorkHacking;
|
||||
this.currentWorkFactionDescription = "carrying out hacking contracts";
|
||||
|
||||
this.startFactionWork(faction);
|
||||
this.startFactionWork(router, faction);
|
||||
}
|
||||
|
||||
export function startFactionFieldWork(faction) {
|
||||
export function startFactionFieldWork(router, faction) {
|
||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkField);
|
||||
|
||||
this.workHackExpGainRate = 0.1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
@ -1006,10 +834,10 @@ export function startFactionFieldWork(faction) {
|
||||
this.factionWorkType = CONSTANTS.FactionWorkField;
|
||||
this.currentWorkFactionDescription = "carrying out field missions";
|
||||
|
||||
this.startFactionWork(faction);
|
||||
this.startFactionWork(router, faction);
|
||||
}
|
||||
|
||||
export function startFactionSecurityWork(faction) {
|
||||
export function startFactionSecurityWork(router, faction) {
|
||||
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkSecurity);
|
||||
|
||||
this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
|
||||
@ -1023,7 +851,7 @@ export function startFactionSecurityWork(faction) {
|
||||
this.factionWorkType = CONSTANTS.FactionWorkSecurity;
|
||||
this.currentWorkFactionDescription = "performing security detail";
|
||||
|
||||
this.startFactionWork(faction);
|
||||
this.startFactionWork(router, faction);
|
||||
}
|
||||
|
||||
export function workForFaction(numCycles) {
|
||||
@ -1046,56 +874,20 @@ export function workForFaction(numCycles) {
|
||||
|
||||
//Cap the number of cycles being processed to whatever would put you at limit (20 hours)
|
||||
var overMax = false;
|
||||
if (this.timeWorked + Engine._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer20Hours) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer20Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.processWorkEarnings(numCycles);
|
||||
|
||||
//If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours
|
||||
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) {
|
||||
return this.finishFactionWork(false);
|
||||
this.finishFactionWork(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently {this.currentWorkFactionDescription} for your faction {faction.name}
|
||||
<br />
|
||||
(Current Faction Reputation: {Reputation(faction.playerReputation)}). <br />
|
||||
You have been doing this for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} ({ReputationRate(this.workRepGainRate * CYCLES_PER_SEC)}) reputation for this
|
||||
faction <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
|
||||
<br />
|
||||
There is no penalty for cancelling earlier.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function finishFactionWork(cancelled, sing = false) {
|
||||
@ -1125,13 +917,8 @@ export function finishFactionWork(cancelled, sing = false) {
|
||||
);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(faction.name);
|
||||
if (sing) {
|
||||
var res =
|
||||
"You worked for your faction " +
|
||||
@ -1387,7 +1174,7 @@ export function getWorkRepGain() {
|
||||
// }
|
||||
|
||||
/* Creating a Program */
|
||||
export function startCreateProgramWork(programName, time, reqLevel) {
|
||||
export function startCreateProgramWork(router, programName, time, reqLevel) {
|
||||
this.resetWorkStatus();
|
||||
this.isWorking = true;
|
||||
this.focus = true;
|
||||
@ -1419,19 +1206,7 @@ export function startCreateProgramWork(programName, time, reqLevel) {
|
||||
}
|
||||
|
||||
this.createProgramName = programName;
|
||||
|
||||
var cancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
cancelButton.innerHTML = "Cancel work on creating program";
|
||||
cancelButton.addEventListener("click", () => {
|
||||
this.finishCreateProgramWork(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function createProgramWork(numCycles) {
|
||||
@ -1441,28 +1216,14 @@ export function createProgramWork(numCycles) {
|
||||
skillMult = 1 + (skillMult - 1) / 5; //The divider constant can be adjusted as necessary
|
||||
|
||||
//Skill multiplier directly applied to "time worked"
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorkedCreateProgram += Engine._idleSpeed * numCycles * skillMult;
|
||||
var programName = this.createProgramName;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
this.timeWorkedCreateProgram += CONSTANTS._idleSpeed * numCycles * skillMult;
|
||||
|
||||
if (this.timeWorkedCreateProgram >= this.timeNeededToCompleteWork) {
|
||||
this.finishCreateProgramWork(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working on coding {programName}.<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
The program is {((this.timeWorkedCreateProgram / this.timeNeededToCompleteWork) * 100).toFixed(2)}
|
||||
% complete. <br />
|
||||
If you cancel, your work will be saved and you can come back to complete the program later.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function finishCreateProgramWork(cancelled) {
|
||||
@ -1483,17 +1244,13 @@ export function finishCreateProgramWork(cancelled) {
|
||||
this.gainIntelligenceExp(this.createProgramReqLvl / CONSTANTS.IntelligenceProgramBaseExpGain);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
Engine.loadTerminalContent();
|
||||
this.resetWorkStatus();
|
||||
}
|
||||
|
||||
/* Studying/Taking Classes */
|
||||
export function startClass(costMult, expMult, className) {
|
||||
export function startClass(router, costMult, expMult, className) {
|
||||
this.resetWorkStatus();
|
||||
this.isWorking = true;
|
||||
this.focus = true;
|
||||
@ -1501,7 +1258,7 @@ export function startClass(costMult, expMult, className) {
|
||||
|
||||
this.className = className;
|
||||
|
||||
const gameCPS = 1000 / Engine._idleSpeed;
|
||||
const gameCPS = 1000 / CONSTANTS._idleSpeed;
|
||||
|
||||
//Find cost and exp gain per game cycle
|
||||
var cost = 0;
|
||||
@ -1564,62 +1321,13 @@ export function startClass(costMult, expMult, className) {
|
||||
this.workDexExpGainRate = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.ClassGymExpGain;
|
||||
this.workAgiExpGainRate = agiExp * this.agility_exp_mult * BitNodeMultipliers.ClassGymExpGain;
|
||||
this.workChaExpGainRate = chaExp * this.charisma_exp_mult * BitNodeMultipliers.ClassGymExpGain;
|
||||
|
||||
var cancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
if (
|
||||
className == CONSTANTS.ClassGymStrength ||
|
||||
className == CONSTANTS.ClassGymDefense ||
|
||||
className == CONSTANTS.ClassGymDexterity ||
|
||||
className == CONSTANTS.ClassGymAgility
|
||||
) {
|
||||
cancelButton.innerHTML = "Stop training at gym";
|
||||
} else {
|
||||
cancelButton.innerHTML = "Stop taking course";
|
||||
}
|
||||
cancelButton.addEventListener("click", () => {
|
||||
this.finishClass();
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function takeClass(numCycles) {
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
var className = this.className;
|
||||
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
this.processWorkEarnings(numCycles);
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You have been {className} for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
This has cost you: <br />
|
||||
<Money money={-this.workMoneyGained} /> ({MoneyRate(this.workMoneyLossRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
You have gained: <br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
You may cancel at any time
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
//The 'sing' argument defines whether or not this function was called
|
||||
@ -1650,12 +1358,8 @@ export function finishClass(sing = false) {
|
||||
);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
Engine.loadLocationContent(false);
|
||||
if (sing) {
|
||||
var res =
|
||||
"After " +
|
||||
@ -1686,7 +1390,19 @@ export function finishClass(sing = false) {
|
||||
}
|
||||
|
||||
//The EXP and $ gains are hardcoded. Time is in ms
|
||||
export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams = null) {
|
||||
export function startCrime(
|
||||
router,
|
||||
crimeType,
|
||||
hackExp,
|
||||
strExp,
|
||||
defExp,
|
||||
dexExp,
|
||||
agiExp,
|
||||
chaExp,
|
||||
money,
|
||||
time,
|
||||
singParams = null,
|
||||
) {
|
||||
this.crimeType = crimeType;
|
||||
|
||||
this.resetWorkStatus();
|
||||
@ -1708,49 +1424,17 @@ export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, c
|
||||
this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
|
||||
|
||||
this.timeNeededToCompleteWork = time;
|
||||
|
||||
//Remove all old event listeners from Cancel button
|
||||
const newCancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
newCancelButton.innerHTML = "Cancel crime";
|
||||
newCancelButton.addEventListener("click", () => {
|
||||
this.finishCrime(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
export function commitCrime(numCycles) {
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
if (this.timeWorked >= this.timeNeededToCompleteWork) {
|
||||
this.finishCrime(false);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var percent = Math.round((this.timeWorked / this.timeNeededToCompleteWork) * 100);
|
||||
var numBars = Math.round(percent / 5);
|
||||
if (numBars < 0) {
|
||||
numBars = 0;
|
||||
}
|
||||
if (numBars > 20) {
|
||||
numBars = 20;
|
||||
}
|
||||
var progressBar = "[" + Array(numBars + 1).join("|") + Array(20 - numBars + 1).join(" ") + "]";
|
||||
|
||||
var txt = document.getElementById("work-in-progress-text");
|
||||
txt.innerHTML =
|
||||
"You are attempting to " +
|
||||
this.crimeType +
|
||||
".<br>" +
|
||||
"Time remaining: " +
|
||||
convertTimeMsToTimeElapsedString(this.timeNeededToCompleteWork - this.timeWorked) +
|
||||
"<br>" +
|
||||
progressBar.replace(/ /g, " ");
|
||||
return false;
|
||||
}
|
||||
|
||||
export function finishCrime(cancelled) {
|
||||
@ -1892,11 +1576,9 @@ export function finishCrime(cancelled) {
|
||||
}
|
||||
this.committingCrimeThruSingFn = false;
|
||||
this.singFnCrimeWorkerScript = null;
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
this.crimeType = "";
|
||||
this.resetWorkStatus();
|
||||
Engine.loadLocationContent(false);
|
||||
}
|
||||
|
||||
//Cancels the player's current "work" assignment and gives the proper rewards
|
||||
|
@ -11,8 +11,8 @@ interface IProps {
|
||||
export function MoreEarningsContent(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{StatsTable(
|
||||
[
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Money ", <Money money={props.sleeve.earningsForTask.money} />],
|
||||
["Hacking Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.hack)],
|
||||
["Strength Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.str)],
|
||||
@ -20,12 +20,12 @@ export function MoreEarningsContent(props: IProps): React.ReactElement {
|
||||
["Dexterity Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.dex)],
|
||||
["Agility Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.agi)],
|
||||
["Charisma Exp ", numeralWrapper.formatExp(props.sleeve.earningsForTask.cha)],
|
||||
],
|
||||
"Earnings for Current Task:",
|
||||
)}
|
||||
]}
|
||||
title="Earnings for Current Task:"
|
||||
/>
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Money: ", <Money money={props.sleeve.earningsForPlayer.money} />],
|
||||
["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.hack)],
|
||||
["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.str)],
|
||||
@ -33,12 +33,12 @@ export function MoreEarningsContent(props: IProps): React.ReactElement {
|
||||
["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.dex)],
|
||||
["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.agi)],
|
||||
["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForPlayer.cha)],
|
||||
],
|
||||
"Total Earnings for Host Consciousness:",
|
||||
)}
|
||||
]}
|
||||
title="Total Earnings for Host Consciousness:"
|
||||
/>
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Money: ", <Money money={props.sleeve.earningsForSleeves.money} />],
|
||||
["Hacking Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.hack)],
|
||||
["Strength Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.str)],
|
||||
@ -46,9 +46,9 @@ export function MoreEarningsContent(props: IProps): React.ReactElement {
|
||||
["Dexterity Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.dex)],
|
||||
["Agility Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.agi)],
|
||||
["Charisma Exp: ", numeralWrapper.formatExp(props.sleeve.earningsForSleeves.cha)],
|
||||
],
|
||||
"Total Earnings for Other Sleeves:",
|
||||
)}
|
||||
]}
|
||||
title="Total Earnings for Other Sleeves:"
|
||||
/>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
|
@ -10,20 +10,20 @@ interface IProps {
|
||||
export function MoreStatsContent(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{StatsTable(
|
||||
[
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Hacking: ", props.sleeve.hacking_skill, `(${numeralWrapper.formatExp(props.sleeve.hacking_exp)} exp)`],
|
||||
["Strength: ", props.sleeve.strength, `(${numeralWrapper.formatExp(props.sleeve.strength_exp)} exp)`],
|
||||
["Defense: ", props.sleeve.defense, `(${numeralWrapper.formatExp(props.sleeve.defense_exp)} exp)`],
|
||||
["Dexterity: ", props.sleeve.dexterity, `(${numeralWrapper.formatExp(props.sleeve.dexterity_exp)} exp)`],
|
||||
["Agility: ", props.sleeve.agility, `(${numeralWrapper.formatExp(props.sleeve.agility_exp)} exp)`],
|
||||
["Charisma: ", props.sleeve.charisma, `(${numeralWrapper.formatExp(props.sleeve.charisma_exp)} exp)`],
|
||||
],
|
||||
"Stats:",
|
||||
)}
|
||||
]}
|
||||
title="Stats:"
|
||||
/>
|
||||
<br />
|
||||
{StatsTable(
|
||||
[
|
||||
<StatsTable
|
||||
rows={[
|
||||
["Hacking Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.hacking_mult)],
|
||||
["Hacking Experience multiplier: ", numeralWrapper.formatPercentage(props.sleeve.hacking_exp_mult)],
|
||||
["Strength Level multiplier: ", numeralWrapper.formatPercentage(props.sleeve.strength_mult)],
|
||||
@ -41,9 +41,9 @@ export function MoreStatsContent(props: IProps): React.ReactElement {
|
||||
["Salary multiplier: ", numeralWrapper.formatPercentage(props.sleeve.work_money_mult)],
|
||||
["Crime Money multiplier: ", numeralWrapper.formatPercentage(props.sleeve.crime_money_mult)],
|
||||
["Crime Success multiplier: ", numeralWrapper.formatPercentage(props.sleeve.crime_success_mult)],
|
||||
],
|
||||
"Multipliers:",
|
||||
)}
|
||||
]}
|
||||
title="Multipliers:"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user