Merge pull request #1235 from danielyxie/dev

Fix travel to s12 in list view
This commit is contained in:
hydroflame 2021-09-13 14:44:07 -04:00 committed by GitHub
commit ae15caf45a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1680 additions and 1172 deletions

@ -63,7 +63,6 @@ module.exports = {
"id-blacklist": ["error"], "id-blacklist": ["error"],
"id-length": ["off"], "id-length": ["off"],
"id-match": ["error"], "id-match": ["error"],
"implicit-arrow-linebreak": ["error", "beside"],
indent: ["off"], indent: ["off"],
"indent-legacy": ["off"], "indent-legacy": ["off"],
"init-declarations": ["off"], "init-declarations": ["off"],

@ -133,6 +133,7 @@
} }
.cmpy-mgmt-upgrade-div { .cmpy-mgmt-upgrade-div {
text-align: left;
display: inline-block; display: inline-block;
border: 1px solid #fff; border: 1px solid #fff;
margin: 2px; margin: 2px;

File diff suppressed because one or more lines are too long

@ -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([916,0]),o()}({916:function(n,t,o){"use strict";o.r(t);o(917),o(919),o(921),o(923),o(925),o(927),o(929),o(931),o(933),o(935),o(937),o(939),o(941),o(943),o(945),o(947),o(949),o(951),o(953),o(955),o(957),o(959),o(961),o(963),o(965),o(967),o(969),o(971),o(973),o(975),o(977)},919:function(n,t,o){},921:function(n,t,o){},923:function(n,t,o){},925:function(n,t,o){},927:function(n,t,o){},929:function(n,t,o){},931:function(n,t,o){},933:function(n,t,o){},935:function(n,t,o){},937:function(n,t,o){},939:function(n,t,o){},941:function(n,t,o){},943:function(n,t,o){},945:function(n,t,o){},947:function(n,t,o){},949:function(n,t,o){},951:function(n,t,o){},953:function(n,t,o){},955:function(n,t,o){},957:function(n,t,o){},959:function(n,t,o){},961:function(n,t,o){},963:function(n,t,o){},965:function(n,t,o){},967:function(n,t,o){},969:function(n,t,o){},971:function(n,t,o){},973:function(n,t,o){},975:function(n,t,o){},977: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([940,0]),o()}({1001:function(n,t,o){},940:function(n,t,o){"use strict";o.r(t);o(941),o(943),o(945),o(947),o(949),o(951),o(953),o(955),o(957),o(959),o(961),o(963),o(965),o(967),o(969),o(971),o(973),o(975),o(977),o(979),o(981),o(983),o(985),o(987),o(989),o(991),o(993),o(995),o(997),o(999),o(1001)},943:function(n,t,o){},945:function(n,t,o){},947:function(n,t,o){},949:function(n,t,o){},951:function(n,t,o){},953:function(n,t,o){},955:function(n,t,o){},957:function(n,t,o){},959:function(n,t,o){},961:function(n,t,o){},963:function(n,t,o){},965:function(n,t,o){},967:function(n,t,o){},969:function(n,t,o){},971:function(n,t,o){},973:function(n,t,o){},975:function(n,t,o){},977:function(n,t,o){},979:function(n,t,o){},981:function(n,t,o){},983:function(n,t,o){},985:function(n,t,o){},987:function(n,t,o){},989:function(n,t,o){},991:function(n,t,o){},993:function(n,t,o){},995:function(n,t,o){},997:function(n,t,o){},999:function(n,t,o){}});
//# sourceMappingURL=engineStyle.bundle.js.map //# sourceMappingURL=engineStyle.bundle.js.map

@ -3097,6 +3097,7 @@ input[type="checkbox"] {
padding: 6px; } padding: 6px; }
.cmpy-mgmt-upgrade-div { .cmpy-mgmt-upgrade-div {
text-align: left;
display: inline-block; display: inline-block;
border: 1px solid #fff; border: 1px solid #fff;
margin: 2px; margin: 2px;

30
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -60,27 +60,6 @@
<div id="generic-react-container"></div> <div id="generic-react-container"></div>
</div> </div>
<div id="infiltration-container" class="generic-fullscreen-container"></div> <div id="infiltration-container" class="generic-fullscreen-container"></div>
<!-- Generic Yes/No Pop Up box -->
<div id="yes-no-box-container" class="popup-box-container">
<div id="yes-no-box-content" class="popup-box-content">
<p id="yes-no-box-text"></p>
<button id="yes-no-box-yes" class="popup-box-button">Yes</button>
<button id="yes-no-box-no" class="popup-box-button">No</button>
</div>
</div>
<!-- Generic yes/no pop up box with text entry field -->
<div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"></p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30"/>
<button id="yes-no-text-input-box-yes" class="popup-box-button">Yes</button>
<button id="yes-no-text-input-box-no" class="popup-box-button">No</button>
</div>
</div>
<!-- Mission container -->
<div id="mission-container" class="generic-fullscreen-container"></div> <div id="mission-container" class="generic-fullscreen-container"></div>
<!-- Work in progress screen --> <!-- Work in progress screen -->
@ -94,9 +73,7 @@
</div> </div>
<!-- Red Pill Container --> <!-- Red Pill Container -->
<div id="red-pill-container" class="generic-fullscreen-container"> <div id="red-pill-container" class="generic-fullscreen-container"></div>
<div id="red-pill-content" class="generic-fullscreen-container-scroll"></div>
</div>
<!-- Cinematic Text Container --> <!-- Cinematic Text Container -->
<div id="cinematic-text-container" class="generic-fullscreen-container"></div> <div id="cinematic-text-container" class="generic-fullscreen-container"></div>

31
package-lock.json generated

@ -10,6 +10,7 @@
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.3", "@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@monaco-editor/react": "^4.2.2", "@monaco-editor/react": "^4.2.2",
"@types/js-beautify": "^1.13.2", "@types/js-beautify": "^1.13.2",
"@types/numeral": "0.0.25", "@types/numeral": "0.0.25",
@ -3150,6 +3151,28 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/@material-ui/icons": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
"integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
"dependencies": {
"@babel/runtime": "^7.4.4"
},
"engines": {
"node": ">=8.0.0"
},
"peerDependencies": {
"@material-ui/core": "^4.0.0",
"@types/react": "^16.8.6 || ^17.0.0",
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@material-ui/styles": { "node_modules/@material-ui/styles": {
"version": "4.11.3", "version": "4.11.3",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz",
@ -28366,6 +28389,14 @@
"react-transition-group": "^4.4.0" "react-transition-group": "^4.4.0"
} }
}, },
"@material-ui/icons": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
"integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
"requires": {
"@babel/runtime": "^7.4.4"
}
},
"@material-ui/styles": { "@material-ui/styles": {
"version": "4.11.3", "version": "4.11.3",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz",

@ -7,6 +7,7 @@
}, },
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.3", "@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@monaco-editor/react": "^4.2.2", "@monaco-editor/react": "^4.2.2",
"@types/js-beautify": "^1.13.2", "@types/js-beautify": "^1.13.2",
"@types/numeral": "0.0.25", "@types/numeral": "0.0.25",

