bitburner-src/src/Locations/ui/Root.tsx
2021-09-04 19:09:30 -04:00

155 lines
3.6 KiB
TypeScript

/**
* Root React Component for displaying overall Location UI
*/
import * as React from "react";
import { LocationCity } from "./City";
import { GenericLocation } from "./GenericLocation";
import { Cities } from "../Cities";
import { Locations } from "../Locations";
import { LocationType } from "../LocationTypeEnum";
import { CityName } from "../data/CityNames";
import { LocationName } from "../data/LocationNames";
import { CONSTANTS } from "../../Constants";
import { IEngine } from "../../IEngine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
initiallyInCity?: boolean;
engine: IEngine;
p: IPlayer;
};
type IState = {
city: CityName;
inCity: boolean;
location: LocationName;
};
export class LocationRoot extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
city: props.p.city,
inCity: props.initiallyInCity == null ? true : props.initiallyInCity,
location: props.p.location,
};
this.enterLocation = this.enterLocation.bind(this);
this.returnToCity = this.returnToCity.bind(this);
this.travel = this.travel.bind(this);
}
enterLocation(to: LocationName): void {
this.props.p.gotoLocation(to);
this.setState({
inCity: false,
location: to,
});
}
/**
* Click listener for a button that lets the player go from a specific location
* back to the city
*/
returnToCity(): void {
this.setState({
inCity: true,
});
}
/**
* Render UI for a city
*/
renderCity(): React.ReactNode {
const city = Cities[this.state.city];
if (city == null) {
throw new Error(`Invalid city when rendering UI: ${this.state.city}`);
}
return (
<div className="noselect">
<h2>{this.state.city}</h2>
<LocationCity city={city} enterLocation={this.enterLocation} />
</div>
);
}
/**
* Render UI for a specific location
*/
renderLocation(): React.ReactNode {
const loc = Locations[this.state.location];
if (loc == null) {
throw new Error(
`Invalid location when rendering UI: ${this.state.location}`,
);
}
if (loc.types.includes(LocationType.StockMarket)) {
this.props.engine.loadStockMarketContent();
}
return (
<GenericLocation
engine={this.props.engine}
loc={loc}
p={this.props.p}
returnToCity={this.returnToCity}
travel={this.travel}
/>
);
}
/**
* Travel to a different city
* @param {CityName} to - Destination city
*/
travel(to: CityName): void {
const p = this.props.p;
const cost = CONSTANTS.TravelCost;
if (!p.canAfford(cost)) {
dialogBoxCreate(`You cannot afford to travel to ${to}`);
return;
}
p.loseMoney(cost);
p.travel(to);
dialogBoxCreate(<span className="noselect">You are now in {to}!</span>);
// Dynamically update main menu
if (p.firstTimeTraveled === false) {
p.firstTimeTraveled = true;
const travelTab = document.getElementById("travel-tab");
const worldHeader = document.getElementById("world-menu-header");
if (travelTab != null && worldHeader !== null) {
travelTab.style.display = "list-item";
worldHeader.click();
worldHeader.click();
}
}
if (this.props.p.travel(to)) {
this.setState({
inCity: true,
city: to,
});
}
}
render(): React.ReactNode {
if (this.state.inCity) {
return this.renderCity();
} else {
return this.renderLocation();
}
}
}