mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-05-13 02:50:04 +02:00
build dev
This commit is contained in:
+120
-100
@@ -6,114 +6,134 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { City } from "../City";
|
||||
import { Cities } from "../Cities";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
import { Locations } from "../Locations";
|
||||
import { Location } from "../Location";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
type IProps = {
|
||||
city: City;
|
||||
enterLocation: (to: LocationName) => void;
|
||||
};
|
||||
|
||||
export class LocationCity extends React.Component<IProps, any> {
|
||||
asciiCity(): React.ReactNode {
|
||||
const LocationLetter = (location: LocationName): JSX.Element => {
|
||||
if (location)
|
||||
return (
|
||||
<span
|
||||
key={location}
|
||||
className="tooltip"
|
||||
style={{
|
||||
color: "white",
|
||||
whiteSpace: "nowrap",
|
||||
margin: "0px",
|
||||
padding: "0px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={this.props.enterLocation.bind(this, location)}
|
||||
>
|
||||
<b>X</b>
|
||||
</span>
|
||||
);
|
||||
return <span>*</span>;
|
||||
};
|
||||
|
||||
const locationLettersRegex = /[A-Z]/g;
|
||||
const letterMap: any = {
|
||||
A: 0,
|
||||
B: 1,
|
||||
C: 2,
|
||||
D: 3,
|
||||
E: 4,
|
||||
F: 5,
|
||||
G: 6,
|
||||
H: 7,
|
||||
I: 8,
|
||||
J: 9,
|
||||
K: 10,
|
||||
L: 11,
|
||||
M: 12,
|
||||
N: 13,
|
||||
O: 14,
|
||||
P: 15,
|
||||
Q: 16,
|
||||
R: 17,
|
||||
S: 18,
|
||||
T: 19,
|
||||
U: 20,
|
||||
V: 21,
|
||||
W: 22,
|
||||
X: 23,
|
||||
Y: 24,
|
||||
Z: 25,
|
||||
};
|
||||
|
||||
const lineElems = (s: string): JSX.Element[] => {
|
||||
const elems: any[] = [];
|
||||
const matches: any[] = [];
|
||||
let match: any;
|
||||
while ((match = locationLettersRegex.exec(s)) !== null) {
|
||||
matches.push(match);
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
elems.push(s);
|
||||
return elems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const startI = i === 0 ? 0 : matches[i - 1].index + 1;
|
||||
const endI = matches[i].index;
|
||||
elems.push(s.slice(startI, endI));
|
||||
const locationI = letterMap[s[matches[i].index]];
|
||||
elems.push(LocationLetter(this.props.city.locations[locationI]));
|
||||
}
|
||||
elems.push(s.slice(matches[matches.length - 1].index + 1));
|
||||
return elems;
|
||||
};
|
||||
|
||||
const elems: JSX.Element[] = [];
|
||||
const lines = this.props.city.asciiArt.split("\n");
|
||||
for (const i in lines) {
|
||||
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>);
|
||||
}
|
||||
|
||||
return <div className="noselect">{elems}</div>;
|
||||
}
|
||||
|
||||
listCity(): React.ReactNode {
|
||||
const locationButtons = this.props.city.locations.map((locName) => {
|
||||
return (
|
||||
<li key={locName}>
|
||||
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} />
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return <ul>{locationButtons}</ul>;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return <>{Settings.DisableASCIIArt ? this.listCity() : this.asciiCity()}</>;
|
||||
function toLocation(router: IRouter, location: Location): void {
|
||||
if (location.name === LocationName.TravelAgency) {
|
||||
router.toTravel();
|
||||
} else if (location.name === LocationName.WorldStockExchange) {
|
||||
router.toStockMarket();
|
||||
} else {
|
||||
router.toLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
function LocationLetter(location: Location): React.ReactElement {
|
||||
const router = use.Router();
|
||||
if (!location) return <span>*</span>;
|
||||
return (
|
||||
<span
|
||||
key={location.name}
|
||||
className="tooltip"
|
||||
style={{
|
||||
color: "white",
|
||||
whiteSpace: "nowrap",
|
||||
margin: "0px",
|
||||
padding: "0px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => toLocation(router, location)}
|
||||
>
|
||||
<b>X</b>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function ASCIICity(props: IProps): React.ReactElement {
|
||||
const locationLettersRegex = /[A-Z]/g;
|
||||
const letterMap: any = {
|
||||
A: 0,
|
||||
B: 1,
|
||||
C: 2,
|
||||
D: 3,
|
||||
E: 4,
|
||||
F: 5,
|
||||
G: 6,
|
||||
H: 7,
|
||||
I: 8,
|
||||
J: 9,
|
||||
K: 10,
|
||||
L: 11,
|
||||
M: 12,
|
||||
N: 13,
|
||||
O: 14,
|
||||
P: 15,
|
||||
Q: 16,
|
||||
R: 17,
|
||||
S: 18,
|
||||
T: 19,
|
||||
U: 20,
|
||||
V: 21,
|
||||
W: 22,
|
||||
X: 23,
|
||||
Y: 24,
|
||||
Z: 25,
|
||||
};
|
||||
|
||||
const lineElems = (s: string): JSX.Element[] => {
|
||||
const elems: any[] = [];
|
||||
const matches: any[] = [];
|
||||
let match: any;
|
||||
while ((match = locationLettersRegex.exec(s)) !== null) {
|
||||
matches.push(match);
|
||||
}
|
||||
if (matches.length === 0) {
|
||||
elems.push(s);
|
||||
return elems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const startI = i === 0 ? 0 : matches[i - 1].index + 1;
|
||||
const endI = matches[i].index;
|
||||
elems.push(s.slice(startI, endI));
|
||||
const locationI = letterMap[s[matches[i].index]];
|
||||
elems.push(LocationLetter(Locations[props.city.locations[locationI]]));
|
||||
}
|
||||
elems.push(s.slice(matches[matches.length - 1].index + 1));
|
||||
return elems;
|
||||
};
|
||||
|
||||
const elems: JSX.Element[] = [];
|
||||
const lines = props.city.asciiArt.split("\n");
|
||||
for (const i in lines) {
|
||||
elems.push(<pre key={i}>{lineElems(lines[i])}</pre>);
|
||||
}
|
||||
|
||||
return <div className="noselect">{elems}</div>;
|
||||
}
|
||||
|
||||
function ListCity(props: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const locationButtons = props.city.locations.map((locName) => {
|
||||
return (
|
||||
<li key={locName}>
|
||||
<StdButton onClick={() => toLocation(router, Locations[locName])} text={locName} />
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return <ul>{locationButtons}</ul>;
|
||||
}
|
||||
|
||||
export function LocationCity(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const city = Cities[player.city];
|
||||
return (
|
||||
<div className="noselect">
|
||||
<h2>{city.name}</h2>
|
||||
{Settings.DisableASCIIArt ? <ListCity city={city} /> : <ASCIICity city={city} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
|
||||
if (!loc.infiltrationData)
|
||||
throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`);
|
||||
|
||||
router.toInfiltration(props.locName);
|
||||
router.toInfiltration(loc);
|
||||
}
|
||||
|
||||
function work(e: React.MouseEvent<HTMLElement>): void {
|
||||
|
||||
@@ -22,7 +22,6 @@ import { CityName } from "../data/CityNames";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
@@ -30,92 +29,73 @@ import { getServer, isBackdoorInstalled } from "../../Server/ServerHelpers";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
returnToCity: () => void;
|
||||
travel: (to: CityName) => void;
|
||||
};
|
||||
|
||||
export class GenericLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
}
|
||||
|
||||
export function GenericLocation({ loc }: IProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const player = use.Player();
|
||||
/**
|
||||
* Determine what needs to be rendered for this location based on the locations
|
||||
* type. Returns an array of React components that should be rendered
|
||||
*/
|
||||
getLocationSpecificContent(): React.ReactNode[] {
|
||||
function getLocationSpecificContent(): React.ReactNode[] {
|
||||
const content: React.ReactNode[] = [];
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Company)) {
|
||||
content.push(<CompanyLocation key={"companylocation"} locName={this.props.loc.name} />);
|
||||
if (loc.types.includes(LocationType.Company)) {
|
||||
content.push(<CompanyLocation key={"companylocation"} locName={loc.name} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key={"gymlocation"} loc={this.props.loc} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Gym)) {
|
||||
content.push(<GymLocation key={"gymlocation"} loc={loc} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key={"hospitallocation"} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Hospital)) {
|
||||
content.push(<HospitalLocation key={"hospitallocation"} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Slums)) {
|
||||
if (loc.types.includes(LocationType.Slums)) {
|
||||
content.push(<SlumsLocation key={"slumslocation"} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Special)) {
|
||||
content.push(<SpecialLocation key={"speciallocation"} loc={this.props.loc} />);
|
||||
if (loc.types.includes(LocationType.Special)) {
|
||||
content.push(<SpecialLocation key={"speciallocation"} loc={loc} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key={"techvendorlocation"} loc={this.props.loc} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.TechVendor)) {
|
||||
content.push(<TechVendorLocation key={"techvendorlocation"} loc={loc} p={player} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyRoot key={"travelagencylocation"} p={this.props.p} router={this.props.router} />);
|
||||
if (loc.types.includes(LocationType.TravelAgency)) {
|
||||
content.push(<TravelAgencyRoot key={"travelagencylocation"} p={player} router={router} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key={"universitylocation"} loc={this.props.loc} />);
|
||||
if (loc.types.includes(LocationType.University)) {
|
||||
content.push(<UniversityLocation key={"universitylocation"} loc={loc} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key={"casinoLocation"} p={this.props.p} />);
|
||||
if (loc.types.includes(LocationType.Casino)) {
|
||||
content.push(<CasinoLocation key={"casinoLocation"} p={player} />);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
|
||||
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||
const server = getServer(ip);
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
const locContent: React.ReactNode[] = getLocationSpecificContent();
|
||||
const ip = SpecialServerIps.getIp(loc.name);
|
||||
const server = getServer(ip);
|
||||
const backdoorInstalled = server !== null && isBackdoorInstalled(server);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
|
||||
<h1 className="noselect">
|
||||
{backdoorInstalled && !Settings.DisableTextEffects ? (
|
||||
<CorruptableText content={this.props.loc.name} />
|
||||
) : (
|
||||
this.props.loc.name
|
||||
)}
|
||||
</h1>
|
||||
{locContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={() => router.toCity()} style={{ display: "block" }} text={"Return to World"} />
|
||||
<h1 className="noselect">
|
||||
{backdoorInstalled && !Settings.DisableTextEffects ? <CorruptableText content={loc.name} /> : loc.name}
|
||||
</h1>
|
||||
{locContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/**
|
||||
* Root React Component for displaying overall Location UI
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { LocationCity } from "./City";
|
||||
import { GenericLocation } from "./GenericLocation";
|
||||
|
||||
import { Cities } from "../Cities";
|
||||
import { Locations } from "../Locations";
|
||||
import { LocationType } from "../LocationTypeEnum";
|
||||
|
||||
import { CityName } from "../data/CityNames";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
type IProps = {
|
||||
initiallyInCity?: boolean;
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
city: CityName;
|
||||
inCity: boolean;
|
||||
location: LocationName;
|
||||
};
|
||||
|
||||
export class LocationRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
city: props.p.city,
|
||||
inCity: props.initiallyInCity == null ? true : props.initiallyInCity,
|
||||
location: props.p.location,
|
||||
};
|
||||
|
||||
this.enterLocation = this.enterLocation.bind(this);
|
||||
this.returnToCity = this.returnToCity.bind(this);
|
||||
this.travel = this.travel.bind(this);
|
||||
}
|
||||
|
||||
enterLocation(to: LocationName): void {
|
||||
if (to == LocationName.TravelAgency) {
|
||||
this.props.router.toTravel();
|
||||
return;
|
||||
}
|
||||
this.props.p.gotoLocation(to);
|
||||
this.setState({
|
||||
inCity: false,
|
||||
location: to,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Click listener for a button that lets the player go from a specific location
|
||||
* back to the city
|
||||
*/
|
||||
returnToCity(): void {
|
||||
this.setState({
|
||||
inCity: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI for a city
|
||||
*/
|
||||
renderCity(): React.ReactNode {
|
||||
const city = Cities[this.state.city];
|
||||
if (city == null) {
|
||||
throw new Error(`Invalid city when rendering UI: ${this.state.city}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="noselect">
|
||||
<h2>{this.state.city}</h2>
|
||||
<LocationCity city={city} enterLocation={this.enterLocation} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render UI for a specific location
|
||||
*/
|
||||
renderLocation(): React.ReactNode {
|
||||
const loc = Locations[this.state.location];
|
||||
|
||||
if (loc == null) {
|
||||
throw new Error(`Invalid location when rendering UI: ${this.state.location}`);
|
||||
}
|
||||
|
||||
if (loc.types.includes(LocationType.StockMarket)) {
|
||||
setTimeout(() => this.props.router.toStockMarket(), 50);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<GenericLocation
|
||||
engine={this.props.engine}
|
||||
router={this.props.router}
|
||||
loc={loc}
|
||||
p={this.props.p}
|
||||
returnToCity={this.returnToCity}
|
||||
travel={this.travel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Travel to a different city
|
||||
* @param {CityName} to - Destination city
|
||||
*/
|
||||
travel(to: CityName): void {
|
||||
const p = this.props.p;
|
||||
const cost = CONSTANTS.TravelCost;
|
||||
if (!p.canAfford(cost)) {
|
||||
dialogBoxCreate(`You cannot afford to travel to ${to}`);
|
||||
return;
|
||||
}
|
||||
|
||||
p.loseMoney(cost);
|
||||
p.travel(to);
|
||||
dialogBoxCreate(<span className="noselect">You are now in {to}!</span>);
|
||||
|
||||
// Dynamically update main menu
|
||||
if (p.firstTimeTraveled === false) {
|
||||
p.firstTimeTraveled = true;
|
||||
const travelTab = document.getElementById("travel-tab");
|
||||
const worldHeader = document.getElementById("world-menu-header");
|
||||
if (travelTab != null && worldHeader !== null) {
|
||||
travelTab.style.display = "list-item";
|
||||
worldHeader.click();
|
||||
worldHeader.click();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.p.travel(to)) {
|
||||
this.setState({
|
||||
inCity: true,
|
||||
city: to,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.state.inCity) {
|
||||
return this.renderCity();
|
||||
} else {
|
||||
return this.renderLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user