work on blade to react

This commit is contained in:
Olivier Gagnon 2021-08-15 21:49:08 -04:00
parent 33f0efd49c
commit 99d4f17cdb
17 changed files with 247 additions and 301 deletions

@ -55,7 +55,7 @@ interface IConstructorParams {
} }
function generateStatsDescription(mults: IMap<number>, programs?: string[], startingMoney?: number): JSX.Element { function generateStatsDescription(mults: IMap<number>, programs?: string[], startingMoney?: number): JSX.Element {
const f = (x: number, decimals: number = 0) => { const f = (x: number, decimals = 0) => {
// look, I don't know how to make a "smart decimals" // look, I don't know how to make a "smart decimals"
// todo, make it smarter // todo, make it smarter
if(x === 1.0777-1) return "7.77%"; if(x === 1.0777-1) return "7.77%";

@ -52,24 +52,10 @@ import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElement } from "../utils/uiHelpers/removeElement"; import { removeElement } from "../utils/uiHelpers/removeElement";
import { removeElementById } from "../utils/uiHelpers/removeElementById"; import { removeElementById } from "../utils/uiHelpers/removeElementById";
import { SkillElem } from "./Bladeburner/ui/SkillElem";
import { SkillList } from "./Bladeburner/ui/SkillList";
import { BlackOpElem } from "./Bladeburner/ui/BlackOpElem";
import { BlackOpList } from "./Bladeburner/ui/BlackOpList";
import { OperationElem } from "./Bladeburner/ui/OperationElem";
import { OperationList } from "./Bladeburner/ui/OperationList";
import { ContractElem } from "./Bladeburner/ui/ContractElem";
import { ContractList } from "./Bladeburner/ui/ContractList";
import { GeneralActionElem } from "./Bladeburner/ui/GeneralActionElem";
import { GeneralActionList } from "./Bladeburner/ui/GeneralActionList";
import { GeneralActionPage } from "./Bladeburner/ui/GeneralActionPage";
import { ContractPage } from "./Bladeburner/ui/ContractPage";
import { OperationPage } from "./Bladeburner/ui/OperationPage";
import { BlackOpPage } from "./Bladeburner/ui/BlackOpPage";
import { SkillPage } from "./Bladeburner/ui/SkillPage";
import { Stats } from "./Bladeburner/ui/Stats"; import { Stats } from "./Bladeburner/ui/Stats";
import { AllPages } from "./Bladeburner/ui/AllPages"; import { AllPages } from "./Bladeburner/ui/AllPages";
import { Console } from "./Bladeburner/ui/Console"; import { Console } from "./Bladeburner/ui/Console";
import { Root } from "./Bladeburner/ui/Root";
import { StatsTable } from "./ui/React/StatsTable"; import { StatsTable } from "./ui/React/StatsTable";
import { CopyableText } from "./ui/React/CopyableText"; import { CopyableText } from "./ui/React/CopyableText";
@ -77,73 +63,6 @@ import { Money } from "./ui/React/Money";
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
const stealthIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 166 132" style="fill:#adff2f;"><g><path d="M132.658-0.18l-24.321,24.321c-7.915-2.71-16.342-4.392-25.087-4.392c-45.84,0-83,46-83,46 s14.1,17.44,35.635,30.844L12.32,120.158l12.021,12.021L144.68,11.841L132.658-0.18z M52.033,80.445 c-2.104-4.458-3.283-9.438-3.283-14.695c0-19.054,15.446-34.5,34.5-34.5c5.258,0,10.237,1.179,14.695,3.284L52.033,80.445z"/><path d="M134.865,37.656l-18.482,18.482c0.884,3.052,1.367,6.275,1.367,9.612c0,19.055-15.446,34.5-34.5,34.5 c-3.337,0-6.56-0.483-9.611-1.367l-10.124,10.124c6.326,1.725,12.934,2.743,19.735,2.743c45.84,0,83-46,83-46 S153.987,50.575,134.865,37.656z"/></g></svg>&nbsp;`
const killIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="-22 0 511 511.99561" style="fill:#adff2f;"><path d="m.496094 466.242188 39.902344-39.902344 45.753906 45.753906-39.898438 39.902344zm0 0"/><path d="m468.421875 89.832031-1.675781-89.832031-300.265625 300.265625 45.753906 45.753906zm0 0"/><path d="m95.210938 316.785156 16.84375 16.847656h.003906l83.65625 83.65625 22.753906-22.753906-100.503906-100.503906zm0 0"/><path d="m101.445312 365.300781-39.902343 39.902344 45.753906 45.753906 39.902344-39.902343-39.90625-39.902344zm0 0"/></svg>`
// DOM related variables
const ActiveActionCssClass = "bladeburner-active-action";
// Console related stuff
let consoleHistoryIndex = 0;
// Keypresses for Console
$(document).keydown(function(event) {
if (routing.isOn(Page.Bladeburner)) {
if (!(Player.bladeburner instanceof Bladeburner)) { return; }
let consoleHistory = Player.bladeburner.consoleHistory;
if (event.keyCode === KEY.ENTER) {
event.preventDefault();
var command = DomElems.consoleInput.value;
if (command.length > 0) {
Player.bladeburner.postToConsole("> " + command);
Player.bladeburner.resetConsoleInput();
Player.bladeburner.executeConsoleCommands(command);
}
}
if (event.keyCode === KEY.UPARROW) {
if (DomElems.consoleInput == null) {return;}
var i = consoleHistoryIndex;
var len = consoleHistory.length;
if (len === 0) {return;}
if (i < 0 || i > len) {
consoleHistoryIndex = len;
}
if (i !== 0) {
--consoleHistoryIndex;
}
var prevCommand = consoleHistory[consoleHistoryIndex];
DomElems.consoleInput.value = prevCommand;
setTimeoutRef(function(){DomElems.consoleInput.selectionStart = DomElems.consoleInput.selectionEnd = 10000; }, 0);
}
if (event.keyCode === KEY.DOWNARROW) {
if (DomElems.consoleInput == null) {return;}
var i = consoleHistoryIndex;
var len = consoleHistory.length;
if (len == 0) {return;}
if (i < 0 || i > len) {
consoleHistoryIndex = len;
}
// Latest command, put nothing
if (i == len || i == len-1) {
consoleHistoryIndex = len;
DomElems.consoleInput.value = "";
} else {
++consoleHistoryIndex;
var prevCommand = consoleHistory[consoleHistoryIndex];
DomElems.consoleInput.value = prevCommand;
}
}
}
});
function ActionIdentifier(params={}) { function ActionIdentifier(params={}) {
if (params.name) {this.name = params.name;} if (params.name) {this.name = params.name;}
if (params.type) {this.type = params.type;} if (params.type) {this.type = params.type;}
@ -1216,67 +1135,19 @@ let DomElems = {};
Bladeburner.prototype.initializeDomElementRefs = function() { Bladeburner.prototype.initializeDomElementRefs = function() {
DomElems = { DomElems = {
bladeburnerDiv: null, bladeburnerDiv: null,
// Main Divs
overviewConsoleParentDiv: null,
overviewDiv: null, // Overview of stats that stays fixed on left
actionAndSkillsDiv: null, // Panel for different sections (contracts, ops, skills)
consoleDiv: null,
consoleTable: null,
consoleInputRow: null, // tr
consoleInputCell: null, // td
consoleInputHeader: null, // "> "
consoleInput: null, // Actual input element
}; };
} }
Bladeburner.prototype.createContent = function() { Bladeburner.prototype.createContent = function() {
DomElems.bladeburnerDiv = createElement("div", { DomElems.bladeburnerDiv = createElement("div");
id:"bladeburner-container", position:"fixed", class:"generic-menupage-container",
});
// Parent Div for Overview and Console ReactDOM.render(<Root bladeburner={this} player={Player} engine={Engine} />, DomElems.bladeburnerDiv);
DomElems.overviewConsoleParentDiv = createElement("div", {
height:"60%", display:"block", position:"relative",
});
// Overview and Action/Skill pane
DomElems.overviewDiv = createElement("div", {
width:"30%", display:"inline-block", border:"1px solid white",
});
DomElems.actionAndSkillsDiv = createElement("div", {
width:"70%", display:"block",
border:"1px solid white", margin:"6px", padding:"6px",
});
ReactDOM.render(<Stats bladeburner={this} player={Player} />, DomElems.overviewDiv);
ReactDOM.render(<AllPages bladeburner={this} />, DomElems.actionAndSkillsDiv);
// Console
DomElems.consoleDiv = createElement("div", {
class:"bladeburner-console-div",
clickListener:() => {
if (DomElems.consoleInput instanceof Element) {
DomElems.consoleInput.focus();
}
return false;
},
});
ReactDOM.render(<Console bladeburner={this} />, DomElems.consoleDiv);
DomElems.overviewConsoleParentDiv.appendChild(DomElems.overviewDiv);
DomElems.overviewConsoleParentDiv.appendChild(DomElems.consoleDiv);
DomElems.bladeburnerDiv.appendChild(DomElems.overviewConsoleParentDiv);
DomElems.bladeburnerDiv.appendChild(DomElems.actionAndSkillsDiv);
document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv); document.getElementById("entire-game-container").appendChild(DomElems.bladeburnerDiv);
if (this.consoleLogs.length === 0) { if (this.consoleLogs.length === 0) {
this.postToConsole("Bladeburner Console BETA"); this.postToConsole("Bladeburner Console");
this.postToConsole("Type 'help' to see console commands"); this.postToConsole("Type 'help' to see console commands");
} else { } else {
for (let i = 0; i < this.consoleLogs.length; ++i) { for (let i = 0; i < this.consoleLogs.length; ++i) {
@ -1323,16 +1194,7 @@ Bladeburner.prototype.postToConsole = function(input, saveToLogs=true) {
} }
} }
Bladeburner.prototype.resetConsoleInput = function() {
DomElems.consoleInput.value = "";
}
Bladeburner.prototype.clearConsole = function() { Bladeburner.prototype.clearConsole = function() {
while (DomElems.consoleTable.childNodes.length > 1) {
DomElems.consoleTable.removeChild(DomElems.consoleTable.firstChild);
}
this.consoleLogs.length = 0; this.consoleLogs.length = 0;
} }
@ -1351,7 +1213,6 @@ Bladeburner.prototype.executeConsoleCommands = function(commands) {
this.consoleHistory.splice(0, 1); this.consoleHistory.splice(0, 1);
} }
} }
consoleHistoryIndex = this.consoleHistory.length;
const arrayOfCommands = commands.split(";"); const arrayOfCommands = commands.split(";");
for (let i = 0; i < arrayOfCommands.length; ++i) { for (let i = 0; i < arrayOfCommands.length; ++i) {

@ -6,6 +6,8 @@ import {
import { ActionTypes } from "../data/ActionTypes"; import { ActionTypes } from "../data/ActionTypes";
import { createProgressBarText } from "../../../utils/helpers/createProgressBarText"; import { createProgressBarText } from "../../../utils/helpers/createProgressBarText";
import { stealthIcon, killIcon } from "../data/Icons"; import { stealthIcon, killIcon } from "../data/Icons";
import { createPopup } from "../../ui/React/createPopup";
import { TeamSizePopup } from "./TeamSizePopup";
interface IProps { interface IProps {
bladeburner: any; bladeburner: any;
@ -34,41 +36,12 @@ export function BlackOpElem(props: IProps): React.ReactElement {
} }
function onTeam() { function onTeam() {
// TODO(hydroflame): this needs some changes that are in the Gang conversion. const popupId = "bladeburner-operation-set-team-size-popup";
// var popupId = "bladeburner-operation-set-team-size-popup"; createPopup(popupId, TeamSizePopup, {
// var txt = createElement("p", { bladeburner: props.bladeburner,
// innerText:"Enter the amount of team members you would like to take on this " + action: props.action,
// "BlackOp. If you do not have the specified number of team members, " + popupId: popupId,
// "then as many as possible will be used. Note that team members may " + });
// "be lost during operations.",
// });
// var input = createElement("input", {
// type:"number", placeholder: "Team size", class: "text-input",
// });
// var setBtn = createElement("a", {
// innerText:"Confirm", class:"a-link-button",
// clickListener:() => {
// var num = Math.round(parseFloat(input.value));
// if (isNaN(num) || num < 0) {
// dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
// } else {
// action.teamCount = num;
// this.updateBlackOpsUIElement(el, action);
// }
// removeElementById(popupId);
// return false;
// },
// });
// var cancelBtn = createElement("a", {
// innerText:"Cancel", class:"a-link-button",
// clickListener:() => {
// removeElementById(popupId);
// return false;
// },
// });
// createPopup(popupId, [txt, input, setBtn, cancelBtn]);
// input.focus();
} }
return (<> return (<>

@ -25,18 +25,16 @@ export function BlackOpList(props: IProps): React.ReactElement {
return (a.reqdRank - b.reqdRank); return (a.reqdRank - b.reqdRank);
}); });
blackops = blackops.filter((blackop: BlackOperation, i: number) => blackops = blackops.filter((blackop: BlackOperation, i: number) => !(props.bladeburner.blackops[blackops[i].name] == null &&
!(props.bladeburner.blackops[blackops[i].name] == null &&
i !== 0 && i !== 0 &&
props.bladeburner.blackops[blackops[i-1].name] == null)); props.bladeburner.blackops[blackops[i-1].name] == null));
blackops = blackops.reverse(); blackops = blackops.reverse();
return (<> return (<>
{blackops.map((blackop: BlackOperation) => {blackops.map((blackop: BlackOperation) => <li key={blackop.name} className="bladeburner-action">
<li key={blackop.name} className="bladeburner-action">
<BlackOpElem bladeburner={props.bladeburner} action={blackop} /> <BlackOpElem bladeburner={props.bladeburner} action={blackop} />
</li> </li>,
)} )}
</>); </>);
} }

@ -15,29 +15,97 @@ interface IProps {
} }
export function Console(props: IProps): React.ReactElement { export function Console(props: IProps): React.ReactElement {
const lastRef = useRef<HTMLTableDataCellElement>(null); const lastRef = useRef<HTMLDivElement>(null);
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
useEffect(() => { const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom() {
if(lastRef.current) if(lastRef.current)
lastRef.current.scrollIntoView({block: "end", inline: "nearest", behavior: "smooth" }); lastRef.current.scrollTop = lastRef.current.scrollHeight;
const id = setInterval(() => setRerender(old => !old), 1000); }
return () => clearInterval(id);
function rerender() {
setRerender(old => !old);
}
useEffect(() => {
const id = setInterval(rerender, 1000);
const id2 = setInterval(scrollToBottom, 100);
return () => {
clearInterval(id);
clearInterval(id2);
};
}, []); }, []);
return (<table className="bladeburner-console-table"> function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
<tbody> if (event.keyCode === 13) {
{/* event.preventDefault();
TODO: optimize this. const command = event.currentTarget.value;
using `i` as a key here isn't great because it'll re-render everything event.currentTarget.value = "";
everytime the console reaches max length. if (command.length > 0) {
*/} props.bladeburner.postToConsole("> " + command);
{props.bladeburner.consoleLogs.map((log: any, i: number) => <Line key={i} content={log} />)} props.bladeburner.executeConsoleCommands(command);
<tr key='input' id="bladeburner-console-input-row" className="bladeburner-console-input-row"> setConsoleHistoryIndex(props.bladeburner.consoleHistory.length);
<td ref={lastRef} className="bladeburner-console-input-cell"> rerender();
<pre>{"> "}</pre><input autoFocus className="bladeburner-console-input" tabIndex={1} type="text" /> }
</td> }
</tr>
</tbody> const consoleHistory = props.bladeburner.consoleHistory;
</table>);
if (event.keyCode === 38) { // up
let i = consoleHistoryIndex;
const len = consoleHistory.length;
if (len === 0) {return;}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
if (i !== 0) {
i = i-1;
}
setConsoleHistoryIndex(i);
const prevCommand = consoleHistory[i];
event.currentTarget.value = prevCommand;
}
if (event.keyCode === 40) {
const i = consoleHistoryIndex;
const len = consoleHistory.length;
if (len == 0) {return;}
if (i < 0 || i > len) {
setConsoleHistoryIndex(len);
}
// Latest command, put nothing
if (i == len || i == len-1) {
setConsoleHistoryIndex(len);
event.currentTarget.value = "";
} else {
setConsoleHistoryIndex(consoleHistoryIndex+1);
const prevCommand = consoleHistory[consoleHistoryIndex+1];
event.currentTarget.value = prevCommand;
}
}
}
return (<div ref={lastRef} className="bladeburner-console-div">
<table className="bladeburner-console-table">
<tbody>
{/*
TODO: optimize this.
using `i` as a key here isn't great because it'll re-render everything
everytime the console reaches max length.
*/}
{props.bladeburner.consoleLogs.map((log: any, i: number) => <Line key={i} content={log} />)}
<tr key="input" id="bladeburner-console-input-row" className="bladeburner-console-input-row">
<td className="bladeburner-console-input-cell">
<pre>{"> "}</pre><input autoFocus className="bladeburner-console-input" tabIndex={1} type="text" onKeyDown={handleKeyDown} />
</td>
</tr>
</tbody>
</table>
</div>);
} }

@ -14,10 +14,9 @@ export function ContractList(props: IProps): React.ReactElement {
const names = Object.keys(props.bladeburner.contracts); const names = Object.keys(props.bladeburner.contracts);
const contracts = props.bladeburner.contracts; const contracts = props.bladeburner.contracts;
return (<> return (<>
{names.map((name: string) => {names.map((name: string) => <li key={name} className="bladeburner-action">
<li key={name} className="bladeburner-action">
<ContractElem bladeburner={props.bladeburner} action={contracts[name]} /> <ContractElem bladeburner={props.bladeburner} action={contracts[name]} />
</li> </li>,
)} )}
</>); </>);
} }

@ -19,10 +19,9 @@ export function GeneralActionList(props: IProps): React.ReactElement {
} }
} }
return (<> return (<>
{actions.map((action: Action) => {actions.map((action: Action) => <li key={action.name} className="bladeburner-action">
<li key={action.name} className="bladeburner-action">
<GeneralActionElem bladeburner={props.bladeburner} action={action} /> <GeneralActionElem bladeburner={props.bladeburner} action={action} />
</li> </li>,
)} )}
</>); </>);
} }

@ -7,6 +7,8 @@ import {
} from "../../../utils/StringHelperFunctions"; } from "../../../utils/StringHelperFunctions";
import { stealthIcon, killIcon } from "../data/Icons"; import { stealthIcon, killIcon } from "../data/Icons";
import { BladeburnerConstants } from "../data/Constants"; import { BladeburnerConstants } from "../data/Constants";
import { createPopup } from "../../ui/React/createPopup";
import { TeamSizePopup } from "./TeamSizePopup";
interface IProps { interface IProps {
bladeburner: any; bladeburner: any;
@ -30,40 +32,12 @@ export function OperationElem(props: IProps): React.ReactElement {
} }
function onTeam() { function onTeam() {
// var popupId = "bladeburner-operation-set-team-size-popup"; const popupId = "bladeburner-operation-set-team-size-popup";
// var txt = createElement("p", { createPopup(popupId, TeamSizePopup, {
// innerText:"Enter the amount of team members you would like to take on these " + bladeburner: props.bladeburner,
// "operations. If you do not have the specified number of team members, " + action: props.action,
// "then as many as possible will be used. Note that team members may " + popupId: popupId,
// "be lost during operations.", });
// });
// var input = createElement("input", {
// type:"number", placeholder: "Team size", class: "text-input",
// });
// var setBtn = createElement("a", {
// innerText:"Confirm", class:"a-link-button",
// clickListener:() => {
// var num = Math.round(parseFloat(input.value));
// if (isNaN(num) || num < 0) {
// dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
// } else {
// action.teamCount = num;
// this.updateOperationsUIElement(el, action);
// }
// removeElementById(popupId);
// return false;
// },
// });
// var cancelBtn = createElement("a", {
// innerText:"Cancel", class:"a-link-button",
// clickListener:() => {
// removeElementById(popupId);
// return false;
// },
// });
// createPopup(popupId, [txt, input, setBtn, cancelBtn]);
// input.focus();
} }
function increaseLevel() { function increaseLevel() {

@ -14,10 +14,9 @@ export function OperationList(props: IProps): React.ReactElement {
const names = Object.keys(props.bladeburner.operations); const names = Object.keys(props.bladeburner.operations);
const operations = props.bladeburner.operations; const operations = props.bladeburner.operations;
return (<> return (<>
{names.map((name: string) => {names.map((name: string) => <li key={name} className="bladeburner-action">
<li key={name} className="bladeburner-action">
<OperationElem bladeburner={props.bladeburner} action={operations[name]} /> <OperationElem bladeburner={props.bladeburner} action={operations[name]} />
</li> </li>,
)} )}
</>); </>);
} }

@ -0,0 +1,27 @@
import React from "react";
import { Stats } from "./Stats";
import { Console } from "./Console";
import { AllPages } from "./AllPages";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IEngine } from "../../IEngine";
interface IProps {
bladeburner: any;
engine: IEngine;
player: IPlayer;
}
export function Root(props: IProps): React.ReactElement {
return (<div id="bladeburner-container" className="generic-menupage-container" style={{position:"fixed"}}>
<div style={{height:"60%", display:"block", position:"relative"}}>
<div style={{height: '100%', width:"30%", display:"inline-block", border:"1px solid white"}}>
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
</div>
<Console bladeburner={props.bladeburner} />
</div>
<div style={{width:"70%", display:"block", border:"1px solid white", marginTop:"6px", padding: "6px", position:"relative"}}>
<AllPages bladeburner={props.bladeburner} />
</div>
</div>);
}

@ -9,10 +9,9 @@ interface IProps {
export function SkillList(props: IProps): React.ReactElement { export function SkillList(props: IProps): React.ReactElement {
return (<> return (<>
{Object.keys(Skills).map((skill: string) => {Object.keys(Skills).map((skill: string) => <li key={skill} className="bladeburner-action">
<li key={skill} className="bladeburner-action">
<SkillElem bladeburner={props.bladeburner} skill={Skills[skill]} onUpgrade={props.onUpgrade} /> <SkillElem bladeburner={props.bladeburner} skill={Skills[skill]} onUpgrade={props.onUpgrade} />
</li> </li>,
)} )}
</>); </>);
} }

@ -5,13 +5,23 @@ import {
} from "../../../utils/StringHelperFunctions"; } from "../../../utils/StringHelperFunctions";
import { BladeburnerConstants } from "../data/Constants"; import { BladeburnerConstants } from "../data/Constants";
import { IPlayer } from "../../PersonObjects/IPlayer"; import { IPlayer } from "../../PersonObjects/IPlayer";
import { IEngine } from "../../IEngine";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { StatsTable } from "../../ui/React/StatsTable"; import { StatsTable } from "../../ui/React/StatsTable";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
import { createPopup } from "../../ui/React/createPopup";
import { Factions } from "../../Faction/Factions";
import {
joinFaction,
displayFactionContent,
} from "../../Faction/FactionHelpers";
import { TravelPopup } from "./TravelPopup";
interface IProps { interface IProps {
bladeburner: any; bladeburner: any;
engine: IEngine;
player: IPlayer; player: IPlayer;
} }
@ -53,53 +63,26 @@ export function Stats(props: IProps): React.ReactElement {
} }
function openTravel() { function openTravel() {
// var popupId = "bladeburner-travel-popup-cancel-btn"; const popupId = "bladeburner-travel-popup";
// var popupArguments = []; createPopup(popupId, TravelPopup, {
// popupArguments.push(createElement("a", { // Cancel Button bladeburner: props.bladeburner,
// innerText:"Cancel", class:"a-link-button", popupId: popupId,
// clickListener:() => { });
// removeElementById(popupId); return false;
// },
// }))
// popupArguments.push(createElement("p", { // Info Text
// innerText:"Travel to a different city for your Bladeburner " +
// "activities. This does not cost any money. The city you are " +
// "in for your Bladeburner duties does not affect " +
// "your location in the game otherwise",
// }));
// for (var i = 0; i < BladeburnerConstants.CityNames.length; ++i) {
// (function(inst, i) {
// popupArguments.push(createElement("div", {
// // Reusing this css class...it adds a border and makes it
// // so that background color changes when you hover
// class:"cmpy-mgmt-find-employee-option",
// innerText:BladeburnerConstants.CityNames[i],
// clickListener:() => {
// inst.city = BladeburnerConstants.CityNames[i];
// removeElementById(popupId);
// inst.updateOverviewContent();
// return false;
// },
// }));
// })(this, i);
// }
// createPopup(popupId, popupArguments);
} }
function openFaction() { function openFaction() {
// if (bladeburnerFac.isMember) { const faction = Factions["Bladeburners"];
// Engine.loadFactionContent(); if (faction.isMember) {
// displayFactionContent(bladeburnersFactionName); props.engine.loadFactionContent();
// } else { displayFactionContent("Bladeburners");
// if (this.rank >= BladeburnerConstants.RankNeededForFaction) { } else {
// joinFaction(bladeburnerFac); if (props.bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
// dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction"); joinFaction(faction);
// removeChildrenFromElement(DomElems.overviewDiv); dialogBoxCreate("Congratulations! You were accepted into the Bladeburners faction");
// this.createOverviewContent(); } else {
// } else { dialogBoxCreate("You need a rank of 25 to join the Bladeburners Faction!")
// dialogBoxCreate("You need a rank of 25 to join the Bladeburners Faction!") }
// } }
// }
} }
return (<> return (<>

@ -0,0 +1,37 @@
import React, { useState } from "react";
import { removePopup } from "../../ui/React/createPopup";
import { BladeburnerConstants } from "../data/Constants";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { Action } from "../Action";
interface IProps {
bladeburner: any;
action: Action;
popupId: string;
}
export function TeamSizePopup(props: IProps): React.ReactElement {
const [teamSize, setTeamSize] = useState<number | undefined>();
function confirmTeamSize(): void {
if(teamSize === undefined) return;
const num = Math.round(teamSize);
if (isNaN(num) || num < 0) {
dialogBoxCreate("Invalid value entered for number of Team Members (must be numeric, positive)")
} else {
props.action.teamCount = num;
}
removePopup(props.popupId);
}
return (<>
<p>
Enter the amount of team members you would like to take on this
Op. If you do not have the specified number of team members,
then as many as possible will be used. Note that team members may
be lost during operations.
</p>
<input autoFocus type="number" placeholder= "Team size" className= "text-input" onChange={event => setTeamSize(parseFloat(event.target.value))} />
<a className="a-link-button" onClick={confirmTeamSize}>Confirm</a>
</>);
}

@ -0,0 +1,31 @@
import React from "react";
import { removePopup } from "../../ui/React/createPopup";
import { BladeburnerConstants } from "../data/Constants";
interface IProps {
bladeburner: any;
popupId: string;
}
export function TravelPopup(props: IProps): React.ReactElement {
function travel(city: string) {
props.bladeburner.city = city;
removePopup(props.popupId);
}
return (<>
<p>
Travel to a different city for your Bladeburner
activities. This does not cost any money. The city you are
in for your Bladeburner duties does not affect
your location in the game otherwise.
</p>
{BladeburnerConstants.CityNames.map(city =>
// Reusing this css class...it adds a border and makes it
// so that background color changes when you hover
<div className="cmpy-mgmt-find-employee-option"
onClick={() => travel(city)}>
{city}
</div>)}
</>);
}

@ -28,8 +28,7 @@ export function FactionList(props: IProps): React.ReactElement {
<p>Lists all factions you have joined</p> <p>Lists all factions you have joined</p>
<br /> <br />
<ul> <ul>
{props.player.factions.map((faction: string) => {props.player.factions.map((faction: string) => <li key={faction}><a
<li key={faction}><a
className="a-link-button" className="a-link-button"
onClick={() => openFaction(faction)} onClick={() => openFaction(faction)}
style={{padding:"4px", margin:"4px", display:"inline-block"}}>{faction} style={{padding:"4px", margin:"4px", display:"inline-block"}}>{faction}
@ -39,8 +38,7 @@ export function FactionList(props: IProps): React.ReactElement {
<h1>Outstanding Faction Invitations</h1> <h1>Outstanding Faction Invitations</h1>
<p style={{width: '70%'}}>Lists factions you have been invited to. You can accept these faction invitations at any time.</p> <p style={{width: '70%'}}>Lists factions you have been invited to. You can accept these faction invitations at any time.</p>
<ul> <ul>
{props.player.factionInvitations.map((faction: string) => {props.player.factionInvitations.map((faction: string) => <li key={faction} style={{padding:"6px", margin:"6px"}}>
<li key={faction} style={{padding:"6px", margin:"6px"}}>
<p style={{display:"inline", margin:"4px", padding:"4px"}}>{faction}</p> <p style={{display:"inline", margin:"4px", padding:"4px"}}>{faction}</p>
<a <a
className="a-link-button" className="a-link-button"

@ -42,6 +42,6 @@ export function TaskSelector(props: IProps): React.ReactElement {
<option key={0} value={"---"}>---</option> <option key={0} value={"---"}>---</option>
{tasks.map((task: string, i: number) => <option key={i+1} value={task}>{task}</option>)} {tasks.map((task: string, i: number) => <option key={i+1} value={task}>{task}</option>)}
</select> </select>
<div>{StatsTable(data, null)}</div> <div>{StatsTable(data)}</div>
</>); </>);
} }

@ -76,7 +76,7 @@ function containsAllStrings(arr: string[]): boolean {
} }
// Formats a number with commas and a specific number of decimal digits // Formats a number with commas and a specific number of decimal digits
function formatNumber(num: number, numFractionDigits: number = 0): string { function formatNumber(num: number, numFractionDigits = 0): string {
return num.toLocaleString(undefined, { return num.toLocaleString(undefined, {
maximumFractionDigits: numFractionDigits, maximumFractionDigits: numFractionDigits,
minimumFractionDigits: numFractionDigits, minimumFractionDigits: numFractionDigits,