@ -7,7 +7,7 @@ import * as React from "react";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { Exploit, ExploitName } from "../../Exploits/Exploit"; import { Exploit, ExploitName } from "../../Exploits/Exploit";
import { Accordion } from "../../ui/React/Accordion"; import { BBAccordion } from "../../ui/React/Accordion";
export function SourceFileMinus1(): React.ReactElement { export function SourceFileMinus1(): React.ReactElement {
const exploits = Player.exploits; const exploits = Player.exploits;
@ -18,7 +18,7 @@ export function SourceFileMinus1(): React.ReactElement {
return ( return (
<li key={-1}> <li key={-1}>
<Accordion <BBAccordion
headerContent={ headerContent={
<> <>
Source-File -1: Exploits in the BitNodes Source-File -1: Exploits in the BitNodes

@ -40,9 +40,9 @@ export function LevelableUpgrade(props: IProps): React.ReactElement {
} }
return ( return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{ width: "45%" }} onClick={onClick}> <button className={"cmpy-mgmt-upgrade-div tooltip"} style={{ width: "45%" }} onClick={onClick}>
{text} {text}
<span className={"tooltiptext"}>{tooltip}</span> <span className={"tooltiptext"}>{tooltip}</span>
</div> </button>
); );
} }

@ -27,330 +27,52 @@ interface IProps {
player: IPlayer; player: IPlayer;
rerender: () => void; rerender: () => void;
} }
export function Overview({ corp, player, rerender }: IProps): React.ReactElement {
export function Overview(props: IProps): React.ReactElement { const profit: number = corp.revenue.minus(corp.expenses).toNumber();
// Generic Function for Creating a button
interface ICreateButtonProps {
text: string;
class?: string;
className?: string;
display?: string;
tooltip?: string;
onClick?: (event: React.MouseEvent) => void;
}
function Button(props: ICreateButtonProps): React.ReactElement {
let className = props.className ? props.className : "std-button";
const hasTooltip = props.tooltip != null;
if (hasTooltip) className += " tooltip";
return (
<a className={className} onClick={props.onClick} style={{ display: props.display ? props.display : "block" }}>
{props.text}
{hasTooltip && <span className={"tooltiptext"}>{props.tooltip}</span>}
</a>
);
}
function openBribeFactionPopup(): void {
const popupId = "corp-bribe-popup";
createPopup(popupId, BribeFactionPopup, {
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
const profit: number = props.corp.revenue.minus(props.corp.expenses).toNumber();
function DividendsStats(): React.ReactElement {
if (props.corp.dividendPercentage <= 0 || profit <= 0) return <></>;
const totalDividends = (props.corp.dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / props.corp.totalShares;
const playerEarnings = props.corp.numShares * dividendsPerShare;
return (
<>
Retained Profits (after dividends): <Money money={retainedEarnings} /> / s<br />
<br />
Dividend Percentage: {numeralWrapper.format(props.corp.dividendPercentage / 100, "0%")}
<br />
Dividends per share: <Money money={dividendsPerShare} /> / s<br />
Your earnings as a shareholder (Pre-Tax): <Money money={playerEarnings} /> / s<br />
Dividend Tax Rate: {props.corp.dividendTaxPercentage}%<br />
Your earnings as a shareholder (Post-Tax):{" "}
<Money money={playerEarnings * (1 - props.corp.dividendTaxPercentage / 100)} /> / s<br />
<br />
</>
);
}
function Mult(props: { name: string; mult: number }): React.ReactElement {
if (props.mult <= 1) return <></>;
return (
<p>
{props.name}
{numeralWrapper.format(props.mult, "0.000")}
<br />
</p>
);
}
// Returns a string with general information about Corporation
function BonusTime(): React.ReactElement {
const storedTime = props.corp.storedCycles * CONSTANTS.MilliPerCycle;
if (storedTime <= 15000) return <></>;
return (
<p>
Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}
<br />
<br />
</p>
);
}
function BribeButton(): React.ReactElement {
const canBribe = props.corp.determineValuation() >= CorporationConstants.BribeThreshold || true;
const bribeFactionsClass = canBribe ? "a-link-button" : "a-link-button-inactive";
return (
<Button
className={bribeFactionsClass}
display="inline-block"
onClick={openBribeFactionPopup}
text="Bribe Factions"
tooltip={
canBribe
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
: "Your Corporation is not powerful enough to bribe Faction leaders"
}
/>
);
}
function openFindInvestorsPopup(): void {
const popupId = "cmpy-mgmt-find-investors-popup";
createPopup(popupId, FindInvestorsPopup, {
rerender: props.rerender,
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function openGoPublicPopup(): void {
const popupId = "cmpy-mgmt-go-public-popup";
createPopup(popupId, GoPublicPopup, {
rerender: props.rerender,
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
// Render the buttons for when your Corporation is still private
function PrivateButtons(): React.ReactElement {
const fundingAvailable = props.corp.fundingRound < 4;
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
const findInvestorsTooltip = fundingAvailable
? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company"
: undefined;
return (
<>
<Button
className={findInvestorsClassName}
onClick={openFindInvestorsPopup}
text="Find Investors"
tooltip={findInvestorsTooltip}
display="inline-block"
/>
<Button
className="std-button"
onClick={openGoPublicPopup}
display="inline-block"
text="Go Public"
tooltip={
"Become a publicly traded and owned entity. Going public " +
"involves issuing shares for an IPO. Once you are a public " +
"company, your shares will be traded on the stock market."
}
/>
<br />
</>
);
}
function openSellSharesPopup(): void {
const popupId = "cmpy-mgmt-sell-shares-popup";
createPopup(popupId, SellSharesPopup, {
corp: props.corp,
player: props.player,
popupId: popupId,
rerender: props.rerender,
});
}
function openBuybackSharesPopup(): void {
const popupId = "corp-buyback-shares-popup";
createPopup(popupId, BuybackSharesPopup, {
rerender: props.rerender,
player: props.player,
popupId: popupId,
corp: props.corp,
});
}
function openIssueNewSharesPopup(): void {
const popupId = "cmpy-mgmt-issue-new-shares-popup";
createPopup(popupId, IssueNewSharesPopup, {
popupId: popupId,
corp: props.corp,
});
}
function openIssueDividendsPopup(): void {
const popupId = "cmpy-mgmt-issue-dividends-popup";
createPopup(popupId, IssueDividendsPopup, {
popupId: popupId,
corp: props.corp,
});
}
// Render the buttons for when your Corporation has gone public
function PublicButtons(): React.ReactElement {
const corp = props.corp;
const sellSharesOnCd = corp.shareSaleCooldown > 0;
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
const sellSharesTooltip = sellSharesOnCd
? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown)
: "Sell your shares in the company. The money earned from selling your " +
"shares goes into your personal account, not the Corporation's. " +
"This is one of the only ways to profit from your business venture.";
const issueNewSharesOnCd = corp.issueNewSharesCooldown > 0;
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
const issueNewSharesTooltip = issueNewSharesOnCd
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
: "Issue new equity shares to raise capital.";
return (
<>
<Button
className={sellSharesClass}
display="inline-block"
onClick={openSellSharesPopup}
text="Sell Shares"
tooltip={sellSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openBuybackSharesPopup}
text="Buyback shares"
tooltip="Buy back shares you that previously issued or sold at market price."
/>
<br />
<Button
className={issueNewSharesClass}
display="inline-block"
onClick={openIssueNewSharesPopup}
text="Issue New Shares"
tooltip={issueNewSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openIssueDividendsPopup}
text="Issue Dividends"
tooltip="Manage the dividends that are paid out to shareholders (including yourself)"
/>
<br />
</>
);
}
// Render the UI for Corporation upgrades
function Upgrades(): React.ReactElement {
// Don't show upgrades
if (props.corp.divisions.length <= 0) {
return <h1>Unlock upgrades after creating your first division</h1>;
}
return (
<div className={"cmpy-mgmt-upgrade-container"}>
<h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1>
{Object.values(CorporationUnlockUpgrades)
.filter((upgrade: CorporationUnlockUpgrade) => props.corp.unlockUpgrades[upgrade[0]] === 0)
.map((upgrade: CorporationUnlockUpgrade) => (
<UnlockUpgrade
rerender={props.rerender}
player={props.player}
corp={props.corp}
upgradeData={upgrade}
key={upgrade[0]}
/>
))}
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
{props.corp.upgrades
.map((level: number, i: number) => CorporationUpgrades[i])
.map((upgrade: CorporationUpgrade) => (
<LevelableUpgrade
rerender={props.rerender}
player={props.player}
corp={props.corp}
upgrade={upgrade}
key={upgrade[0]}
/>
))}
</div>
);
}
return ( return (
<div> <div>
<p> <p>
Total Funds: <Money money={props.corp.funds.toNumber()} /> Total Funds: <Money money={corp.funds.toNumber()} />
<br /> <br />
Total Revenue: <Money money={props.corp.revenue.toNumber()} /> / s<br /> Total Revenue: <Money money={corp.revenue.toNumber()} /> / s<br />
Total Expenses: <Money money={props.corp.expenses.toNumber()} /> / s Total Expenses: <Money money={corp.expenses.toNumber()} /> / s
<br /> <br />
Total Profits: <Money money={profit} /> / s<br /> Total Profits: <Money money={profit} /> / s<br />
<DividendsStats /> <DividendsStats corp={corp} profit={profit} />
Publicly Traded: {props.corp.public ? "Yes" : "No"} Publicly Traded: {corp.public ? "Yes" : "No"}
<br /> <br />
Owned Stock Shares: {numeralWrapper.format(props.corp.numShares, "0.000a")} Owned Stock Shares: {numeralWrapper.format(corp.numShares, "0.000a")}
<br /> <br />
Stock Price: {props.corp.public ? <Money money={props.corp.sharePrice} /> : "N/A"} Stock Price: {corp.public ? <Money money={corp.sharePrice} /> : "N/A"}
<br /> <br />
</p> </p>
<p className="tooltip"> <p className="tooltip">
Total Stock Shares: {numeralWrapper.format(props.corp.totalShares, "0.000a")} Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")}
<span className="tooltiptext"> <span className="tooltiptext">
Outstanding Shares: {numeralWrapper.format(props.corp.issuedShares, "0.000a")} Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")}
<br /> <br />
Private Shares:{" "} Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")}
{numeralWrapper.format(props.corp.totalShares - props.corp.issuedShares - props.corp.numShares, "0.000a")}
</span> </span>
</p> </p>
<br /> <br />
<br /> <br />
<Mult name="Production Multiplier: " mult={props.corp.getProductionMultiplier()} /> <Mult name="Production Multiplier: " mult={corp.getProductionMultiplier()} />
<Mult name="Storage Multiplier: " mult={props.corp.getStorageMultiplier()} /> <Mult name="Storage Multiplier: " mult={corp.getStorageMultiplier()} />
<Mult name="Advertising Multiplier: " mult={props.corp.getAdvertisingMultiplier()} /> <Mult name="Advertising Multiplier: " mult={corp.getAdvertisingMultiplier()} />
<Mult name="Empl. Creativity Multiplier: " mult={props.corp.getEmployeeCreMultiplier()} /> <Mult name="Empl. Creativity Multiplier: " mult={corp.getEmployeeCreMultiplier()} />
<Mult name="Empl. Charisma Multiplier: " mult={props.corp.getEmployeeChaMultiplier()} /> <Mult name="Empl. Charisma Multiplier: " mult={corp.getEmployeeChaMultiplier()} />
<Mult name="Empl. Intelligence Multiplier: " mult={props.corp.getEmployeeIntMultiplier()} /> <Mult name="Empl. Intelligence Multiplier: " mult={corp.getEmployeeIntMultiplier()} />
<Mult name="Empl. Efficiency Multiplier: " mult={props.corp.getEmployeeEffMultiplier()} /> <Mult name="Empl. Efficiency Multiplier: " mult={corp.getEmployeeEffMultiplier()} />
<Mult name="Sales Multiplier: " mult={props.corp.getSalesMultiplier()} /> <Mult name="Sales Multiplier: " mult={corp.getSalesMultiplier()} />
<Mult name="Scientific Research Multiplier: " mult={props.corp.getScientificResearchMultiplier()} /> <Mult name="Scientific Research Multiplier: " mult={corp.getScientificResearchMultiplier()} />
<br /> <br />
<BonusTime /> <BonusTime corp={corp} />
<div> <div>
<Button <Button
className="a-link-button" className="a-link-button"
display="inline-block" display="inline-block"
onClick={() => props.corp.getStarterGuide(props.player)} onClick={() => corp.getStarterGuide(player)}
text="Getting Started Guide" text="Getting Started Guide"
tooltip={ tooltip={
"Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " + "Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " +
@ -358,11 +80,307 @@ export function Overview(props: IProps): React.ReactElement {
"provides some tips/pointers for helping you get started with managing it." "provides some tips/pointers for helping you get started with managing it."
} }
/> />
{props.corp.public ? <PublicButtons /> : <PrivateButtons />} {corp.public ? (
<BribeButton /> <PublicButtons corp={corp} player={player} rerender={rerender} />
) : (
<PrivateButtons corp={corp} player={player} rerender={rerender} />
)}
<BribeButton corp={corp} player={player} />
</div> </div>
<br /> <br />
<Upgrades /> <Upgrades corp={corp} player={player} rerender={rerender} />
</div> </div>
); );
} }
interface IPrivateButtonsProps {
corp: ICorporation;
player: IPlayer;
rerender: () => void;
}
// Render the buttons for when your Corporation is still private
function PrivateButtons({ corp, player, rerender }: IPrivateButtonsProps): React.ReactElement {
function openFindInvestorsPopup(): void {
const popupId = "cmpy-mgmt-find-investors-popup";
createPopup(popupId, FindInvestorsPopup, {
rerender,
player,
popupId,
corp: corp,
});
}
function openGoPublicPopup(): void {
const popupId = "cmpy-mgmt-go-public-popup";
createPopup(popupId, GoPublicPopup, {
rerender,
player,
popupId,
corp: corp,
});
}
const fundingAvailable = corp.fundingRound < 4;
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
const findInvestorsTooltip = fundingAvailable
? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company"
: undefined;
return (
<>
<Button
className={findInvestorsClassName}
onClick={openFindInvestorsPopup}
text="Find Investors"
tooltip={findInvestorsTooltip}
display="inline-block"
/>
<Button
className="std-button"
onClick={openGoPublicPopup}
display="inline-block"
text="Go Public"
tooltip={
"Become a publicly traded and owned entity. Going public " +
"involves issuing shares for an IPO. Once you are a public " +
"company, your shares will be traded on the stock market."
}
/>
<br />
</>
);
}
interface IUpgradeProps {
corp: ICorporation;
player: IPlayer;
rerender: () => void;
}
// Render the UI for Corporation upgrades
function Upgrades({ corp, player, rerender }: IUpgradeProps): React.ReactElement {
// Don't show upgrades
if (corp.divisions.length <= 0) {
return <h1>Unlock upgrades after creating your first division</h1>;
}
return (
<div className={"cmpy-mgmt-upgrade-container"}>
<h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1>
{Object.values(CorporationUnlockUpgrades)
.filter((upgrade: CorporationUnlockUpgrade) => corp.unlockUpgrades[upgrade[0]] === 0)
.map((upgrade: CorporationUnlockUpgrade) => (
<UnlockUpgrade rerender={rerender} player={player} corp={corp} upgradeData={upgrade} key={upgrade[0]} />
))}
<h1 className={"cmpy-mgmt-upgrade-header"}> Upgrades </h1>
{corp.upgrades
.map((level: number, i: number) => CorporationUpgrades[i])
.map((upgrade: CorporationUpgrade) => (
<LevelableUpgrade rerender={rerender} player={player} corp={corp} upgrade={upgrade} key={upgrade[0]} />
))}
</div>
);
}
interface IPublicButtonsProps {
corp: ICorporation;
player: IPlayer;
rerender: () => void;
}
// Render the buttons for when your Corporation has gone public
function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.ReactElement {
const sellSharesOnCd = corp.shareSaleCooldown > 0;
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
const sellSharesTooltip = sellSharesOnCd
? "Cannot sell shares for " + corp.convertCooldownToString(corp.shareSaleCooldown)
: "Sell your shares in the company. The money earned from selling your " +
"shares goes into your personal account, not the Corporation's. " +
"This is one of the only ways to profit from your business venture.";
const issueNewSharesOnCd = corp.issueNewSharesCooldown > 0;
const issueNewSharesClass = issueNewSharesOnCd ? "a-link-button-inactive" : "std-button";
const issueNewSharesTooltip = issueNewSharesOnCd
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
: "Issue new equity shares to raise capital.";
function openSellSharesPopup(): void {
const popupId = "cmpy-mgmt-sell-shares-popup";
createPopup(popupId, SellSharesPopup, {
corp: corp,
player,
popupId,
rerender,
});
}
function openBuybackSharesPopup(): void {
const popupId = "corp-buyback-shares-popup";
createPopup(popupId, BuybackSharesPopup, {
rerender,
player,
popupId,
corp: corp,
});
}
function openIssueNewSharesPopup(): void {
const popupId = "cmpy-mgmt-issue-new-shares-popup";
createPopup(popupId, IssueNewSharesPopup, {
popupId,
corp: corp,
});
}
function openIssueDividendsPopup(): void {
const popupId = "cmpy-mgmt-issue-dividends-popup";
createPopup(popupId, IssueDividendsPopup, {
popupId,
corp: corp,
});
}
return (
<>
<Button
className={sellSharesClass}
display="inline-block"
onClick={openSellSharesPopup}
text="Sell Shares"
tooltip={sellSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openBuybackSharesPopup}
text="Buyback shares"
tooltip="Buy back shares you that previously issued or sold at market price."
/>
<br />
<Button
className={issueNewSharesClass}
display="inline-block"
onClick={openIssueNewSharesPopup}
text="Issue New Shares"
tooltip={issueNewSharesTooltip}
/>
<Button
className="std-button"
display="inline-block"
onClick={openIssueDividendsPopup}
text="Issue Dividends"
tooltip="Manage the dividends that are paid out to shareholders (including yourself)"
/>
<br />
</>
);
}
// Generic Function for Creating a button
interface ICreateButtonProps {
text: string;
className?: string;
display?: string;
tooltip?: string;
onClick?: (event: React.MouseEvent) => void;
}
function Button({ className = "std-button", text, display, tooltip, onClick }: ICreateButtonProps): React.ReactElement {
const hasTooltip = tooltip != null;
if (hasTooltip) className += " tooltip";
return (
<button className={className} onClick={onClick} style={{ display: display ? display : "block" }}>
{text}
{hasTooltip && <span className={"tooltiptext"}>{tooltip}</span>}
</button>
);
}
interface IBribeButtonProps {
player: IPlayer;
corp: ICorporation;
}
function BribeButton({ player, corp }: IBribeButtonProps): React.ReactElement {
function openBribeFactionPopup(): void {
const popupId = "corp-bribe-popup";
createPopup(popupId, BribeFactionPopup, {
player,
popupId,
corp: corp,
});
}
const canBribe = corp.determineValuation() >= CorporationConstants.BribeThreshold || true;
const bribeFactionsClass = canBribe ? "a-link-button" : "a-link-button-inactive";
return (
<Button
className={bribeFactionsClass}
display="inline-block"
onClick={openBribeFactionPopup}
text="Bribe Factions"
tooltip={
canBribe
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
: "Your Corporation is not powerful enough to bribe Faction leaders"
}
/>
);
}
interface IDividendsStatsProps {
corp: ICorporation;
profit: number;
}
function DividendsStats({ corp, profit }: IDividendsStatsProps): React.ReactElement {
if (corp.dividendPercentage <= 0 || profit <= 0) return <></>;
const totalDividends = (corp.dividendPercentage / 100) * profit;
const retainedEarnings = profit - totalDividends;
const dividendsPerShare = totalDividends / corp.totalShares;
const playerEarnings = corp.numShares * dividendsPerShare;
return (
<>
Retained Profits (after dividends): <Money money={retainedEarnings} /> / s
<br />
<br />
Dividend Percentage: {numeralWrapper.format(corp.dividendPercentage / 100, "0%")}
<br />
Dividends per share: <Money money={dividendsPerShare} /> / s<br />
Your earnings as a shareholder (Pre-Tax): <Money money={playerEarnings} /> / s<br />
Dividend Tax Rate: {corp.dividendTaxPercentage}%<br />
Your earnings as a shareholder (Post-Tax):{" "}
<Money money={playerEarnings * (1 - corp.dividendTaxPercentage / 100)} /> / s<br />
<br />
</>
);
}
interface IMultProps {
name: string;
mult: number;
}
function Mult({ name, mult }: IMultProps): React.ReactElement {
if (mult <= 1) return <></>;
return (
<p>
{name}
{numeralWrapper.format(mult, "0.000")}
<br />
</p>
);
}
interface IBonusTimeProps {
corp: ICorporation;
}
// Returns a string with general information about Corporation
function BonusTime({ corp }: IBonusTimeProps): React.ReactElement {
const storedTime = corp.storedCycles * CONSTANTS.MilliPerCycle;
if (storedTime <= 15000) return <></>;
return (
<p>
Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}
<br />
<br />
</p>
);
}

@ -34,9 +34,9 @@ export function UnlockUpgrade(props: IProps): React.ReactElement {
} }
return ( return (
<div className={"cmpy-mgmt-upgrade-div tooltip"} style={{ width: "45%" }} onClick={onClick}> <button className={"cmpy-mgmt-upgrade-div tooltip"} style={{ width: "45%" }} onClick={onClick}>
{text} {text}
<span className={"tooltiptext"}>{tooltip}</span> <span className={"tooltiptext"}>{tooltip}</span>
</div> </button>
); );
} }

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import { AllServers } from "../Server/AllServers"; import { AllServers } from "../Server/AllServers";
import { Accordion } from "../ui/React/Accordion"; import { BBAccordion } from "../ui/React/Accordion";
import { numeralWrapper } from "../ui/numeralFormat"; import { numeralWrapper } from "../ui/numeralFormat";
interface IServerProps { interface IServerProps {
@ -40,7 +40,7 @@ export function ServerAccordion(props: IServerProps): React.ReactElement {
files.sort((a: File, b: File): number => b.size - a.size); files.sort((a: File, b: File): number => b.size - a.size);
return ( return (
<Accordion <BBAccordion
headerContent={ headerContent={
<> <>
{server.hostname} ({numeralWrapper.formatBigNumber(totalSize)}b) {server.hostname} ({numeralWrapper.formatBigNumber(totalSize)}b)

@ -4,7 +4,7 @@
import React from "react"; import React from "react";
import { Gang } from "../Gang"; import { Gang } from "../Gang";
import { GangMember } from "../GangMember"; import { GangMember } from "../GangMember";
import { Accordion } from "../../ui/React/Accordion"; import { BBAccordion } from "../../ui/React/Accordion";
import { GangMemberAccordionContent } from "./GangMemberAccordionContent"; import { GangMemberAccordionContent } from "./GangMemberAccordionContent";
interface IProps { interface IProps {
@ -14,7 +14,7 @@ interface IProps {
export function GangMemberAccordion(props: IProps): React.ReactElement { export function GangMemberAccordion(props: IProps): React.ReactElement {
return ( return (
<Accordion <BBAccordion
panelInitiallyOpened={true} panelInitiallyOpened={true}
headerContent={<>{props.member.name}</>} headerContent={<>{props.member.name}</>}
panelContent={<GangMemberAccordionContent gang={props.gang} member={props.member} />} panelContent={<GangMemberAccordionContent gang={props.gang} member={props.member} />}

@ -60,16 +60,18 @@ function ListWorldMap(props: IProps): React.ReactElement {
</p> </p>
{Object.values(CityName) {Object.values(CityName)
.filter((city: string) => city != props.p.city) .filter((city: string) => city != props.p.city)
.map((city: string) => ( .map((city: string) => {
<StdButton const match = Object.entries(CityName).find(([key, value]) => value === city);
key={city} if (match === undefined) throw new Error(`could not find key for city '${city}'`);
onClick={() => return (
createTravelPopup(props.p, city, () => props.travel(CityName[city as keyof typeof CityName])) <StdButton
} key={city}
style={{ display: "block" }} onClick={() => createTravelPopup(props.p, city, () => props.travel(match[1]))}
text={`Travel to ${city}`} style={{ display: "block" }}
/> text={`Travel to ${city}`}
))} />
);
})}
</div> </div>
); );
} }

@ -1,11 +0,0 @@
export function unknownBladeburnerActionErrorMessage(functionName, actionType, actionName) {
return (
`ERROR: bladeburner.${functionName}() failed due to an invalid action specified. ` +
`Type: ${actionType}, Name: ${actionName}. Note that for contracts and operations, the ` +
`name of the operation is case-sensitive.`
);
}
export function unknownBladeburnerExceptionMessage(functionName, err) {
return `bladeburner.${functionName}() failed with exception: ` + err;
}

@ -174,6 +174,9 @@ export function prestigeAugmentation() {
this.hacknetNodes.length = 0; this.hacknetNodes.length = 0;
this.hashManager.prestige(); this.hashManager.prestige();
// Reset player multipliers
this.resetMultipliers();
// Re-calculate skills and reset HP // Re-calculate skills and reset HP
this.updateSkillLevels(); this.updateSkillLevels();
this.hp = this.max_hp; this.hp = this.max_hp;

@ -16,7 +16,7 @@ import ReactDOM from "react-dom";
let redPillFlag = false; let redPillFlag = false;
function hackWorldDaemon(currentNodeNumber, flume = false, quick = false) { function hackWorldDaemon(currentNodeNumber, flume = false, quick = false) {
// Clear the screen // Clear the screen
const container = document.getElementById("red-pill-content"); const container = document.getElementById("red-pill-container");
ReactDOM.unmountComponentAtNode(container); ReactDOM.unmountComponentAtNode(container);
Engine.loadRedPillContent(); Engine.loadRedPillContent();
ReactDOM.render( ReactDOM.render(
@ -85,7 +85,7 @@ function enterBitNode(flume, destroyedBitNode, newBitNode) {
Player.intelligence = 1; Player.intelligence = 1;
} }
redPillFlag = false; redPillFlag = false;
const container = document.getElementById("red-pill-content"); const container = document.getElementById("red-pill-container");
ReactDOM.unmountComponentAtNode(container); ReactDOM.unmountComponentAtNode(container);
// Set new Bit Node // Set new Bit Node

@ -18,7 +18,7 @@ import { PositionTypes } from "../data/PositionTypes";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { Accordion } from "../../ui/React/Accordion"; import { BBAccordion } from "../../ui/React/Accordion";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { createPopup } from "../../ui/React/createPopup"; import { createPopup } from "../../ui/React/createPopup";
@ -157,7 +157,8 @@ export class StockTicker extends React.Component<IProps, IState> {
createPopup(popupId, PlaceOrderPopup, { createPopup(popupId, PlaceOrderPopup, {
text: "Enter the price for your Limit Order", text: "Enter the price for your Limit Order",
placeText: "Place Buy Limit Order", placeText: "Place Buy Limit Order",
place: (price: number) => this.props.placeOrder(this.props.stock, shares, price, OrderTypes.LimitBuy, this.state.position), place: (price: number) =>
this.props.placeOrder(this.props.stock, shares, price, OrderTypes.LimitBuy, this.state.position),
popupId: popupId, popupId: popupId,
}); });
break; break;
@ -167,7 +168,8 @@ export class StockTicker extends React.Component<IProps, IState> {
createPopup(popupId, PlaceOrderPopup, { createPopup(popupId, PlaceOrderPopup, {
text: "Enter the price for your Stop Order", text: "Enter the price for your Stop Order",
placeText: "Place Buy Stop Order", placeText: "Place Buy Stop Order",
place: (price: number) => this.props.placeOrder(this.props.stock, shares, price, OrderTypes.StopBuy, this.state.position), place: (price: number) =>
this.props.placeOrder(this.props.stock, shares, price, OrderTypes.StopBuy, this.state.position),
popupId: popupId, popupId: popupId,
}); });
break; break;
@ -279,7 +281,8 @@ export class StockTicker extends React.Component<IProps, IState> {
createPopup(popupId, PlaceOrderPopup, { createPopup(popupId, PlaceOrderPopup, {
text: "Enter the price for your Limit Order", text: "Enter the price for your Limit Order",
placeText: "Place Sell Limit Order", placeText: "Place Sell Limit Order",
place: (price: number) => this.props.placeOrder(this.props.stock, shares, price, OrderTypes.LimitSell, this.state.position), place: (price: number) =>
this.props.placeOrder(this.props.stock, shares, price, OrderTypes.LimitSell, this.state.position),
popupId: popupId, popupId: popupId,
}); });
break; break;
@ -289,7 +292,8 @@ export class StockTicker extends React.Component<IProps, IState> {
createPopup(popupId, PlaceOrderPopup, { createPopup(popupId, PlaceOrderPopup, {
text: "Enter the price for your Stop Order", text: "Enter the price for your Stop Order",
placeText: "Place Sell Stop Order", placeText: "Place Sell Stop Order",
place: (price: number) => this.props.placeOrder(this.props.stock, shares, price, OrderTypes.StopSell, this.state.position), place: (price: number) =>
this.props.placeOrder(this.props.stock, shares, price, OrderTypes.StopSell, this.state.position),
popupId: popupId, popupId: popupId,
}); });
break; break;
@ -332,7 +336,7 @@ export class StockTicker extends React.Component<IProps, IState> {
render(): React.ReactNode { render(): React.ReactNode {
return ( return (
<li> <li>
<Accordion <BBAccordion
headerContent={<StockTickerHeaderText p={this.props.p} stock={this.props.stock} />} headerContent={<StockTickerHeaderText p={this.props.p} stock={this.props.stock} />}
panelContent={ panelContent={
<div> <div>

@ -265,7 +265,6 @@ const Engine = {
routing.navigateTo(Page.WorkInProgress); routing.navigateTo(Page.WorkInProgress);
}, },
// TODO reactify
loadRedPillContent: function () { loadRedPillContent: function () {
Engine.hideAllContent(); Engine.hideAllContent();
const mainMenu = document.getElementById("mainmenu-container"); const mainMenu = document.getElementById("mainmenu-container");

@ -67,27 +67,6 @@
<div id="generic-react-container"></div> <div id="generic-react-container"></div>
</div> </div>
<div id="infiltration-container" class="generic-fullscreen-container"></div> <div id="infiltration-container" class="generic-fullscreen-container"></div>
<!-- Generic Yes/No Pop Up box -->
<div id="yes-no-box-container" class="popup-box-container">
<div id="yes-no-box-content" class="popup-box-content">
<p id="yes-no-box-text"></p>
<button id="yes-no-box-yes" class="popup-box-button">Yes</button>
<button id="yes-no-box-no" class="popup-box-button">No</button>
</div>
</div>
<!-- Generic yes/no pop up box with text entry field -->
<div id="yes-no-text-input-box-container" class="popup-box-container">
<div id="yes-no-text-input-box-content" class="popup-box-content">
<p id="yes-no-text-input-box-text"></p>
<input type="text" id="yes-no-text-input-box-input" pattern="[a-zA-Z0-9-_]" maxlength="30" />
<button id="yes-no-text-input-box-yes" class="popup-box-button">Yes</button>
<button id="yes-no-text-input-box-no" class="popup-box-button">No</button>
</div>
</div>
<!-- Mission container -->
<div id="mission-container" class="generic-fullscreen-container"></div> <div id="mission-container" class="generic-fullscreen-container"></div>
<!-- Work in progress screen --> <!-- Work in progress screen -->
@ -101,9 +80,7 @@
</div> </div>
<!-- Red Pill Container --> <!-- Red Pill Container -->
<div id="red-pill-container" class="generic-fullscreen-container"> <div id="red-pill-container" class="generic-fullscreen-container"></div>
<div id="red-pill-content" class="generic-fullscreen-container-scroll"></div>
</div>
<!-- Cinematic Text Container --> <!-- Cinematic Text Container -->
<div id="cinematic-text-container" class="generic-fullscreen-container"></div> <div id="cinematic-text-container" class="generic-fullscreen-container"></div>

@ -4,7 +4,7 @@
*/ */
import * as React from "react"; import * as React from "react";
import { Accordion } from "../React/Accordion"; import { BBAccordion } from "../React/Accordion";
import { ServerAccordionContent } from "./ServerAccordionContent"; import { ServerAccordionContent } from "./ServerAccordionContent";
import { BaseServer } from "../../Server/BaseServer"; import { BaseServer } from "../../Server/BaseServer";
@ -34,7 +34,7 @@ export function ServerAccordion(props: IProps): React.ReactElement {
const headerTxt = `${paddedName} ${createProgressBarText(barOptions)}`; const headerTxt = `${paddedName} ${createProgressBarText(barOptions)}`;
return ( return (
<Accordion <BBAccordion
headerContent={<pre>{headerTxt}</pre>} headerContent={<pre>{headerTxt}</pre>}
panelContent={<ServerAccordionContent workerScripts={props.workerScripts} />} panelContent={<ServerAccordionContent workerScripts={props.workerScripts} />}
/> />

@ -6,7 +6,7 @@ import * as React from "react";
import { numeralWrapper } from "../numeralFormat"; import { numeralWrapper } from "../numeralFormat";
import { Accordion } from "../React/Accordion"; import { BBAccordion } from "../React/Accordion";
import { AccordionButton } from "../React/AccordionButton"; import { AccordionButton } from "../React/AccordionButton";
import { killWorkerScript } from "../../Netscript/killWorkerScript"; import { killWorkerScript } from "../../Netscript/killWorkerScript";
@ -41,7 +41,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
const offlineEps = scriptRef.offlineExpGained / scriptRef.offlineRunningTime; const offlineEps = scriptRef.offlineExpGained / scriptRef.offlineRunningTime;
return ( return (
<Accordion <BBAccordion
headerClass="active-scripts-script-header" headerClass="active-scripts-script-header"
headerContent={<>{props.workerScript.name}</>} headerContent={<>{props.workerScript.name}</>}
panelClass="active-scripts-script-panel" panelClass="active-scripts-script-panel"

@ -16,7 +16,7 @@ type IState = {
panelOpened: boolean; panelOpened: boolean;
}; };
export class Accordion extends React.Component<IProps, IState> { export class BBAccordion extends React.Component<IProps, IState> {
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);

@ -6,7 +6,7 @@
*/ */
import * as React from "react"; import * as React from "react";
import { Accordion } from "./Accordion"; import { BBAccordion } from "./Accordion";
import { Augmentation } from "../../Augmentation/Augmentation"; import { Augmentation } from "../../Augmentation/Augmentation";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
@ -26,7 +26,7 @@ export function AugmentationAccordion(props: IProps): React.ReactElement {
if (typeof props.aug.info === "string") { if (typeof props.aug.info === "string") {
return ( return (
<Accordion <BBAccordion
headerContent={<>{displayName}</>} headerContent={<>{displayName}</>}
panelContent={ panelContent={
<p> <p>
@ -41,7 +41,7 @@ export function AugmentationAccordion(props: IProps): React.ReactElement {
} }
return ( return (
<Accordion <BBAccordion
headerContent={<>{displayName}</>} headerContent={<>{displayName}</>}
panelContent={ panelContent={
<p> <p>

47
src/ui/React/Button.tsx Normal file

@ -0,0 +1,47 @@
/**
* Wrapper around material-ui's Button component that styles it with
* Bitburner's UI theme
*/
import React from "react";
import { Button as MuiButton, ButtonProps, makeStyles } from "@material-ui/core";
import { colors } from "./Theme";
const useStyles = makeStyles({
// Tries to emulate StdButton in buttons.scss
root: {
backgroundColor: "#333",
border: "1px solid #000",
color: colors.primary,
margin: "5px",
padding: "3px 5px",
"&:hover": {
backgroundColor: "#000",
},
borderRadius: 0,
},
textPrimary: {
color: "rgb( 144, 202, 249)",
},
textSecondary: {
color: "rgb(244, 143, 177)",
},
disabled: {
backgroundColor: "#333",
color: "#fff",
cursor: "default",
},
});
export const Button: React.FC<ButtonProps> = (props: ButtonProps) => {
return (
<MuiButton
{...props}
classes={{
...useStyles(),
...props.classes,
}}
/>
);
};

@ -5,7 +5,6 @@
import React from "react"; import React from "react";
import { Button, ButtonProps, makeStyles } from "@material-ui/core"; import { Button, ButtonProps, makeStyles } from "@material-ui/core";
const useStyles = makeStyles({ const useStyles = makeStyles({
// Tries to emulate StdButton in buttons.scss // Tries to emulate StdButton in buttons.scss
root: { root: {
@ -17,6 +16,8 @@ const useStyles = makeStyles({
"&:hover": { "&:hover": {
backgroundColor: "#666", backgroundColor: "#666",
}, },
borderRadius: 0,
}, },
textPrimary: { textPrimary: {
color: "rgb( 144, 202, 249)", color: "rgb( 144, 202, 249)",

337
src/ui/React/Options.tsx Normal file

@ -0,0 +1,337 @@
import React from "react";
interface IProps {}
export function Options(props: IProps): React.ReactElement {
return (
<>
<h1>Game Options</h1>
</>
);
/*
<h1>Game Options</h1>
<br />
<div id="game-options-left-panel">
<!-- Netscript execution time -->
<fieldset>
<label for="settingsNSExecTimeRangeVal" class="tooltip"
>Netscript exec time:&nbsp;
<span class="tooltiptext">
The minimum number of milliseconds it takes to execute an operation in Netscript. Setting this too low
can result in poor performance if you have many scripts running. The default value is 25ms.
</span>
</label>
<input
class="optionRange"
type="range"
max="100"
min="10"
step="1"
name="settingsNSExecTimeRangeVal"
id="settingsNSExecTimeRangeVal"
value="25"
/>
<em id="settingsNSExecTimeRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Log capacity -->
<fieldset>
<label for="settingsNSLogRangeVal" class="tooltip"
>Netscript log size:&nbsp;&nbsp;
<span class="tooltiptext">
The maximum number of lines a script's logs can hold. Setting this too high can cause the game to use
a lot of memory if you have many scripts running. The default value is 50.
</span>
</label>
<input
class="optionRange"
type="range"
max="100"
min="20"
step="1"
name="settingsNSLogRangeVal"
id="settingsNSLogRangeVal"
value="50"
/>
<em id="settingsNSLogRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Port capacity -->
<fieldset>
<label for="settingsNSPortRangeVal" class="tooltip"
>Netscript port size:&nbsp;
<span class="tooltiptext">
The maximum number of entries that can be written to a port using Netscript's write() function.
Setting this too high can cause the game to use a lot of memory. The default value is 50.
</span>
</label>
<input
class="optionRange"
type="range"
max="100"
min="20"
step="1"
name="settingsNSPortRangeVal"
id="settingsNSPortRangeVal"
value="50"
/>
<em id="settingsNSPortRangeValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Autosave Interval -->
<fieldset>
<label for="settingsAutosaveIntervalVal" class="tooltip"
>Autosave Interval:&nbsp;&nbsp;&nbsp;
<span class="tooltiptext">
The time (in seconds) between each autosave. Set to 0 to disable autosave.
</span>
</label>
<input
class="optionRange"
type="range"
max="600"
min="0"
step="1"
name="settingsAutosaveIntervalVal"
id="settingsAutosaveIntervalVal"
value="60"
/>
<em id="settingsAutosaveIntervalValLabel" style="font-style: normal"></em>
</fieldset>
<!-- Suppress messages -->
<fieldset>
<label for="settingsSuppressMessages" class="tooltip"
>Suppress Messages:
<span class="tooltiptext">
If this is set, then any messages you receive will not appear as popups on the screen. They will still
get sent to your home computer as '.msg' files and can be viewed with the 'cat' Terminal command.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressMessages"
id="settingsSuppressMessages"
/>
</fieldset>
<!-- Suppress faction invites -->
<fieldset>
<label for="settingsSuppressFactionInvites" class="tooltip"
>Suppress Faction Invites:
<span class="tooltiptexthigh">
If this is set, then any faction invites you receive will not appear as popups on the screen. Your
outstanding faction invites can be viewed in the 'Factions' page.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressFactionInvites"
id="settingsSuppressFactionInvites"
/>
</fieldset>
<!-- Suppress travel confirmation -->
<fieldset>
<label for="settingsSuppressTravelConfirmation" class="tooltip"
>Suppress Travel Confirmation:
<span class="tooltiptexthigh">
If this is set, the confirmation message before traveling will not show up. You will automatically be
deducted the travel cost as soon as you click.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressTravelConfirmation"
id="settingsSuppressTravelConfirmation"
/>
</fieldset>
<!-- Suppress buy aug confirmation -->
<fieldset>
<label for="settingsSuppressBuyAugmentationConfirmation" class="tooltip"
>Suppress buy augmentation confirmation:
<span class="tooltiptexthigh">
If this is set, the confirmation message before buying augmentation will not show up.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBuyAugmentationConfirmation"
id="settingsSuppressBuyAugmentationConfirmation"
/>
</fieldset>
<!-- Hospitalization Popup -->
<fieldset>
<label for="settingsSuppressHospitalizationPopup" class="tooltip"
>Suppress Hospitalization popup:
<span class="tooltiptexthigh">
If this is set, a popup message will no longer be shown when you are hospitalized after taking too
much damage.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressHospitalizationPopup"
id="settingsSuppressHospitalizationPopup"
/>
</fieldset>
<!-- Suppress Bladeburner popups -->
<fieldset>
<label for="settingsSuppressBladeburnerPopup" class="tooltip"
>Suppress Bladeburner Popup:
<span class="tooltiptext">
If this is set, then having your Bladeburner actions interrupted by being busy with something else
will not display a popup message.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsSuppressBladeburnerPopup"
id="settingsSuppressBladeburnerPopup"
/>
</fieldset>
<!-- Disable Terminal and Navigation Shortcuts -->
<fieldset>
<label for="settingsDisableHotkeys" class="tooltip"
>Disable Hotkeys:
<span class="tooltiptexthigh">
If this is set, then most hotkeys (keyboard shortcuts) in the game are disabled. This includes
Terminal commands, hotkeys to navigate between different parts of the game, and the "Save and Close
(Ctrl + b)" hotkey in the Text Editor.
</span>
</label>
<input class="optionCheckbox" type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys" />
</fieldset>
<!-- View city as list of buttons instead of ASCII art. -->
<fieldset>
<label for="settingsDisableASCIIArt" class="tooltip"
>Disable ASCII art:
<span class="tooltiptexthigh"> If this is set all ASCII art will be disabled. </span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsDisableASCIIArt"
id="settingsDisableASCIIArt"
/>
</fieldset>
<!-- Disable text effects such as corruption. -->
<fieldset>
<label for="settingsDisableTextEffects" class="tooltip"
>Disable Text Effects:
<span class="tooltiptexthigh">
If this is set, text effects will not be displayed. This can help if text is difficult to read in
certain areas.
</span>
</label>
<input
class="optionCheckbox"
type="checkbox"
name="settingsDisableTextEffects"
id="settingsDisableTextEffects"
/>
</fieldset>
<!-- Locale for displaying numbers -->
<fieldset>
<label for="settingsLocale" class="tooltip"
>Locale:
<span class="tooltiptexthigh"> Sets the locale for displaying numbers. Defaults to 'en' </span>
</label>
<select name="settingsLocale" id="settingsLocale" class="dropdown">
<option value="en">en</option>
<option value="bg">bg</option>
<option value="cs">cs</option>
<option value="da-dk">da-dk</option>
<option value="de">de</option>
<option value="en-au">en-au</option>
<option value="en-gb">en-gb</option>
<option value="es">es</option>
<option value="fr">fr</option>
<option value="hu">hu</option>
<option value="it">it</option>
<option value="lv">lv</option>
<option value="no">no</option>
<option value="pl">pl</option>
<option value="ru">ru</option>
</select>
</fieldset>
<!-- Donate button -->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick" />
<input
type="hidden"
name="encrypted"
value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYA2Y2VGE75oWct89z//G2YEJKmzx0uDTXNrpje9ThxmUnBLFZCY+I11Pors7lGRvFqo5okwnu41CfYMPHDxpAgyYyQndMX9pWUX0gLfBMm2BaHwsNBCwt34WmpQqj7TGsQ+aw9NbmkxiJltGnOa+6/gy10mPZAA3HxiieLeCKkGgDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQI72F1YSzHUd2AgaDMekHU3AKT93Ey9wkB3486bV+ngFSD6VOHrPweH9QATsp+PMe9QM9vmq+s2bGtTbZaYrFqM3M97SnQ0l7IQ5yuOzdZhRdfysu5uJ8dnuHUzq4gLSzqMnZ6/3c+PoHB8AS1nYHUVL4U0+ogZsO1s97IAQyfck9SaoFlxVtqQhkb8752MkQJJvGu3ZQSQGcVC4hFDPk8prXqyq4BU/k/EliwoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcwNzI1MDExODE2WjAjBgkqhkiG9w0BCQQxFgQUNo8efiZ7sk7nwKM/6B6Z7sU8hIIwDQYJKoZIhvcNAQEBBQAEgYB+JB4vZ/r48815/1HF/xK3+rOx7bPz3kAXmbhW/mkoF4OUbzqMeljvDIA9q/BDdlCLtxFOw9XlftTzv0eZCW/uCIiwu5wTzPIfPY1SI8WHe4cJbP2f2EYxIVs8D7OSirbW4yVa0+gACaLLj0rzIzNN8P/5PxgB03D+jwkcJABqng==-----END PKCS7-----
"
/>
<input
type="image"
src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif"
border="0"
name="submit"
alt="PayPal - The safer, easier way to pay online!"
/>
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>
</div>
<div id="game-options-right-panel">
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/changelog.html" target="_blank">
Changelog
</a>
<a class="a-link-button" href="https://bitburner.readthedocs.io/en/latest/index.html" target="_blank"
>Documentation</a
>
<a class="a-link-button" href="https://discord.gg/TFc3hKD" target="_blank">Discord</a>
<a class="a-link-button" href="https://www.reddit.com/r/bitburner" target="_blank">Subreddit</a>
<button id="save-game-link" class="a-link-button">Save Game</button>
<button id="delete-game-link" class="a-link-button">Delete Game</button>
<button id="export-game-link" class="a-link-button">Export Game</button>
<input type="file" id="import-game-file-selector" name="file" />
<button id="import-game-link" class="a-link-button">Import Game</button>
<button id="copy-save-to-clipboard-link" class="std-button">Copy Save data to Clipboard</button>
<button id="debug-delete-scripts-link" class="a-link-button tooltip">
Force kill all active scripts
<span class="tooltiptextleft">
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the
game. After using this, save the game and then reload the page. This is different then normal kill in
that normal kill will tell the script to shut down while force kill just removes the references to it
(and it should crash on it's own). This will not remove the files on your computer. Just forcefully kill
all running instance of all scripts.
</span>
</button>
<button id="debug-soft-reset" class="a-link-button tooltip">
Soft Reset
<span class="tooltiptextleft">
Perform a soft reset. Resets everything as if you had just purchased an Augmentation.
</span>
</button>
<button id="debug-files" class="a-link-button tooltip">
Diagnose files
<span class="tooltiptextleft">
If your save file is extremely big you can use this button to view a map of all the files on every
server. Be careful there might be spoilers.
</span>
</button>
</div>
*/
}

36
src/ui/React/Select.tsx Normal file

@ -0,0 +1,36 @@
/**
* Wrapper around material-ui's Button component that styles it with
* Bitburner's UI theme
*/
import React from "react";
import { Select as MuiSelect, SelectProps, makeStyles } from "@material-ui/core";
import { colors } from "./Theme";
const useStyles = makeStyles({
// Tries to emulate StdButton in buttons.scss
root: {
backgroundColor: "#222",
color: colors.primarydark,
margin: "5px",
padding: "3px 5px",
"&:hover": {
backgroundColor: "#222",
},
borderRadius: 0,
},
});
export const Select: React.FC<SelectProps> = (props: SelectProps) => {
return (
<MuiSelect
native
{...props}
classes={{
...useStyles(),
...props.classes,
}}
/>
);
};

@ -6,7 +6,7 @@
*/ */
import * as React from "react"; import * as React from "react";
import { Accordion } from "./Accordion"; import { BBAccordion } from "./Accordion";
import { SourceFile } from "../../SourceFile/SourceFile"; import { SourceFile } from "../../SourceFile/SourceFile";
@ -19,7 +19,7 @@ export function SourceFileAccordion(props: IProps): React.ReactElement {
const maxLevel = props.sf.n === 12 ? "∞" : "3"; const maxLevel = props.sf.n === 12 ? "∞" : "3";
return ( return (
<Accordion <BBAccordion
headerContent={ headerContent={
<> <>
{props.sf.name} {props.sf.name}

@ -0,0 +1,56 @@
/**
* Wrapper around material-ui's Button component that styles it with
* Bitburner's UI colors
*/
import React from "react";
import { TextField as MuiTF, TextFieldProps, makeStyles } from "@material-ui/core";
import { colors } from "./Theme";
const useStyles = makeStyles({
// Tries to emulate StdButton in buttons.scss
root: {
backgroundColor: "#222",
color: "white",
borderRadius: 0,
"& .MuiInputBase-input": {
color: colors.primary, // Text color
},
"& .MuiInputBase-input::placeholder::before": {
color: colors.primarydarker,
userSelect: "none",
},
"& .MuiInput-underline:before": {
borderBottomColor: colors.primarydarker,
},
"& .MuiInput-underline:hover:before": {
borderBottomColor: colors.primarydark,
},
"& .MuiInput-underline:after": {
borderBottomColor: colors.primary,
},
"& .MuiInputLabel-root::before": {
color: colors.primarydark,
},
"& .MuiInputLabel-root": {
// The little label on the top-right
color: colors.primarydark, // unfocused
userSelect: "none",
"&.Mui-focused": {
color: colors.primary, // focused
},
},
},
});
export const TextField: React.FC<TextFieldProps> = (props: TextFieldProps) => {
return (
<MuiTF
{...props}
classes={{
...useStyles(),
...props.classes,
}}
/>
);
};

32
src/ui/React/Theme.tsx Normal file

@ -0,0 +1,32 @@
import React from "react";
import { createMuiTheme } from "@material-ui/core/styles";
import { ThemeProvider } from "@material-ui/core/styles";
export const colors = {
primary: "#0f0",
primarydark: "#090",
primarydarker: "#030",
};
export const theme = createMuiTheme({
palette: {
primary: {
main: colors.primary,
dark: colors.primarydark,
},
},
typography: {
button: {
textTransform: "none",
},
},
});
interface IProps {
children: JSX.Element[] | JSX.Element;
}
export const Theme = ({ children }: IProps): React.ReactElement => (
<ThemeProvider theme={theme}>{children}</ThemeProvider>
);