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,128 +27,100 @@ interface IProps {
player: IPlayer; player: IPlayer;
rerender: () => void; rerender: () => void;
} }
export function Overview({ corp, player, rerender }: IProps): React.ReactElement {
const profit: number = corp.revenue.minus(corp.expenses).toNumber();
export function Overview(props: IProps): React.ReactElement {
// 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 ( return (
<div>
<p> <p>
{props.name} Total Funds: <Money money={corp.funds.toNumber()} />
{numeralWrapper.format(props.mult, "0.000")} <br />
Total Revenue: <Money money={corp.revenue.toNumber()} /> / s<br />
Total Expenses: <Money money={corp.expenses.toNumber()} /> / s
<br />
Total Profits: <Money money={profit} /> / s<br />
<DividendsStats corp={corp} profit={profit} />
Publicly Traded: {corp.public ? "Yes" : "No"}
<br />
Owned Stock Shares: {numeralWrapper.format(corp.numShares, "0.000a")}
<br />
Stock Price: {corp.public ? <Money money={corp.sharePrice} /> : "N/A"}
<br /> <br />
</p> </p>
); <p className="tooltip">
} Total Stock Shares: {numeralWrapper.format(corp.totalShares, "0.000a")}
<span className="tooltiptext">
// Returns a string with general information about Corporation Outstanding Shares: {numeralWrapper.format(corp.issuedShares, "0.000a")}
function BonusTime(): React.ReactElement {
const storedTime = props.corp.storedCycles * CONSTANTS.MilliPerCycle;
if (storedTime <= 15000) return <></>;
return (
<p>
Bonus time: {convertTimeMsToTimeElapsedString(storedTime)}
<br />
<br /> <br />
Private Shares: {numeralWrapper.format(corp.totalShares - corp.issuedShares - corp.numShares, "0.000a")}
</span>
</p> </p>
); <br />
} <br />
<Mult name="Production Multiplier: " mult={corp.getProductionMultiplier()} />
function BribeButton(): React.ReactElement { <Mult name="Storage Multiplier: " mult={corp.getStorageMultiplier()} />
const canBribe = props.corp.determineValuation() >= CorporationConstants.BribeThreshold || true; <Mult name="Advertising Multiplier: " mult={corp.getAdvertisingMultiplier()} />
const bribeFactionsClass = canBribe ? "a-link-button" : "a-link-button-inactive"; <Mult name="Empl. Creativity Multiplier: " mult={corp.getEmployeeCreMultiplier()} />
return ( <Mult name="Empl. Charisma Multiplier: " mult={corp.getEmployeeChaMultiplier()} />
<Mult name="Empl. Intelligence Multiplier: " mult={corp.getEmployeeIntMultiplier()} />
<Mult name="Empl. Efficiency Multiplier: " mult={corp.getEmployeeEffMultiplier()} />
<Mult name="Sales Multiplier: " mult={corp.getSalesMultiplier()} />
<Mult name="Scientific Research Multiplier: " mult={corp.getScientificResearchMultiplier()} />
<br />
<BonusTime corp={corp} />
<div>
<Button <Button
className={bribeFactionsClass} className="a-link-button"
display="inline-block" display="inline-block"
onClick={openBribeFactionPopup} onClick={() => corp.getStarterGuide(player)}
text="Bribe Factions" text="Getting Started Guide"
tooltip={ tooltip={
canBribe "Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " +
? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation" "This is a .lit file that guides you through the beginning of setting up a Corporation and " +
: "Your Corporation is not powerful enough to bribe Faction leaders" "provides some tips/pointers for helping you get started with managing it."
} }
/> />
{corp.public ? (
<PublicButtons corp={corp} player={player} rerender={rerender} />
) : (
<PrivateButtons corp={corp} player={player} rerender={rerender} />
)}
<BribeButton corp={corp} player={player} />
</div>
<br />
<Upgrades corp={corp} player={player} rerender={rerender} />
</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 { function openFindInvestorsPopup(): void {
const popupId = "cmpy-mgmt-find-investors-popup"; const popupId = "cmpy-mgmt-find-investors-popup";
createPopup(popupId, FindInvestorsPopup, { createPopup(popupId, FindInvestorsPopup, {
rerender: props.rerender, rerender,
player: props.player, player,
popupId: popupId, popupId,
corp: props.corp, corp: corp,
}); });
} }
function openGoPublicPopup(): void { function openGoPublicPopup(): void {
const popupId = "cmpy-mgmt-go-public-popup"; const popupId = "cmpy-mgmt-go-public-popup";
createPopup(popupId, GoPublicPopup, { createPopup(popupId, GoPublicPopup, {
rerender: props.rerender, rerender,
player: props.player, player,
popupId: popupId, popupId,
corp: props.corp, corp: corp,
}); });
} }
// Render the buttons for when your Corporation is still private const fundingAvailable = corp.fundingRound < 4;
function PrivateButtons(): React.ReactElement {
const fundingAvailable = props.corp.fundingRound < 4;
const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive"; const findInvestorsClassName = fundingAvailable ? "std-button" : "a-link-button-inactive";
const findInvestorsTooltip = fundingAvailable const findInvestorsTooltip = fundingAvailable
? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company" ? "Search for private investors who will give you startup funding in exchangefor equity (stock shares) in your company"
@ -179,46 +151,45 @@ export function Overview(props: IProps): React.ReactElement {
); );
} }
function openSellSharesPopup(): void { interface IUpgradeProps {
const popupId = "cmpy-mgmt-sell-shares-popup"; corp: ICorporation;
createPopup(popupId, SellSharesPopup, { player: IPlayer;
corp: props.corp, rerender: () => void;
player: props.player, }
popupId: popupId, // Render the UI for Corporation upgrades
rerender: props.rerender, 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>;
} }
function openBuybackSharesPopup(): void { return (
const popupId = "corp-buyback-shares-popup"; <div className={"cmpy-mgmt-upgrade-container"}>
createPopup(popupId, BuybackSharesPopup, { <h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1>
rerender: props.rerender, {Object.values(CorporationUnlockUpgrades)
player: props.player, .filter((upgrade: CorporationUnlockUpgrade) => corp.unlockUpgrades[upgrade[0]] === 0)
popupId: popupId, .map((upgrade: CorporationUnlockUpgrade) => (
corp: props.corp, <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>
);
} }
function openIssueNewSharesPopup(): void { interface IPublicButtonsProps {
const popupId = "cmpy-mgmt-issue-new-shares-popup"; corp: ICorporation;
createPopup(popupId, IssueNewSharesPopup, { player: IPlayer;
popupId: popupId, rerender: () => void;
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 // Render the buttons for when your Corporation has gone public
function PublicButtons(): React.ReactElement { function PublicButtons({ corp, player, rerender }: IPublicButtonsProps): React.ReactElement {
const corp = props.corp;
const sellSharesOnCd = corp.shareSaleCooldown > 0; const sellSharesOnCd = corp.shareSaleCooldown > 0;
const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button"; const sellSharesClass = sellSharesOnCd ? "a-link-button-inactive" : "std-button";
const sellSharesTooltip = sellSharesOnCd const sellSharesTooltip = sellSharesOnCd
@ -233,6 +204,42 @@ export function Overview(props: IProps): React.ReactElement {
? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown) ? "Cannot issue new shares for " + corp.convertCooldownToString(corp.issueNewSharesCooldown)
: "Issue new equity shares to raise capital."; : "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 ( return (
<> <>
<Button <Button
@ -269,100 +276,111 @@ export function Overview(props: IProps): React.ReactElement {
); );
} }
// Render the UI for Corporation upgrades // Generic Function for Creating a button
function Upgrades(): React.ReactElement { interface ICreateButtonProps {
// Don't show upgrades text: string;
if (props.corp.divisions.length <= 0) { className?: string;
return <h1>Unlock upgrades after creating your first division</h1>; 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 ( return (
<div className={"cmpy-mgmt-upgrade-container"}> <button className={className} onClick={onClick} style={{ display: display ? display : "block" }}>
<h1 className={"cmpy-mgmt-upgrade-header"}> Unlocks </h1> {text}
{Object.values(CorporationUnlockUpgrades) {hasTooltip && <span className={"tooltiptext"}>{tooltip}</span>}
.filter((upgrade: CorporationUnlockUpgrade) => props.corp.unlockUpgrades[upgrade[0]] === 0) </button>
.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>
); );
} }
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 ( return (
<div>
<p>
Total Funds: <Money money={props.corp.funds.toNumber()} />
<br />
Total Revenue: <Money money={props.corp.revenue.toNumber()} /> / s<br />
Total Expenses: <Money money={props.corp.expenses.toNumber()} /> / s
<br />
Total Profits: <Money money={profit} /> / s<br />
<DividendsStats />
Publicly Traded: {props.corp.public ? "Yes" : "No"}
<br />
Owned Stock Shares: {numeralWrapper.format(props.corp.numShares, "0.000a")}
<br />
Stock Price: {props.corp.public ? <Money money={props.corp.sharePrice} /> : "N/A"}
<br />
</p>
<p className="tooltip">
Total Stock Shares: {numeralWrapper.format(props.corp.totalShares, "0.000a")}
<span className="tooltiptext">
Outstanding Shares: {numeralWrapper.format(props.corp.issuedShares, "0.000a")}
<br />
Private Shares:{" "}
{numeralWrapper.format(props.corp.totalShares - props.corp.issuedShares - props.corp.numShares, "0.000a")}
</span>
</p>
<br />
<br />
<Mult name="Production Multiplier: " mult={props.corp.getProductionMultiplier()} />
<Mult name="Storage Multiplier: " mult={props.corp.getStorageMultiplier()} />
<Mult name="Advertising Multiplier: " mult={props.corp.getAdvertisingMultiplier()} />
<Mult name="Empl. Creativity Multiplier: " mult={props.corp.getEmployeeCreMultiplier()} />
<Mult name="Empl. Charisma Multiplier: " mult={props.corp.getEmployeeChaMultiplier()} />
<Mult name="Empl. Intelligence Multiplier: " mult={props.corp.getEmployeeIntMultiplier()} />
<Mult name="Empl. Efficiency Multiplier: " mult={props.corp.getEmployeeEffMultiplier()} />
<Mult name="Sales Multiplier: " mult={props.corp.getSalesMultiplier()} />
<Mult name="Scientific Research Multiplier: " mult={props.corp.getScientificResearchMultiplier()} />
<br />
<BonusTime />
<div>
<Button <Button
className="a-link-button" className={bribeFactionsClass}
display="inline-block" display="inline-block"
onClick={() => props.corp.getStarterGuide(props.player)} onClick={openBribeFactionPopup}
text="Getting Started Guide" text="Bribe Factions"
tooltip={ tooltip={
"Get a copy of and read 'The Complete Handbook for Creating a Successful Corporation.' " + canBribe
"This is a .lit file that guides you through the beginning of setting up a Corporation and " + ? "Use your Corporations power and influence to bribe Faction leaders in exchange for reputation"
"provides some tips/pointers for helping you get started with managing it." : "Your Corporation is not powerful enough to bribe Faction leaders"
} }
/> />
{props.corp.public ? <PublicButtons /> : <PrivateButtons />} );
<BribeButton /> }
</div>
<br /> interface IDividendsStatsProps {
<Upgrades /> corp: ICorporation;
</div> 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>
); );
} }

@ -18,8 +18,17 @@ import { saveObject } from "./SaveObject";
import { dialogBoxCreate } from "../utils/DialogBox"; import { dialogBoxCreate } from "../utils/DialogBox";
import { Money } from "./ui/React/Money"; import { Money } from "./ui/React/Money";
import { TextField } from "./ui/React/TextField";
import { Button } from "./ui/React/Button";
import { Select } from "./ui/React/Select";
import React, { useState } from "react"; import React, { useState } from "react";
import AddIcon from "@material-ui/icons/Add";
import RemoveIcon from "@material-ui/icons/Remove";
import IconButton from "@material-ui/core/IconButton";
import ExposureZeroIcon from "@material-ui/icons/ExposureZero";
import ButtonGroup from "@material-ui/core/ButtonGroup";
import { Theme } from "./ui/React/Theme";
// Update as additional BitNodes get implemented // Update as additional BitNodes get implemented
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
@ -29,38 +38,48 @@ const tonsPP = 1e27;
const tonsP = 1e12; const tonsP = 1e12;
interface IValueAdjusterProps { interface IValueAdjusterProps {
title: string; label: string;
placeholder: string;
add: (x: number) => void; add: (x: number) => void;
subtract: (x: number) => void; subtract: (x: number) => void;
reset: () => void; reset: () => void;
} }
function ValueAdjusterComponent(props: IValueAdjusterProps): React.ReactElement { function ValueAdjusterComponent(props: IValueAdjusterProps): React.ReactElement {
const [value, setValue] = useState(0); const [value, setValue] = useState<number | string>("");
function onChange(event: React.ChangeEvent<HTMLInputElement>): void { function onChange(event: React.ChangeEvent<HTMLInputElement>): void {
setValue(parseFloat(event.target.value)); if (event.target.value === "") setValue("");
else setValue(parseFloat(event.target.value));
} }
const { title, add, subtract, reset } = props; const { label, placeholder, add, subtract, reset } = props;
return ( return (
<> <>
<button className="std-button add-exp-button" onClick={() => add(value)}> <TextField
+ label={label}
</button>
<input
className="text-input exp-input"
type="number"
placeholder={`+/- ${title}`}
value={value} value={value}
onChange={onChange} onChange={onChange}
></input> placeholder={placeholder}
<button className="std-button remove-exp-button" onClick={() => subtract(value)}> type="number"
- InputProps={{
</button> startAdornment: (
<button className="std-button" onClick={reset}> <IconButton color="primary" onClick={() => add(typeof value !== "string" ? value : 0)}>
Reset <AddIcon />
</button> </IconButton>
),
endAdornment: (
<>
<IconButton color="primary" onClick={() => subtract(typeof value !== "string" ? value : 0)}>
<RemoveIcon />
</IconButton>
<IconButton color="primary" onClick={reset}>
<ExposureZeroIcon />
</IconButton>
</>
),
}}
/>
</> </>
); );
} }
@ -80,28 +99,28 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
const [stockPrice, setStockPrice] = useState(0); const [stockPrice, setStockPrice] = useState(0);
const [stockSymbol, setStockSymbol] = useState(""); const [stockSymbol, setStockSymbol] = useState("");
function setFactionDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setFactionDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setFaction(event.target.value); setFaction(event.target.value as string);
} }
function setCompanyDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setCompanyDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setCompany(event.target.value); setCompany(event.target.value as string);
} }
function setProgramDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setProgramDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setProgram(event.target.value); setProgram(event.target.value as string);
} }
function setServerDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setServerDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setServer(event.target.value); setServer(event.target.value as string);
} }
function setAugmentationDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setAugmentationDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setAugmentation(event.target.value); setAugmentation(event.target.value as string);
} }
function setCodingcontractDropdown(event: React.ChangeEvent<HTMLSelectElement>): void { function setCodingcontractDropdown(event: React.ChangeEvent<{ value: unknown }>): void {
setCodingcontract(event.target.value); setCodingcontract(event.target.value as string);
} }
function setStockPriceField(event: React.ChangeEvent<HTMLInputElement>): void { function setStockPriceField(event: React.ChangeEvent<HTMLInputElement>): void {
@ -751,7 +770,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
} }
return ( return (
<div className="col"> <Theme>
<div className="col" style={{ backgroundColor: "#111" }}>
<div className="row"> <div className="row">
<h1>Development Menu - Only meant to be used for testing/debugging</h1> <h1>Development Menu - Only meant to be used for testing/debugging</h1>
</div> </div>
@ -759,38 +779,38 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<h2>Generic</h2> <h2>Generic</h2>
</div> </div>
<div className="row"> <div className="row">
<button className="std-button" onClick={addMoney(1e6)}> <Button onClick={addMoney(1e6)}>
Add <Money money={1e6} /> <pre>
</button> + <Money money={1e6} />
<button className="std-button" onClick={addMoney(1e9)}> </pre>
Add <Money money={1e9} /> </Button>
</button> <Button onClick={addMoney(1e9)}>
<button className="std-button" onClick={addMoney(1e12)}> <pre>
Add <Money money={1e12} /> + <Money money={1e9} />
</button> </pre>
<button className="std-button" onClick={addMoney(1e15)}> </Button>
Add <Money money={1000e12} /> <Button onClick={addMoney(1e12)}>
</button> <pre>
<button className="std-button" onClick={addMoney(Infinity)}> + <Money money={1e12} />
Add <Money money={Infinity} /> </pre>
</button> </Button>
<button className="std-button" onClick={upgradeRam}> <Button onClick={addMoney(1e15)}>
Upgrade Home Computer's RAM <pre>
</button> + <Money money={1000e12} />
</pre>
</Button>
<Button onClick={addMoney(Infinity)}>
<pre>
+ <Money money={Infinity} />
</pre>
</Button>
<Button onClick={upgradeRam}>+ RAM</Button>
</div> </div>
<div className="row"> <div className="row">
<button className="std-button" onClick={quickB1tFlum3}> <Button onClick={quickB1tFlum3}>Quick b1t_flum3.exe</Button>
Quick b1t_flum3.exe <Button onClick={b1tflum3}>Run b1t_flum3.exe</Button>
</button> <Button onClick={quickHackW0r1dD43m0n}>Quick w0rld_d34m0n</Button>
<button className="std-button" onClick={b1tflum3}> <Button onClick={hackW0r1dD43m0n}>Hack w0rld_d34m0n</Button>
Run b1t_flum3.exe
</button>
<button className="std-button" onClick={quickHackW0r1dD43m0n}>
Quick w0rld_d34m0n
</button>
<button className="std-button" onClick={hackW0r1dD43m0n}>
Hack w0rld_d34m0n
</button>
</div> </div>
<div className="row"> <div className="row">
<div className="col"> <div className="col">
@ -804,14 +824,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text text-center">All:</span> <span className="text text-center">All:</span>
</td> </td>
<td> <td>
<button className="std-button tooltip" onClick={tonsOfExp}> <Button onClick={tonsOfExp}>Tons of exp</Button>
Tons of exp <Button onClick={resetAllExp}>Reset</Button>
<span className="tooltiptext">Sometimes you just need a ton of experience in every stat</span>
</button>
<button className="std-button tooltip" onClick={resetAllExp}>
Reset
<span className="tooltiptext">Reset all experience to 0</span>
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -820,7 +834,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="hacking exp" label="hacking"
placeholder="exp"
add={modifyExp("hacking", 1)} add={modifyExp("hacking", 1)}
subtract={modifyExp("hacking", -1)} subtract={modifyExp("hacking", -1)}
reset={resetExperience("hacking")} reset={resetExperience("hacking")}
@ -833,7 +848,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="strength exp" label="strength"
placeholder="exp"
add={modifyExp("strength", 1)} add={modifyExp("strength", 1)}
subtract={modifyExp("strength", -1)} subtract={modifyExp("strength", -1)}
reset={resetExperience("strength")} reset={resetExperience("strength")}
@ -846,7 +862,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="defense exp" label="defense"
placeholder="exp"
add={modifyExp("defense", 1)} add={modifyExp("defense", 1)}
subtract={modifyExp("defense", -1)} subtract={modifyExp("defense", -1)}
reset={resetExperience("defense")} reset={resetExperience("defense")}
@ -859,7 +876,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="dexterity exp" label="dexterity"
placeholder="exp"
add={modifyExp("dexterity", 1)} add={modifyExp("dexterity", 1)}
subtract={modifyExp("dexterity", -1)} subtract={modifyExp("dexterity", -1)}
reset={resetExperience("dexterity")} reset={resetExperience("dexterity")}
@ -872,7 +890,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="agility exp" label="agility"
placeholder="exp"
add={modifyExp("agility", 1)} add={modifyExp("agility", 1)}
subtract={modifyExp("agility", -1)} subtract={modifyExp("agility", -1)}
reset={resetExperience("agility")} reset={resetExperience("agility")}
@ -885,7 +904,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="charisma exp" label="charisma"
placeholder="exp"
add={modifyExp("charisma", 1)} add={modifyExp("charisma", 1)}
subtract={modifyExp("charisma", -1)} subtract={modifyExp("charisma", -1)}
reset={resetExperience("charisma")} reset={resetExperience("charisma")}
@ -898,21 +918,18 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="intelligence exp" label="intelligence"
placeholder="exp"
add={modifyExp("intelligence", 1)} add={modifyExp("intelligence", 1)}
subtract={modifyExp("intelligence", -1)} subtract={modifyExp("intelligence", -1)}
reset={resetExperience("intelligence")} reset={resetExperience("intelligence")}
/> />
</td> </td>
<td> <td>
<button className="std-button" onClick={enableIntelligence}> <Button onClick={enableIntelligence}>Enable</Button>
Enable
</button>
</td> </td>
<td> <td>
<button className="std-button" onClick={disableIntelligence}> <Button onClick={disableIntelligence}>Disable</Button>
Disable
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -921,7 +938,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="karma" label="karma"
placeholder="amt"
add={modifyKarma(1)} add={modifyKarma(1)}
subtract={modifyKarma(-1)} subtract={modifyKarma(-1)}
reset={resetKarma()} reset={resetKarma()}
@ -944,14 +962,19 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Faction:</span> <span className="text">Faction:</span>
</td> </td>
<td> <td>
<select <Select
id="factions-dropdown" id="factions-dropdown"
className="dropdown exp-input" className="dropdown exp-input"
onChange={setFactionDropdown} onChange={setFactionDropdown}
value={faction} value={faction}
startAdornment={
<IconButton color="primary">
<AddIcon />
</IconButton>
}
> >
{factions} {factions}
</select> </Select>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -959,14 +982,10 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Invites:</span> <span className="text">Invites:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={receiveInvite}> <Button onClick={receiveInvite}>Receive invite from faction</Button>
Receive invite from faction
</button>
</td> </td>
<td> <td>
<button className="std-button" onClick={receiveAllInvites}> <Button onClick={receiveAllInvites}>Receive all Invites</Button>
Receive all Invites
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -975,7 +994,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="reputation" label="reputation"
placeholder="amt"
add={modifyFactionRep(1)} add={modifyFactionRep(1)}
subtract={modifyFactionRep(-1)} subtract={modifyFactionRep(-1)}
reset={resetFactionRep} reset={resetFactionRep}
@ -988,7 +1008,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="favor" label="favor"
placeholder="amt"
add={modifyFactionFavor(1)} add={modifyFactionFavor(1)}
subtract={modifyFactionFavor(-1)} subtract={modifyFactionFavor(-1)}
reset={resetFactionFavor} reset={resetFactionFavor}
@ -1000,12 +1021,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">All Reputation:</span> <span className="text">All Reputation:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={tonsOfRep}> <Button onClick={tonsOfRep}>Tons</Button>
Tons <Button onClick={resetAllRep}>Reset</Button>
</button>
<button className="std-button" onClick={resetAllRep}>
Reset
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1013,12 +1030,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">All Favor:</span> <span className="text">All Favor:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={tonsOfFactionFavor}> <Button onClick={tonsOfFactionFavor}>Tons</Button>
Tons <Button onClick={resetAllFactionFavor}>Reset</Button>
</button>
<button className="std-button" onClick={resetAllFactionFavor}>
Reset
</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -1037,14 +1050,14 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Aug:</span> <span className="text">Aug:</span>
</td> </td>
<td> <td>
<select <Select
id="dev-augs-dropdown" id="dev-augs-dropdown"
className="dropdown" className="dropdown"
onChange={setAugmentationDropdown} onChange={setAugmentationDropdown}
value={augmentation} value={augmentation}
> >
{augs} {augs}
</select> </Select>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1052,12 +1065,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Queue:</span> <span className="text">Queue:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={queueAug}> <Button onClick={queueAug}>One</Button>
One <Button onClick={queueAllAugs}>All</Button>
</button>
<button className="std-button" onClick={queueAllAugs}>
All
</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -1086,18 +1095,12 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">All:</span> <span className="text">All:</span>
</td> </td>
<td> <td>
<button className="std-button touch-right" onClick={setAllSF(0)}> <ButtonGroup>
0 <Button onClick={setAllSF(0)}>0</Button>
</button> <Button onClick={setAllSF(1)}>1</Button>
<button className="std-button touch-sides" onClick={setAllSF(1)}> <Button onClick={setAllSF(2)}>2</Button>
1 <Button onClick={setAllSF(3)}>3</Button>
</button> </ButtonGroup>
<button className="std-button touch-sides" onClick={setAllSF(2)}>
2
</button>
<button className="std-button touch-left" onClick={setAllSF(3)}>
3
</button>
</td> </td>
</tr> </tr>
{validSFN.map((i) => ( {validSFN.map((i) => (
@ -1106,18 +1109,12 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">SF-{i}:</span> <span className="text">SF-{i}:</span>
</td> </td>
<td> <td>
<button className="std-button touch-right" onClick={setSF(i, 0)}> <ButtonGroup>
0 <Button onClick={setSF(i, 0)}>0</Button>
</button> <Button onClick={setSF(i, 1)}>1</Button>
<button className="std-button touch-sides" onClick={setSF(i, 1)}> <Button onClick={setSF(i, 2)}>2</Button>
1 <Button onClick={setSF(i, 3)}>3</Button>
</button> </ButtonGroup>
<button className="std-button touch-sides" onClick={setSF(i, 2)}>
2
</button>
<button className="std-button touch-left" onClick={setSF(i, 3)}>
3
</button>
</td> </td>
</tr> </tr>
))} ))}
@ -1137,9 +1134,14 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Program:</span> <span className="text">Program:</span>
</td> </td>
<td> <td>
<select id="dev-programs-dropdown" className="dropdown" onChange={setProgramDropdown} value={program}> <Select
id="dev-programs-dropdown"
className="dropdown"
onChange={setProgramDropdown}
value={program}
>
{programs} {programs}
</select> </Select>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1147,12 +1149,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Add:</span> <span className="text">Add:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={addProgram}> <Button onClick={addProgram}>One</Button>
One <Button onClick={addAllPrograms}>All</Button>
</button>
<button className="std-button" onClick={addAllPrograms}>
All
</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -1171,9 +1169,9 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Server:</span> <span className="text">Server:</span>
</td> </td>
<td colSpan={2}> <td colSpan={2}>
<select id="dev-servers-dropdown" className="dropdown" onChange={setServerDropdown} value={server}> <Select id="dev-servers-dropdown" className="dropdown" onChange={setServerDropdown} value={server}>
{servers} {servers}
</select> </Select>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1181,14 +1179,10 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Root:</span> <span className="text">Root:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={rootServer}> <Button onClick={rootServer}>Root one</Button>
Root one
</button>
</td> </td>
<td> <td>
<button className="std-button" onClick={rootAllServers}> <Button onClick={rootAllServers}>Root all</Button>
Root all
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1196,14 +1190,10 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Security:</span> <span className="text">Security:</span>
</td> </td>
<td> <td>
<button className="std-button" onClick={minSecurity}> <Button onClick={minSecurity}>Min one</Button>
Min one
</button>
</td> </td>
<td> <td>
<button className="std-button" onClick={minAllSecurity}> <Button onClick={minAllSecurity}>Min all</Button>
Min all
</button>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1237,14 +1227,14 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
<span className="text">Company:</span> <span className="text">Company:</span>
</td> </td>
<td colSpan={3}> <td colSpan={3}>
<select <Select
id="dev-companies-dropdown" id="dev-companies-dropdown"
className="dropdown" className="dropdown"
onChange={setCompanyDropdown} onChange={setCompanyDropdown}
value={company} value={company}
> >
{companies} {companies}
</select> </Select>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -1253,7 +1243,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="reputation" label="reputation"
placeholder="amt"
add={modifyCompanyRep(1)} add={modifyCompanyRep(1)}
subtract={modifyCompanyRep(-1)} subtract={modifyCompanyRep(-1)}
reset={resetCompanyRep} reset={resetCompanyRep}
@ -1266,7 +1257,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="favor" label="favor"
placeholder="amt"
add={modifyCompanyFavor(1)} add={modifyCompanyFavor(1)}
subtract={modifyCompanyFavor(-1)} subtract={modifyCompanyFavor(-1)}
reset={resetCompanyFavor} reset={resetCompanyFavor}
@ -1323,7 +1315,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="rank" label="rank"
placeholder="amt"
add={modifyBladeburnerRank(1)} add={modifyBladeburnerRank(1)}
subtract={modifyBladeburnerRank(-1)} subtract={modifyBladeburnerRank(-1)}
reset={resetBladeburnerRank} reset={resetBladeburnerRank}
@ -1341,7 +1334,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="cycles" label="cycles"
placeholder="amt"
add={modifyBladeburnerCycles(1)} add={modifyBladeburnerCycles(1)}
subtract={modifyBladeburnerCycles(-1)} subtract={modifyBladeburnerCycles(-1)}
reset={resetBladeburnerCycles} reset={resetBladeburnerCycles}
@ -1373,7 +1367,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="cycles" label="cycles"
placeholder="amt"
add={modifyGangCycles(1)} add={modifyGangCycles(1)}
subtract={modifyGangCycles(-1)} subtract={modifyGangCycles(-1)}
reset={resetGangCycles} reset={resetGangCycles}
@ -1415,7 +1410,8 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</td> </td>
<td> <td>
<ValueAdjusterComponent <ValueAdjusterComponent
title="cycles" label="cycles"
placeholder="amt"
add={modifyCorporationCycles(1)} add={modifyCorporationCycles(1)}
subtract={modifyCorporationCycles(-1)} subtract={modifyCorporationCycles(-1)}
reset={resetCorporationCycles} reset={resetCorporationCycles}
@ -1461,14 +1457,14 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</tr> </tr>
<tr> <tr>
<td> <td>
<select <Select
id="contract-types-dropdown" id="contract-types-dropdown"
className="dropdown" className="dropdown"
onChange={setCodingcontractDropdown} onChange={setCodingcontractDropdown}
value={codingcontract} value={codingcontract}
> >
{contractTypes} {contractTypes}
</select> </Select>
<button className="std-button" onClick={specificContract}> <button className="std-button" onClick={specificContract}>
Generate Specified Contract Type on Home Comp Generate Specified Contract Type on Home Comp
</button> </button>
@ -1597,5 +1593,6 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
</div> </div>
</div> </div>
</div> </div>
</Theme>
); );
} }

@ -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) => {
const match = Object.entries(CityName).find(([key, value]) => value === city);
if (match === undefined) throw new Error(`could not find key for city '${city}'`);
return (
<StdButton <StdButton
key={city} key={city}
onClick={() => onClick={() => createTravelPopup(props.p, city, () => props.travel(match[1]))}
createTravelPopup(props.p, city, () => props.travel(CityName[city as keyof typeof CityName]))
}
style={{ display: "block" }} style={{ display: "block" }}
text={`Travel to ${city}`} 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>
);