Began creating 'parent' components for the City and Location-specific parts of the UI

This commit is contained in:
danielyxie
2019-03-29 00:12:41 -07:00
parent 75bc34208c
commit 7172f4e527
16 changed files with 551 additions and 344 deletions
+4 -3
View File
@@ -2,6 +2,7 @@
* Map of all Cities in the game
* Key = City Name, Value = City object
*/
export interface IMetadata = {
name: string;
}
import { City } from "./City";
import { IMap } from "../types";
export const Cities: IMap<City> = {};
+7 -3
View File
@@ -1,22 +1,26 @@
/**
* Class representing a City in the game
*/
import { Location } from "./Location";
import { CityName } from "./data/CityNames";
import { LocationName } from "./data/LocationNames";
export class City {
/**
* List of all locations in this city
*/
locations: Location[];
locations: LocationName[];
/**
* Name of this city
*/
name: CityName;
constructor(name: CityName, locations: Location[]) {
constructor(name: CityName, locations: LocationName[]=[]) {
this.name = name;
this.locations = locations;
}
addLocation(loc: LocationName): void {
this.locations.push(loc);
}
}
+23 -8
View File
@@ -10,29 +10,44 @@ export interface IConstructorParams {
name?: LocationName;
types?: LocationType[];
techVendorMaxRam?: number;
techVendorMinRam?: number;
}
export class Location {
// Name of city this location is in
// If this property is null, it means this is a generic Location that
// is available in all cities
/**
* Name of city this location is in. If this property is null, it means this i
* is a generic location that is available in all cities
*/
city: CityName | null = null;
// Identifier for location
/**
* Identifier for location
*/
name: LocationName = LocationName.Void;
// List of what type(s) this location is
// A location can be multiple types (e.g. company and tech vendor)
/**
* List of what type(s) this location is. A location can be multiple types
* (e.g. company and tech vendor)
*/
types: LocationType[] = [];
// Tech vendors allow you to purchase servers.
// This property defines the max RAM server you can purchase from this vendor
/**
* Tech vendors allow you to purchase servers.
* This property defines the max RAM server you can purchase from this vendor
*/
techVendorMaxRam: number = 0;
/**
* Tech vendors allow you to purchase servers.
* This property defines the max RAM server you can purchase from this vendor
*/
techVendorMinRam: number = 0;
constructor(p: IConstructorParams) {
if (p.city) { this.city = p.city; }
if (p.name) { this.name = p.name; }
if (p.types) { this.types = p.types; }
if (p.techVendorMaxRam) { this.techVendorMaxRam = p.techVendorMaxRam; }
if (p.techVendorMinRam) { this.techVendorMinRam = p.techVendorMinRam; }
}
}
+1 -1
View File
@@ -2,11 +2,11 @@
* Enum defining the different types of possible locations
*/
export enum LocationType {
CityHall,
Company,
Gym,
Hospital,
Slums,
Special, // This location has special options/activities (e.g. Bladeburner, Re-sleeving)
StockMarket,
TechVendor,
TravelAgency,
+34 -5
View File
@@ -2,15 +2,23 @@
* Map of all Locations in the game
* Key = Location name, value = Location object
*/
import { City } from "./City";
import { Cities } from "./Cities";
import { Location,
IConstructorParams } from "./Location";
import { LocationsMetadata } from "./data/LocationsMetadata";
IConstructorParams } from "./Location";
import { CityName } from "./data/CityNames";
import { LocationsMetadata } from "./data/LocationsMetadata";
import { IMap } from "../types";
export const Locations: IMap<Location> = {};
function constructLocation(p: IConstructorParams) {
/**
* Here, we'll initialize both Locations and Cities data. These can both
* be initialized from the `LocationsMetadata`
*/
function constructLocation(p: IConstructorParams): Location {
if (!p.name) {
throw new Error(`Invalid constructor parameters for Location. No 'name' property`);
}
@@ -20,8 +28,29 @@ function constructLocation(p: IConstructorParams) {
}
Locations[p.name] = new Location(p);
return Locations[p.name];
}
for (const metadata of LocationsMetadata {
constructLocation(metadata);
// First construct all cities
Cities[CityName.Aevum] = new City(CityName.Aevum);
Cities[CityName.Chongqing] = new City(CityName.Chongqing);
Cities[CityName.Ishima] = new City(CityName.Ishima);
Cities[CityName.NewTokyo] = new City(CityName.NewTokyo);
Cities[CityName.Sector12] = new City(CityName.Sector12);
Cities[CityName.Volhaven] = new City(CityName.Volhaven);
// Then construct all locations, and add them to the cities as we go.
for (const metadata of LocationsMetadata) {
const loc = constructLocation(metadata);
const cityName = loc.city;
if (cityName === null) {
// Generic location, add to all cities
for (const city in Cities) {
Cities[city].addLocation(loc.name);
}
} else {
Cities[cityName].addLocation(loc.name);
}
}
+1
View File
@@ -0,0 +1 @@
import { Player } from "../Player";
+69 -103
View File
@@ -5,312 +5,278 @@
import { CityName } from "./CityNames";
import { LocationName } from "./LocationNames";
import { IConstructorParams } from "../Location";
import { LocationType } from "../LocationTypeEnum";
export const LocationsMetadata: IConstructorParams[] = [
{
city: CityName.Aevum,
name: LocationName.AevumAeroCorp,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumBachmanAndAssociates,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumClarkeIncorporated,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumCrushFitnessGym,
types:
techVendorMaxRam:
types: [LocationType.Gym],
},
{
city: CityName.Aevum,
name: LocationName.AevumECorp,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 512,
techVendorMinRam: 128,
},
{
city: CityName.Aevum,
name: LocationName.AevumFulcrumTechnologies,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 1024,
techVendorMinRam: 256,
},
{
city: CityName.Aevum,
name: LocationName.AevumGalacticCybersystems,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumNetLinkTechnologies
types:
techVendorMaxRam:
name: LocationName.AevumNetLinkTechnologies,
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 64,
techVendorMinRam: 8,
},
{
city: CityName.Aevum,
name: LocationName.AevumPolice,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumRhoConstruction,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Aevum,
name: LocationName.AevumSnapFitnessGym,
types:
techVendorMaxRam:
types: [LocationType.Gym],
},
{
city: CityName.Aevum,
name: LocationName.AevumSummitUniversity,
types:
techVendorMaxRam:
types: [LocationType.University],
},
{
city: CityName.Aevum,
name: LocationName.AevumWatchdogSecurity,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Chongqing,
name: LocationName.ChongqingKuaiGongInternational,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Chongqing,
name: LocationName.ChongqingSolarisSpaceSystems,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Ishima,
name: LocationName.IshimaNovaMedical,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Ishima,
name: LocationName.IshimaOmegaSoftware,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 128,
techVendorMinRam: 4,
},
{
city: CityName.Ishima,
name: LocationName.IshimaStormTechnologies,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 512,
techVendorMinRam: 32,
},
{
city: CityName.NewTokyo,
name: LocationName.NewTokyoDefComm,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
name: LocationName.NewTokyoGlobalPharmaceuticals,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
name: LocationName.NewTokyoNoodleBar,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.NewTokyo,
name: LocationName.NewTokyoVitaLife,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.Special],
},
{
city: CityName.Sector12,
name: LocationName.Sector12AlphaEnterprises,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 8,
techVendorMinRam: 2,
},
{
city: CityName.Sector12,
name: LocationName.Sector12BladeIndustries,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12CIA,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12CarmichaelSecurity,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12CityHall,
types:
techVendorMaxRam:
types: [LocationType.Special],
},
{
city: CityName.Sector12,
name: LocationName.Sector12DeltaOne,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12FoodNStuff,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12FourSigma,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12IcarusMicrosystems,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12IronGym,
types:
techVendorMaxRam:
types: [LocationType.Gym],
},
{
city: CityName.Sector12,
name: LocationName.Sector12JoesGuns,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12MegaCorp,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Sector12,
name: LocationName.Sector12NSA,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.Special],
},
{
city: CityName.Sector12,
name: LocationName.Sector12PowerhouseGym,
types:
techVendorMaxRam:
types: [LocationType.Gym],
},
{
city: CityName.Sector12,
name: LocationName.Sector12RothmanUniversity,
types:
techVendorMaxRam:
types: [LocationType.University],
},
{
city: CityName.Sector12,
name: LocationName.Sector12UniversalEnergy,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenCompuTek,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 256,
techVendorMinRam: 8,
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenHeliosLabs,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenLexoCorp,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenMilleniumFitnessGym,
types:
techVendorMaxRam:
types: [LocationType.Gym],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenNWO,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenOmniTekIncorporated,
types:
techVendorMaxRam:
types: [LocationType.Company, LocationType.TechVendor],
techVendorMaxRam: 1024,
techVendorMinRam: 128,
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenOmniaCybersystems,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenSysCoreSecurities,
types:
techVendorMaxRam:
types: [LocationType.Company],
},
{
city: CityName.Volhaven,
name: LocationName.VolhavenZBInstituteOfTechnology,
types:
techVendorMaxRam:
types: [LocationType.University],
},
{
city: null,
name: LocationName.Hospital,
types:
techVendorMaxRam:
types: [LocationType.Hospital],
},
{
city: null,
name: LocationName.Slums,
types:
techVendorMaxRam:
types: [LocationType.Slums],
},
{
city: null,
name: LocationName.TravelAgency,
types:
techVendorMaxRam:
types: [LocationType.TravelAgency],
},
{
city: null,
name: LocationName.WorldStockExchange,
types:
techVendorMaxRam:
types: [LocationType.StockMarket],
},
];
+34
View File
@@ -0,0 +1,34 @@
/**
* React Component for displaying a City's UI.
* This UI shows all of the available locations in the city, and lets the player
* visit those locations
*/
import * as React from "react";
import { City } from "../City";
import { LocationName } from "../data/LocationNames";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
city: City;
enterLocation: (to: LocationName) => void;
}
export class LocationCity extends React.Component<IProps, any> {
render() {
const locationButtons = this.props.city.locations.map((locName) => {
return (
<li>
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} key={locName} />
</li>
)
});
return (
<ul>
{locationButtons}
</ul>
)
}
}
+112
View File
@@ -0,0 +1,112 @@
/**
* React Component for displaying a location's UI, when that location is a company
*/
import * as React from "react";
import { LocationName } from "../data/LocationNames";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
locName: LocationName;
p: IPlayer;
}
export class CompanyLocation extends React.Component<IProps, any> {
/**
* We'll keep a reference to the Company that this component is being rendered for,
* so we don't have to look it up every time
*/
company: Company;
constructor(props: IProps) {
super(props);
this.applyForAgentJob = this.applyForAgentJob.bind(this);
this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this);
this.applyForBusinessJob = this.applyForBusinessJob.bind(this);
this.applyForEmployeeJob = this.applyForEmployeeJob.bind(this);
this.applyForItJob = this.applyForItJob.bind(this);
this.applyForPartTimeEmployeeJob = this.applyForPartTimeEmployeeJob.bind(this);
this.applyForPartTimeWaiterJob = this.applyForPartTimeWaiterJob.bind(this);
this.applyForSecurityJob = this.applyForSecurityJob.bind(this);
this.applyForSoftwareConsultantJob = this.applyForSoftwareConsultantJob.bind(this);
this.applyForSoftwareJob = this.applyForSoftwareJob.bind(this);
this.applyForWaiterJob = this.applyForWaiterJob.bind(this);
this.company = Companies[props.locName];
if (this.company == null) {
throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
}
}
applyForAgentJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForAgentJob();
}
applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessConsultantJob();
}
applyForBusinessJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessJob();
}
applyForEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForEmployeeJob();
}
applyForItJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForItJob();
}
applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeEmployeeJob();
}
applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeWaiterJob();
}
applyForSecurityJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSecurityJob();
}
applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareConsultantJob();
}
applyForSoftwareJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareJob();
}
applyForWaiterJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForWaiterJob();
}
render() {
return (
<div>
{
this.company.hasAgentPositions() &&
<StdButton onClick={this.applyForAgentJob} text={""}
}
</div>
)
}
}
+95
View File
@@ -0,0 +1,95 @@
/**
* React Component for displaying a location's UI
*
* This is a "router" component of sorts, meaning it deduces the type of
* location that is being rendered and then creates the proper component(s) for that.
*/
import * as React from "react";
import { Location } from "../Location";
import { Locations } from "../Locations";
import { LocationType } from "../LocationTypeEnum";
import { LocationName } from "../data/LocationNames";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { StdButton } from "../../ui/React/StdButton";
type IProps = {
locName: LocationName;
p: IPlayer;
returnToCity: () => void;
}
export class GenericLocation extends React.Component<IProps, any> {
/**
* Reference to the Location object that is being rendered
*/
loc: Location;
constructor(props: IProps) {
super(props);
this.loc = Locations[props.locName];
if (this.loc == null) {
throw new Error(`Invalid Location being rendered: ${props.locName}`);
}
}
/**
* 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[] {
const content: React.ReactNode[] = [];
if (this.loc.types.includes(LocationType.Company)) {
}
if (this.loc.types.includes(LocationType.Gym)) {
}
if (this.loc.types.includes(LocationType.Hospital)) {
}
if (this.loc.types.includes(LocationType.Slums)) {
}
if (this.loc.types.includes(LocationType.Special)) {
}
if (this.loc.types.includes(LocationType.StockMarket)) {
}
if (this.loc.types.includes(LocationType.TechVendor)) {
}
if (this.loc.types.includes(LocationType.TravelAgency)) {
}
if (this.loc.types.includes(LocationType.University)) {
}
}
render() {
const locContent: React.ReactNode[] = this.getLocationSpecificContent();
return (
<div>
<StdButton onClick={this.props.returnToCity} text={"Return to world"} />
<br />
<h1>this.loc.name</h1>
{locContent}
</div>
)
}
}
+91
View File
@@ -0,0 +1,91 @@
/**
* Root React Component for displaying overall Location UI
*/
import * as React from "react";
import { LocationCity } from "./City";
import { CityName } from "../data/CityNames";
import { LocationName } from "../data/LocationNames";
import { IPlayer } from "../../PersonObjects/IPlayer";
type IProps = {
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: true,
location: props.p.location,
}
this.changeCity = this.changeCity.bind(this);
this.returnToCity = this.returnToCity.bind(this);
}
changeCity(to: CityName): void {
if (this.props.p.travel(to)) {
this.setState({
city: to
});
}
}
enterLocation(to: LocationName): void {
this.props.p.location = 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 {
return (
<div>
<h2>{this.state.city}</h2>
<LocationCity city={this.state.city} enterLocation={this.enterLocation} />
</div>
)
}
/**
* Render UI for a specific location
*/
renderLocation(): React.ReactNode {
return (
<GenericLocation />
)
}
render() {
if (this.state.inCity) {
return this.renderCity();
} else {
return this.renderLocation();
}
}
}