From 75bc34208c84857f8b4c83542784d15db1debb0f Mon Sep 17 00:00:00 2001 From: danielyxie Date: Wed, 27 Mar 2019 01:31:47 -0700 Subject: [PATCH 1/4] Initial commit for Location Code refactor --- src/Corporation/Product.ts | 2 +- src/Corporation/ui/MainPanel.jsx | 4 +- src/Locations.ts | 90 ------- src/Locations/Cities.ts | 17 +- src/Locations/City.ts | 22 ++ src/Locations/Location.ts | 38 +++ src/Locations/LocationTypeEnum.ts | 14 ++ src/Locations/Locations.ts | 27 ++ src/Locations/data/CityNames.ts | 12 + src/Locations/data/LocationNames.ts | 92 +++++++ src/Locations/data/LocationsMetadata.ts | 316 ++++++++++++++++++++++++ src/PersonObjects/Person.ts | 4 +- src/PersonObjects/Sleeve/Sleeve.ts | 20 +- 13 files changed, 541 insertions(+), 117 deletions(-) delete mode 100644 src/Locations.ts create mode 100644 src/Locations/City.ts create mode 100644 src/Locations/Location.ts create mode 100644 src/Locations/LocationTypeEnum.ts create mode 100644 src/Locations/Locations.ts create mode 100644 src/Locations/data/CityNames.ts create mode 100644 src/Locations/data/LocationNames.ts create mode 100644 src/Locations/data/LocationsMetadata.ts diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index 6f8524e62..1afda5b57 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -3,7 +3,7 @@ import { MaterialSizes } from "./MaterialSizes"; import { ProductRatingWeights, IProductRatingWeight } from "./ProductRatingWeights"; -import { Cities } from "../Locations/Cities"; +import { CityName } from "../Locations/data/CityNames"; import { IMap } from "../types"; import { Generic_fromJSON, diff --git a/src/Corporation/ui/MainPanel.jsx b/src/Corporation/ui/MainPanel.jsx index f67827feb..d22c9a869 100644 --- a/src/Corporation/ui/MainPanel.jsx +++ b/src/Corporation/ui/MainPanel.jsx @@ -11,7 +11,7 @@ import { overviewPage } from "./Routing"; import { OfficeSpace } from "../Corporation"; -import { Cities } from "../../Locations/Cities"; +import { CityName } from "../../Locations/data/Cities"; export class MainPanel extends BaseReactComponent { constructor(props) { @@ -19,7 +19,7 @@ export class MainPanel extends BaseReactComponent { this.state = { division: "", - city: Cities.Sector12, + city: CityName.Sector12, } } diff --git a/src/Locations.ts b/src/Locations.ts deleted file mode 100644 index 35477941e..000000000 --- a/src/Locations.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { IMap } from "./types"; - -/** - * Display Location Content when visiting somewhere in the World - */ -// tslint:disable-next-line:variable-name -export const Locations: IMap = { - // Cities - Aevum: "Aevum", - Chongqing: "Chongqing", - Ishima: "Ishima", - NewTokyo: "New Tokyo", - Sector12: "Sector-12", - Volhaven: "Volhaven", - - // Aevum Locations - AevumAeroCorp: "AeroCorp", - AevumBachmanAndAssociates: "Bachman & Associates", - AevumClarkeIncorporated: "Clarke Incorporated", - AevumCrushFitnessGym: "Crush Fitness Gym", - AevumECorp: "ECorp", - AevumFulcrumTechnologies: "Fulcrum Technologies", - AevumGalacticCybersystems: "Galactic Cybersystems", - AevumNetLinkTechnologies: "NetLink Technologies", - AevumPolice: "Aevum Police Headquarters", - AevumRhoConstruction: "Rho Construction", - AevumSlums: "Aevum Slums", - AevumSnapFitnessGym: "Snap Fitness Gym", - AevumSummitUniversity: "Summit University", - AevumTravelAgency: "Aevum Travel Agency", - AevumWatchdogSecurity: "Watchdog Security", - - // Chongqing locations - ChongqingKuaiGongInternational: "KuaiGong International", - ChongqingSlums: "Chongqing Slums", - ChongqingSolarisSpaceSystems: "Solaris Space Systems", - ChongqingTravelAgency: "Chongqing Travel Agency", - - // Sector 12 - Sector12AlphaEnterprises: "Alpha Enterprises", - Sector12BladeIndustries: "Blade Industries", - Sector12CIA: "Central Intelligence Agency", - Sector12CarmichaelSecurity: "Carmichael Security", - Sector12CityHall: "Sector-12 City Hall", - Sector12DeltaOne: "DeltaOne", - Sector12FoodNStuff: "FoodNStuff", - Sector12FourSigma: "Four Sigma", - Sector12IcarusMicrosystems: "Icarus Microsystems", - Sector12IronGym: "Iron Gym", - Sector12JoesGuns: "Joe's Guns", - Sector12MegaCorp: "MegaCorp", - Sector12NSA: "National Security Agency", - Sector12PowerhouseGym: "Powerhouse Gym", - Sector12RothmanUniversity: "Rothman University", - Sector12Slums: "Sector-12 Slums", - Sector12TravelAgency: "Sector-12 Travel Agency", - Sector12UniversalEnergy: "Universal Energy", - - // New Tokyo - NewTokyoDefComm: "DefComm", - NewTokyoGlobalPharmaceuticals: "Global Pharmaceuticals", - NewTokyoNoodleBar: "Noodle Bar", - NewTokyoSlums: "New Tokyo Slums", - NewTokyoTravelAgency: "New Tokyo Travel Agency", - NewTokyoVitaLife: "VitaLife", - - // Ishima - IshimaNovaMedical: "Nova Medical", - IshimaOmegaSoftware: "Omega Software", - IshimaSlums: "Ishima Slums", - IshimaStormTechnologies: "Storm Technologies", - IshimaTravelAgency: "Ishima Travel Agency", - - // Volhaven - VolhavenCompuTek: "CompuTek", - VolhavenHeliosLabs: "Helios Labs", - VolhavenLexoCorp: "LexoCorp", - VolhavenMilleniumFitnessGym: "Millenium Fitness Gym", - VolhavenNWO: "NWO", - VolhavenOmniTekIncorporated: "OmniTek Incorporated", - VolhavenOmniaCybersystems: "Omnia Cybersystems", - VolhavenSlums: "Volhaven Slums", - VolhavenSysCoreSecurities: "SysCore Securities", - VolhavenTravelAgency: "Volhaven Travel Agency", - VolhavenZBInstituteOfTechnology: "ZB Institute of Technology", - - // Generic locations - Hospital: "Hospital", - WorldStockExchange: "World Stock Exchange", -}; diff --git a/src/Locations/Cities.ts b/src/Locations/Cities.ts index 660c29a47..fc138ad25 100644 --- a/src/Locations/Cities.ts +++ b/src/Locations/Cities.ts @@ -1,14 +1,7 @@ -import { IMap } from "../types"; - /** - * Display Location Content when visiting somewhere in the World + * Map of all Cities in the game + * Key = City Name, Value = City object */ -// tslint:disable-next-line:variable-name -export const Cities: IMap = { - Aevum: "Aevum", - Chongqing: "Chongqing", - Ishima: "Ishima", - NewTokyo: "New Tokyo", - Sector12: "Sector-12", - Volhaven: "Volhaven", -}; +export interface IMetadata = { + name: string; +} diff --git a/src/Locations/City.ts b/src/Locations/City.ts new file mode 100644 index 000000000..14aae4a7c --- /dev/null +++ b/src/Locations/City.ts @@ -0,0 +1,22 @@ +/** + * Class representing a City in the game + */ +import { Location } from "./Location"; +import { CityName } from "./data/CityNames"; + +export class City { + /** + * List of all locations in this city + */ + locations: Location[]; + + /** + * Name of this city + */ + name: CityName; + + constructor(name: CityName, locations: Location[]) { + this.name = name; + this.locations = locations; + } +} diff --git a/src/Locations/Location.ts b/src/Locations/Location.ts new file mode 100644 index 000000000..3cc97609c --- /dev/null +++ b/src/Locations/Location.ts @@ -0,0 +1,38 @@ +/** + * Class representing a visitable location in the world + */ +import { CityName } from "./data/CityNames"; +import { LocationName } from "./data/LocationNames"; +import { LocationType } from "./LocationTypeEnum"; + +export interface IConstructorParams { + city?: CityName | null; + name?: LocationName; + types?: LocationType[]; + techVendorMaxRam?: 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 + city: CityName | null = null; + + // 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) + types: LocationType[] = []; + + // Tech vendors allow you to purchase servers. + // This property defines the max RAM server you can purchase from this vendor + techVendorMaxRam: 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; } + } +} diff --git a/src/Locations/LocationTypeEnum.ts b/src/Locations/LocationTypeEnum.ts new file mode 100644 index 000000000..ddfeafbce --- /dev/null +++ b/src/Locations/LocationTypeEnum.ts @@ -0,0 +1,14 @@ +/** + * Enum defining the different types of possible locations + */ +export enum LocationType { + CityHall, + Company, + Gym, + Hospital, + Slums, + StockMarket, + TechVendor, + TravelAgency, + University, +} diff --git a/src/Locations/Locations.ts b/src/Locations/Locations.ts new file mode 100644 index 000000000..d91095247 --- /dev/null +++ b/src/Locations/Locations.ts @@ -0,0 +1,27 @@ +/** + * Map of all Locations in the game + * Key = Location name, value = Location object + */ +import { Location, + IConstructorParams } from "./Location"; +import { LocationsMetadata } from "./data/LocationsMetadata"; + +import { IMap } from "../types"; + +export const Locations: IMap = {}; + +function constructLocation(p: IConstructorParams) { + if (!p.name) { + throw new Error(`Invalid constructor parameters for Location. No 'name' property`); + } + + if (Locations[p.name] instanceof Location) { + console.warn(`Property with name ${p.name} already exists and is being overwritten`); + } + + Locations[p.name] = new Location(p); +} + +for (const metadata of LocationsMetadata { + constructLocation(metadata); +} diff --git a/src/Locations/data/CityNames.ts b/src/Locations/data/CityNames.ts new file mode 100644 index 000000000..8b02aa2a5 --- /dev/null +++ b/src/Locations/data/CityNames.ts @@ -0,0 +1,12 @@ +/** + * All possible Cities in the game. Names only, not actual "City" object + * Implemented as an enum for typing purposes + */ +export enum CityName { + Aevum = "Aevum", + Chongqing = "Chongqing", + Ishima = "Ishima", + NewTokyo = "New Tokyo", + Sector12 = "Sector-12", + Volhaven = "Volhaven", +}; diff --git a/src/Locations/data/LocationNames.ts b/src/Locations/data/LocationNames.ts new file mode 100644 index 000000000..af0d56157 --- /dev/null +++ b/src/Locations/data/LocationNames.ts @@ -0,0 +1,92 @@ +/** + * Names of all locations + */ +export enum LocationName { + // Cities + Aevum = "Aevum", + Chongqing = "Chongqing", + Ishima = "Ishima", + NewTokyo = "New Tokyo", + Sector12 = "Sector-12", + Volhaven = "Volhaven", + + // Aevum Locations + AevumAeroCorp = "AeroCorp", + AevumBachmanAndAssociates = "Bachman & Associates", + AevumClarkeIncorporated = "Clarke Incorporated", + AevumCrushFitnessGym = "Crush Fitness Gym", + AevumECorp = "ECorp", + AevumFulcrumTechnologies = "Fulcrum Technologies", + AevumGalacticCybersystems = "Galactic Cybersystems", + AevumNetLinkTechnologies = "NetLink Technologies", + AevumPolice = "Aevum Police Headquarters", + AevumRhoConstruction = "Rho Construction", + AevumSlums = "Aevum Slums", // TODO Delete this and other Slums locations + AevumSnapFitnessGym = "Snap Fitness Gym", + AevumSummitUniversity = "Summit University", + AevumTravelAgency = "Aevum Travel Agency", // TODO Delete this and other travel agency locations + AevumWatchdogSecurity = "Watchdog Security", + + // Chongqing locations + ChongqingKuaiGongInternational = "KuaiGong International", + ChongqingSlums = "Chongqing Slums", + ChongqingSolarisSpaceSystems = "Solaris Space Systems", + ChongqingTravelAgency = "Chongqing Travel Agency", + + // Sector 12 + Sector12AlphaEnterprises = "Alpha Enterprises", + Sector12BladeIndustries = "Blade Industries", + Sector12CIA = "Central Intelligence Agency", + Sector12CarmichaelSecurity = "Carmichael Security", + Sector12CityHall = "Sector-12 City Hall", + Sector12DeltaOne = "DeltaOne", + Sector12FoodNStuff = "FoodNStuff", + Sector12FourSigma = "Four Sigma", + Sector12IcarusMicrosystems = "Icarus Microsystems", + Sector12IronGym = "Iron Gym", + Sector12JoesGuns = "Joe's Guns", + Sector12MegaCorp = "MegaCorp", + Sector12NSA = "National Security Agency", + Sector12PowerhouseGym = "Powerhouse Gym", + Sector12RothmanUniversity = "Rothman University", + Sector12Slums = "Sector-12 Slums", + Sector12TravelAgency = "Sector-12 Travel Agency", + Sector12UniversalEnergy = "Universal Energy", + + // New Tokyo + NewTokyoDefComm = "DefComm", + NewTokyoGlobalPharmaceuticals = "Global Pharmaceuticals", + NewTokyoNoodleBar = "Noodle Bar", + NewTokyoSlums = "New Tokyo Slums", + NewTokyoTravelAgency = "New Tokyo Travel Agency", + NewTokyoVitaLife = "VitaLife", + + // Ishima + IshimaNovaMedical = "Nova Medical", + IshimaOmegaSoftware = "Omega Software", + IshimaSlums = "Ishima Slums", + IshimaStormTechnologies = "Storm Technologies", + IshimaTravelAgency = "Ishima Travel Agency", + + // Volhaven + VolhavenCompuTek = "CompuTek", + VolhavenHeliosLabs = "Helios Labs", + VolhavenLexoCorp = "LexoCorp", + VolhavenMilleniumFitnessGym = "Millenium Fitness Gym", + VolhavenNWO = "NWO", + VolhavenOmniTekIncorporated = "OmniTek Incorporated", + VolhavenOmniaCybersystems = "Omnia Cybersystems", + VolhavenSlums = "Volhaven Slums", + VolhavenSysCoreSecurities = "SysCore Securities", + VolhavenTravelAgency = "Volhaven Travel Agency", + VolhavenZBInstituteOfTechnology = "ZB Institute of Technology", + + // Generic locations + Hospital = "Hospital", + Slums = "The Slums", + TravelAgency = "Travel Agency", + WorldStockExchange = "World Stock Exchange", + + // Default name for Location objects + Void = "The Void", +}; diff --git a/src/Locations/data/LocationsMetadata.ts b/src/Locations/data/LocationsMetadata.ts new file mode 100644 index 000000000..fb8ae03e3 --- /dev/null +++ b/src/Locations/data/LocationsMetadata.ts @@ -0,0 +1,316 @@ +/** + * Metadata for constructing Location objects for all Locations + * in the game + */ +import { CityName } from "./CityNames"; +import { LocationName } from "./LocationNames"; +import { IConstructorParams } from "../Location"; + +export const LocationsMetadata: IConstructorParams[] = [ + { + city: CityName.Aevum, + name: LocationName.AevumAeroCorp, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumBachmanAndAssociates, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumClarkeIncorporated, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumCrushFitnessGym, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumECorp, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumFulcrumTechnologies, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumGalacticCybersystems, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumNetLinkTechnologies + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumPolice, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumRhoConstruction, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumSnapFitnessGym, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumSummitUniversity, + types: + techVendorMaxRam: + }, + { + city: CityName.Aevum, + name: LocationName.AevumWatchdogSecurity, + types: + techVendorMaxRam: + }, + { + city: CityName.Chongqing, + name: LocationName.ChongqingKuaiGongInternational, + types: + techVendorMaxRam: + }, + { + city: CityName.Chongqing, + name: LocationName.ChongqingSolarisSpaceSystems, + types: + techVendorMaxRam: + }, + { + city: CityName.Ishima, + name: LocationName.IshimaNovaMedical, + types: + techVendorMaxRam: + }, + { + city: CityName.Ishima, + name: LocationName.IshimaOmegaSoftware, + types: + techVendorMaxRam: + }, + { + city: CityName.Ishima, + name: LocationName.IshimaStormTechnologies, + types: + techVendorMaxRam: + }, + { + city: CityName.NewTokyo, + name: LocationName.NewTokyoDefComm, + types: + techVendorMaxRam: + }, + { + city: CityName.NewTokyo, + name: LocationName.NewTokyoGlobalPharmaceuticals, + types: + techVendorMaxRam: + }, + { + city: CityName.NewTokyo, + name: LocationName.NewTokyoNoodleBar, + types: + techVendorMaxRam: + }, + { + city: CityName.NewTokyo, + name: LocationName.NewTokyoVitaLife, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12AlphaEnterprises, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12BladeIndustries, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12CIA, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12CarmichaelSecurity, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12CityHall, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12DeltaOne, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12FoodNStuff, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12FourSigma, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12IcarusMicrosystems, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12IronGym, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12JoesGuns, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12MegaCorp, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12NSA, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12PowerhouseGym, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12RothmanUniversity, + types: + techVendorMaxRam: + }, + { + city: CityName.Sector12, + name: LocationName.Sector12UniversalEnergy, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenCompuTek, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenHeliosLabs, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenLexoCorp, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenMilleniumFitnessGym, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenNWO, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenOmniTekIncorporated, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenOmniaCybersystems, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenSysCoreSecurities, + types: + techVendorMaxRam: + }, + { + city: CityName.Volhaven, + name: LocationName.VolhavenZBInstituteOfTechnology, + types: + techVendorMaxRam: + }, + { + city: null, + name: LocationName.Hospital, + types: + techVendorMaxRam: + }, + { + city: null, + name: LocationName.Slums, + types: + techVendorMaxRam: + }, + { + city: null, + name: LocationName.TravelAgency, + types: + techVendorMaxRam: + }, + { + city: null, + name: LocationName.WorldStockExchange, + types: + techVendorMaxRam: + }, +]; diff --git a/src/PersonObjects/Person.ts b/src/PersonObjects/Person.ts index 9bc208a0a..d778989aa 100644 --- a/src/PersonObjects/Person.ts +++ b/src/PersonObjects/Person.ts @@ -3,7 +3,7 @@ import { Augmentation } from "../Augmentation/Augmentation"; import { Augmentations } from "../Augmentation/Augmentations"; import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; -import { Cities } from "../Locations/Cities"; +import { CityName } from "../Locations/data/CityNames"; import { CONSTANTS } from "../Constants"; // Interface that defines a generic object used to track experience/money @@ -105,7 +105,7 @@ export abstract class Person { /** * City that the person is in */ - city: string = Cities.Sector12; + city: string = CityName.Sector12; constructor() {} diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 8e644e2af..a8afb85b8 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -20,7 +20,7 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { Crime } from "../../Crime/Crime"; import { Crimes } from "../../Crime/Crimes"; -import { Cities } from "../../Locations/Cities"; +import { CityName } from "../../Locations/data/CityNames"; import { Companies } from "../../Company/Companies"; import { Company } from "../../Company/Company"; @@ -547,19 +547,19 @@ export class Sleeve extends Person { let expMult: number = 1; switch (universityName.toLowerCase()) { case Locations.AevumSummitUniversity.toLowerCase(): - if (this.city !== Cities.Aevum) { return false; } + if (this.city !== CityName.Aevum) { return false; } this.currentTaskLocation = Locations.AevumSummitUniversity; costMult = 4; expMult = 3; break; case Locations.Sector12RothmanUniversity.toLowerCase(): - if (this.city !== Cities.Sector12) { return false; } + if (this.city !== CityName.Sector12) { return false; } this.currentTaskLocation = Locations.Sector12RothmanUniversity; costMult = 3; expMult = 2; break; case Locations.VolhavenZBInstituteOfTechnology.toLowerCase(): - if (this.city !== Cities.Volhaven) { return false; } + if (this.city !== CityName.Volhaven) { return false; } this.currentTaskLocation = Locations.VolhavenZBInstituteOfTechnology; costMult = 5; expMult = 4; @@ -613,7 +613,7 @@ export class Sleeve extends Person { * Travel to another City. Costs money from player */ travel(p: IPlayer, newCity: string): boolean { - if (Cities[newCity] == null) { + if (CityName[newCity] == null) { console.error(`Invalid city ${newCity} passed into Sleeve.travel()`); return false; } @@ -747,31 +747,31 @@ export class Sleeve extends Person { let expMult: number = 1; switch (gymName.toLowerCase()) { case Locations.AevumCrushFitnessGym.toLowerCase(): - if (this.city != Cities.Aevum) { return false; } + if (this.city != CityName.Aevum) { return false; } this.currentTaskLocation = Locations.AevumCrushFitnessGym; costMult = 3; expMult = 2; break; case Locations.AevumSnapFitnessGym.toLowerCase(): - if (this.city != Cities.Aevum) { return false; } + if (this.city != CityName.Aevum) { return false; } this.currentTaskLocation = Locations.AevumSnapFitnessGym; costMult = 10; expMult = 5; break; case Locations.Sector12IronGym.toLowerCase(): - if (this.city != Cities.Sector12) { return false; } + if (this.city != CityName.Sector12) { return false; } this.currentTaskLocation = Locations.Sector12IronGym; costMult = 1; expMult = 1; break; case Locations.Sector12PowerhouseGym.toLowerCase(): - if (this.city != Cities.Sector12) { return false; } + if (this.city != CityName.Sector12) { return false; } this.currentTaskLocation = Locations.Sector12PowerhouseGym; costMult = 20; expMult = 10; break; case Locations.VolhavenMilleniumFitnessGym: - if (this.city != Cities.Volhaven) { return false; } + if (this.city != CityName.Volhaven) { return false; } this.currentTaskLocation = Locations.VolhavenMilleniumFitnessGym; costMult = 7; expMult = 4; From 7172f4e527ef0d63554a8c835d79d789969c7d9b Mon Sep 17 00:00:00 2001 From: danielyxie Date: Fri, 29 Mar 2019 00:12:41 -0700 Subject: [PATCH 2/4] Began creating 'parent' components for the City and Location-specific parts of the UI --- src/Company/Company.ts | 42 +++- src/{Location.js => LocationHelpers.js} | 0 src/Locations/Cities.ts | 7 +- src/Locations/City.ts | 10 +- src/Locations/Location.ts | 31 ++- src/Locations/LocationTypeEnum.ts | 2 +- src/Locations/Locations.ts | 39 +++- src/Locations/LocationsHelpers.js | 1 + src/Locations/data/LocationsMetadata.ts | 172 ++++++-------- src/Locations/ui/City.tsx | 34 +++ src/Locations/ui/CompanyLocation.tsx | 112 +++++++++ src/Locations/ui/GenericLocation.tsx | 95 ++++++++ src/Locations/ui/Root.tsx | 91 ++++++++ src/PersonObjects/IPlayer.ts | 30 ++- .../Player/PlayerGeneralMethods.js | 12 + src/index.html | 217 +----------------- 16 files changed, 551 insertions(+), 344 deletions(-) rename src/{Location.js => LocationHelpers.js} (100%) create mode 100644 src/Locations/LocationsHelpers.js create mode 100644 src/Locations/ui/City.tsx create mode 100644 src/Locations/ui/CompanyLocation.tsx create mode 100644 src/Locations/ui/GenericLocation.tsx create mode 100644 src/Locations/ui/Root.tsx create mode 100644 src/PersonObjects/Player/PlayerGeneralMethods.js diff --git a/src/Company/Company.ts b/src/Company/Company.ts index 98e8e3c8c..52dc44cd1 100644 --- a/src/Company/Company.ts +++ b/src/Company/Company.ts @@ -1,8 +1,11 @@ -import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; import { CompanyPosition } from "./CompanyPosition"; +import * as posNames from "./data/companypositionnames"; + import { CONSTANTS } from "../Constants"; import { IMap } from "../types"; +import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; + export interface IConstructorParams { name: string; info: string; @@ -93,6 +96,43 @@ export class Company { } } + hasAgentPositions(): boolean { + return (this.companyPositions[posNames.AgentCompanyPositions[0]] != null); + } + + hasBusinessConsultantPositions(): boolean { + return (this.companyPositions[posNames.BusinessConsultantCompanyPositions[0]] != null); + } + + hasBusinessPositions(): boolean { + return (this.companyPositions[posNames.BusinessCompanyPositions[0]] != null); + } + + hasEmployeePositions(): boolean { + return (this.companyPositions[posNames.MiscCompanyPositions[1]] != null); + } + + hasITPositions(): boolean { + return (this.companyPositions[posNames.ITCompanyPositions[0]] != null); + } + + hasSecurityPositions(): boolean { + return (this.companyPositions[posNames.SecurityCompanyPositions[2]] != null); + } + + hasSoftwareConsultantPositions(): boolean { + return (this.companyPositions[posNames.SoftwareConsultantCompanyPositions[0]] != null); + } + + hasSoftwarePositions(): boolean { + return (this.companyPositions[posNames.SoftwareCompanyPositions[0]] != null); + } + + hasWaiterPositions(): boolean { + return (this.companyPositions[posNames.MiscCompanyPositions[0]] != null); + } + + gainFavor(): void { if (this.favor == null) { this.favor = 0; } if (this.rolloverRep == null) { this.rolloverRep = 0; } diff --git a/src/Location.js b/src/LocationHelpers.js similarity index 100% rename from src/Location.js rename to src/LocationHelpers.js diff --git a/src/Locations/Cities.ts b/src/Locations/Cities.ts index fc138ad25..1ec9d970a 100644 --- a/src/Locations/Cities.ts +++ b/src/Locations/Cities.ts @@ -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 = {}; diff --git a/src/Locations/City.ts b/src/Locations/City.ts index 14aae4a7c..637d2734f 100644 --- a/src/Locations/City.ts +++ b/src/Locations/City.ts @@ -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); + } } diff --git a/src/Locations/Location.ts b/src/Locations/Location.ts index 3cc97609c..8667e4d86 100644 --- a/src/Locations/Location.ts +++ b/src/Locations/Location.ts @@ -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; } } } diff --git a/src/Locations/LocationTypeEnum.ts b/src/Locations/LocationTypeEnum.ts index ddfeafbce..246e6122d 100644 --- a/src/Locations/LocationTypeEnum.ts +++ b/src/Locations/LocationTypeEnum.ts @@ -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, diff --git a/src/Locations/Locations.ts b/src/Locations/Locations.ts index d91095247..752085d9b 100644 --- a/src/Locations/Locations.ts +++ b/src/Locations/Locations.ts @@ -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 = {}; -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); + } } diff --git a/src/Locations/LocationsHelpers.js b/src/Locations/LocationsHelpers.js new file mode 100644 index 000000000..590e9ea56 --- /dev/null +++ b/src/Locations/LocationsHelpers.js @@ -0,0 +1 @@ +import { Player } from "../Player"; diff --git a/src/Locations/data/LocationsMetadata.ts b/src/Locations/data/LocationsMetadata.ts index fb8ae03e3..0b80019d1 100644 --- a/src/Locations/data/LocationsMetadata.ts +++ b/src/Locations/data/LocationsMetadata.ts @@ -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], }, ]; diff --git a/src/Locations/ui/City.tsx b/src/Locations/ui/City.tsx new file mode 100644 index 000000000..91ad06f1a --- /dev/null +++ b/src/Locations/ui/City.tsx @@ -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 { + render() { + const locationButtons = this.props.city.locations.map((locName) => { + return ( +
  • + +
  • + ) + }); + + return ( +
      + {locationButtons} +
    + ) + } +} diff --git a/src/Locations/ui/CompanyLocation.tsx b/src/Locations/ui/CompanyLocation.tsx new file mode 100644 index 000000000..392e309ad --- /dev/null +++ b/src/Locations/ui/CompanyLocation.tsx @@ -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 { + /** + * 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) { + if (!e.isTrusted) { return false; } + this.props.p.applyForAgentJob(); + } + + applyForBusinessConsultantJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForBusinessConsultantJob(); + } + + applyForBusinessJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForBusinessJob(); + } + + applyForEmployeeJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForEmployeeJob(); + } + + applyForItJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForItJob(); + } + + applyForPartTimeEmployeeJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForPartTimeEmployeeJob(); + } + + applyForPartTimeWaiterJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForPartTimeWaiterJob(); + } + + applyForSecurityJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForSecurityJob(); + } + + applyForSoftwareConsultantJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForSoftwareConsultantJob(); + } + + applyForSoftwareJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForSoftwareJob(); + } + + applyForWaiterJob(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + this.props.p.applyForWaiterJob(); + } + + render() { + return ( +
    + { + this.company.hasAgentPositions() && + + ) + } +} diff --git a/src/Locations/ui/GenericLocation.tsx b/src/Locations/ui/GenericLocation.tsx new file mode 100644 index 000000000..e5c37d32a --- /dev/null +++ b/src/Locations/ui/GenericLocation.tsx @@ -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 { + /** + * 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 ( +
    + +
    +

    this.loc.name

    + {locContent} +
    + ) + } +} diff --git a/src/Locations/ui/Root.tsx b/src/Locations/ui/Root.tsx new file mode 100644 index 000000000..01f61e349 --- /dev/null +++ b/src/Locations/ui/Root.tsx @@ -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 { + 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 ( +
    +

    {this.state.city}

    + +
    + ) + } + + /** + * Render UI for a specific location + */ + renderLocation(): React.ReactNode { + return ( + + ) + } + + render() { + if (this.state.inCity) { + return this.renderCity(); + } else { + return this.renderLocation(); + } + } +} diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts index c41247a2e..40cd39cdb 100644 --- a/src/PersonObjects/IPlayer.ts +++ b/src/PersonObjects/IPlayer.ts @@ -8,16 +8,20 @@ import { Sleeve } from "./Sleeve/Sleeve"; import { IMap } from "../types"; -import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; -import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile"; -import { MoneySourceTracker } from "../utils/MoneySourceTracker"; +import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; +import { Company } from "../Company/Company"; +import { CompanyPosition } from "../Company/CompanyPosition"; +import { CityName } from "../Locations/data/CityNames"; +import { LocationName } from "../Locations/data/LocationNames"; +import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile"; +import { MoneySourceTracker } from "../utils/MoneySourceTracker"; export interface IPlayer { // Class members augmentations: IPlayerOwnedAugmentation[]; bladeburner: any; bitNodeN: number; - city: string; + city: CityName; companyName: string; corporation: any; currentServer: string; @@ -26,6 +30,7 @@ export interface IPlayer { hasWseAccount: boolean; jobs: IMap; karma: number; + location: LocationName; money: any; moneySourceA: MoneySourceTracker; moneySourceB: MoneySourceTracker; @@ -85,6 +90,20 @@ export interface IPlayer { crime_money_mult: number; // Methods + applyForAgentJob(sing?: boolean): boolean | void; + applyForBusinessConsultantJob(sing?: boolean): boolean | void; + applyForBusinessJob(sing?: boolean): boolean | void; + applyForEmployeeJob(sing?: boolean): boolean | void; + applyForItJob(sing?: boolean): boolean | void; + applyForJob(entryPosType: CompanyPosition, sing?: boolean): boolean | void; + applyForNetworkEngineerJob(sing?: boolean): boolean | void; + applyForPartTimeEmployeeJob(sing?: boolean): boolean | void; + applyForPartTimeWaiterJob(sing?: boolean): boolean | void; + applyForSecurityEngineerJob(sing?: boolean): boolean | void; + applyForSecurityJob(sing?: boolean): boolean | void; + applyForSoftwareConsultantJob(sing?: boolean): boolean | void; + applyForSoftwareJob(sing?: boolean): boolean | void; + applyForWaiterJob(sing?: boolean): boolean | void; canAfford(cost: number): boolean; gainHackingExp(exp: number): void; gainStrengthExp(exp: number): void; @@ -93,9 +112,11 @@ export interface IPlayer { gainAgilityExp(exp: number): void; gainCharismaExp(exp: number): void; gainMoney(money: number): void; + getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition; hasCorporation(): boolean; inBladeburner(): boolean; inGang(): boolean; + isQualified(company: Company, position: CompanyPosition): boolean; loseMoney(money: number): void; reapplyAllAugmentations(resetMultipliers: boolean): void; reapplyAllSourceFiles(): void; @@ -110,4 +131,5 @@ export interface IPlayer { money: number, time: number, singParams: any): void; + travel(to: CityName): boolean; } diff --git a/src/PersonObjects/Player/PlayerGeneralMethods.js b/src/PersonObjects/Player/PlayerGeneralMethods.js new file mode 100644 index 000000000..df585e69a --- /dev/null +++ b/src/PersonObjects/Player/PlayerGeneralMethods.js @@ -0,0 +1,12 @@ +import { PlayerObject } from "../../Player"; +import { Cities } from "../../Locations/Cities"; + +PlayerObject.prototype.travel = function(to) { + if (Cities[to] == null) { + console.warn(`Player.travel() called with invalid city: ${to}`); + return false; + } + this.city = to; + + return true; +} diff --git a/src/index.html b/src/index.html index 5dd72486b..568785a22 100644 --- a/src/index.html +++ b/src/index.html @@ -236,222 +236,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %> From 4b95ba9ed117ff1b1886cb24dfb919953d085038 Mon Sep 17 00:00:00 2001 From: danielyxie Date: Mon, 1 Apr 2019 02:23:25 -0700 Subject: [PATCH 3/4] Finished location code refactor. Has not yet been tested --- src/Bladeburner.js | 5 +- src/Company/CompanyPosition.ts | 2 +- src/Company/data/CompaniesMetadata.ts | 85 +- src/Company/data/CompanyPositionsMetadata.ts | 2 +- src/Corporation/Corporation.jsx | 32 +- src/Corporation/ui/MainPanel.jsx | 2 +- src/Faction/FactionHelpers.js | 1 - src/IEngine.ts | 10 + src/Infiltration.d.ts | 7 + src/InteractiveTutorial.js | 4 +- src/LocationHelpers.js | 2295 ----------------- src/Locations/Location.ts | 29 + src/Locations/LocationsHelpers.js | 9 - src/Locations/LocationsHelpers.ts | 281 ++ src/Locations/data/LocationNames.ts | 12 - src/Locations/data/LocationsMetadata.ts | 220 ++ src/Locations/ui/ApplyToJobButton.tsx | 46 + src/Locations/ui/CompanyLocation.tsx | 167 +- src/Locations/ui/GenericLocation.tsx | 117 +- src/Locations/ui/GymLocation.tsx | 78 + src/Locations/ui/HospitalLocation.tsx | 55 + src/Locations/ui/Root.tsx | 79 +- src/Locations/ui/SlumsLocation.tsx | 187 ++ src/Locations/ui/SpecialLocation.tsx | 136 + src/Locations/ui/TechVendorLocation.tsx | 94 + src/Locations/ui/TravelAgencyLocation.tsx | 54 + src/Locations/ui/UniversityLocation.tsx | 100 + src/NetscriptFunctions.js | 88 +- src/PersonObjects/IPlayer.ts | 24 +- .../Player/PlayerGeneralMethods.js | 12 - src/PersonObjects/Sleeve/Sleeve.ts | 37 +- src/PersonObjects/Sleeve/SleeveUI.ts | 53 +- src/Player.js | 239 +- src/Prestige.js | 1 - src/Server/BaseServer.ts | 2 +- ...{ServerPurchases.js => ServerPurchases.ts} | 33 +- src/StockMarket/StockMarket.js | 114 +- src/engine.jsx | 170 +- src/index.html | 146 +- src/ui/React/AutoupdatingStdButton.tsx | 70 + src/ui/React/StdButton.tsx | 15 +- src/ui/React/StdButtonPurchased.tsx | 20 + src/ui/React/StdButtonWithTooltip.tsx | 28 - src/ui/navigationTracking.ts | 7 +- utils/DialogBox.d.ts | 4 +- utils/YesNoBox.ts | 11 +- 46 files changed, 2100 insertions(+), 3083 deletions(-) create mode 100644 src/IEngine.ts create mode 100644 src/Infiltration.d.ts delete mode 100644 src/LocationHelpers.js delete mode 100644 src/Locations/LocationsHelpers.js create mode 100644 src/Locations/LocationsHelpers.ts create mode 100644 src/Locations/ui/ApplyToJobButton.tsx create mode 100644 src/Locations/ui/GymLocation.tsx create mode 100644 src/Locations/ui/HospitalLocation.tsx create mode 100644 src/Locations/ui/SlumsLocation.tsx create mode 100644 src/Locations/ui/SpecialLocation.tsx create mode 100644 src/Locations/ui/TechVendorLocation.tsx create mode 100644 src/Locations/ui/TravelAgencyLocation.tsx create mode 100644 src/Locations/ui/UniversityLocation.tsx delete mode 100644 src/PersonObjects/Player/PlayerGeneralMethods.js rename src/Server/{ServerPurchases.js => ServerPurchases.ts} (80%) create mode 100644 src/ui/React/AutoupdatingStdButton.tsx create mode 100644 src/ui/React/StdButtonPurchased.tsx delete mode 100644 src/ui/React/StdButtonWithTooltip.tsx diff --git a/src/Bladeburner.js b/src/Bladeburner.js index 495109ba8..7b37b9745 100644 --- a/src/Bladeburner.js +++ b/src/Bladeburner.js @@ -6,7 +6,6 @@ import { Engine } from "./engine"; import { Faction } from "./Faction/Faction"; import { Factions, factionExists } from "./Faction/Factions"; import { joinFaction, displayFactionContent } from "./Faction/FactionHelpers"; -import { Locations } from "./Locations"; import { Player } from "./Player"; import { hackWorldDaemon, redPillFlag } from "./RedPill"; import { numeralWrapper } from "./ui/numeralFormat"; @@ -218,7 +217,7 @@ $(document).keydown(function(event) { }); function City(params={}) { - this.name = params.name ? params.name : Locations.Sector12; + this.name = params.name ? params.name : CityNames[2]; // Sector-12 //Synthoid population and estimate this.pop = params.pop ? params.pop : getRandomInt(PopulationThreshold, 1.5 * PopulationThreshold); @@ -690,7 +689,7 @@ function Bladeburner(params={}) { for (var i = 0; i < CityNames.length; ++i) { this.cities[CityNames[i]] = new City({name:CityNames[i]}); } - this.city = Locations.Sector12; + this.city = CityNames[2]; // Sector-12 //Map of SkillNames -> level this.skills = {}; diff --git a/src/Company/CompanyPosition.ts b/src/Company/CompanyPosition.ts index a72c52882..1786bd4c6 100644 --- a/src/Company/CompanyPosition.ts +++ b/src/Company/CompanyPosition.ts @@ -1,5 +1,5 @@ import { CONSTANTS } from "../Constants"; -import * as names from "./data/CompanyPositionNames"; +import * as names from "./data/companypositionnames"; /* tslint:disable:completed-docs */ diff --git a/src/Company/data/CompaniesMetadata.ts b/src/Company/data/CompaniesMetadata.ts index ed1a4ae0a..06f5dc872 100644 --- a/src/Company/data/CompaniesMetadata.ts +++ b/src/Company/data/CompaniesMetadata.ts @@ -1,7 +1,8 @@ -import { IConstructorParams } from "../Company"; -import { Locations } from "../../Locations"; -import * as posNames from "./CompanyPositionNames"; -import { IMap } from "../../types"; +import * as posNames from "./companypositionnames"; +import { IConstructorParams } from "../Company"; + +import { IMap } from "../../types"; +import { LocationName } from "../../Locations/data/LocationNames"; // Create Objects containing Company Positions by category // Will help in metadata construction later @@ -89,7 +90,7 @@ CEOOnly[posNames.BusinessCompanyPositions[5]] = true; // Metadata export const companiesMetadata: IConstructorParams[] = [ { - name: Locations.AevumECorp, + name: LocationName.AevumECorp, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -101,7 +102,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 249, }, { - name: Locations.Sector12MegaCorp, + name: LocationName.Sector12MegaCorp, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -113,7 +114,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 249, }, { - name: Locations.AevumBachmanAndAssociates, + name: LocationName.AevumBachmanAndAssociates, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -125,7 +126,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.Sector12BladeIndustries, + name: LocationName.Sector12BladeIndustries, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -137,7 +138,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.VolhavenNWO, + name: LocationName.VolhavenNWO, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -149,7 +150,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 249, }, { - name: Locations.AevumClarkeIncorporated, + name: LocationName.AevumClarkeIncorporated, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -161,7 +162,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.VolhavenOmniTekIncorporated, + name: LocationName.VolhavenOmniTekIncorporated, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -173,7 +174,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.Sector12FourSigma, + name: LocationName.Sector12FourSigma, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -185,7 +186,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.ChongqingKuaiGongInternational, + name: LocationName.ChongqingKuaiGongInternational, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -197,7 +198,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.AevumFulcrumTechnologies, + name: LocationName.AevumFulcrumTechnologies, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -208,7 +209,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.IshimaStormTechnologies, + name: LocationName.IshimaStormTechnologies, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -220,7 +221,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.NewTokyoDefComm, + name: LocationName.NewTokyoDefComm, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -232,7 +233,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.VolhavenHeliosLabs, + name: LocationName.VolhavenHeliosLabs, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -244,7 +245,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.NewTokyoVitaLife, + name: LocationName.NewTokyoVitaLife, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -256,7 +257,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.Sector12IcarusMicrosystems, + name: LocationName.Sector12IcarusMicrosystems, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -268,7 +269,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.Sector12UniversalEnergy, + name: LocationName.Sector12UniversalEnergy, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -280,7 +281,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.AevumGalacticCybersystems, + name: LocationName.AevumGalacticCybersystems, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -292,7 +293,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.AevumAeroCorp, + name: LocationName.AevumAeroCorp, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -305,7 +306,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.VolhavenOmniaCybersystems, + name: LocationName.VolhavenOmniaCybersystems, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -318,7 +319,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.ChongqingSolarisSpaceSystems, + name: LocationName.ChongqingSolarisSpaceSystems, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -331,7 +332,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.Sector12DeltaOne, + name: LocationName.Sector12DeltaOne, info: "", companyPositions: Object.assign({}, CEOOnly, @@ -344,7 +345,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.NewTokyoGlobalPharmaceuticals, + name: LocationName.NewTokyoGlobalPharmaceuticals, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -357,7 +358,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 224, }, { - name: Locations.IshimaNovaMedical, + name: LocationName.IshimaNovaMedical, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -370,7 +371,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 199, }, { - name: Locations.Sector12CIA, + name: LocationName.Sector12CIA, info: "", companyPositions: Object.assign({}, SoftwarePositionsUpToHeadOfEngineering, @@ -385,7 +386,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 149, }, { - name: Locations.Sector12NSA, + name: LocationName.Sector12NSA, info: "", companyPositions: Object.assign({}, SoftwarePositionsUpToHeadOfEngineering, @@ -400,7 +401,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 149, }, { - name: Locations.AevumWatchdogSecurity, + name: LocationName.AevumWatchdogSecurity, info: "", companyPositions: Object.assign({}, SoftwarePositionsUpToHeadOfEngineering, @@ -415,7 +416,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 124, }, { - name: Locations.VolhavenLexoCorp, + name: LocationName.VolhavenLexoCorp, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -428,7 +429,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 99, }, { - name: Locations.AevumRhoConstruction, + name: LocationName.AevumRhoConstruction, info: "", companyPositions: Object.assign({}, SoftwarePositionsUpToLeadDeveloper, @@ -439,7 +440,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 49, }, { - name: Locations.Sector12AlphaEnterprises, + name: LocationName.Sector12AlphaEnterprises, info: "", companyPositions: Object.assign({}, SoftwarePositionsUpToLeadDeveloper, @@ -451,7 +452,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 99, }, { - name: Locations.AevumPolice, + name: LocationName.AevumPolice, info: "", companyPositions: Object.assign({}, AllSecurityPositions, @@ -462,7 +463,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 99, }, { - name: Locations.VolhavenSysCoreSecurities, + name: LocationName.VolhavenSysCoreSecurities, info: "", companyPositions: Object.assign({}, AllTechnologyPositions @@ -472,7 +473,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 124, }, { - name: Locations.VolhavenCompuTek, + name: LocationName.VolhavenCompuTek, info: "", companyPositions: Object.assign({}, AllTechnologyPositions @@ -482,7 +483,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 74, }, { - name: Locations.AevumNetLinkTechnologies, + name: LocationName.AevumNetLinkTechnologies, info: "", companyPositions: Object.assign({}, AllTechnologyPositions @@ -492,7 +493,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 99, }, { - name: Locations.Sector12CarmichaelSecurity, + name: LocationName.Sector12CarmichaelSecurity, info: "", companyPositions: Object.assign({}, AllTechnologyPositions, @@ -505,7 +506,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 74, }, { - name: Locations.Sector12FoodNStuff, + name: LocationName.Sector12FoodNStuff, info: "", companyPositions: Object.assign({}, EmployeeOnly, PartTimeEmployeeOnly @@ -515,7 +516,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 0, }, { - name: Locations.Sector12JoesGuns, + name: LocationName.Sector12JoesGuns, info: "", companyPositions: Object.assign({}, EmployeeOnly, PartTimeEmployeeOnly @@ -525,7 +526,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 0, }, { - name: Locations.IshimaOmegaSoftware, + name: LocationName.IshimaOmegaSoftware, info: "", companyPositions: Object.assign({}, AllSoftwarePositions, @@ -537,7 +538,7 @@ export const companiesMetadata: IConstructorParams[] = [ jobStatReqOffset: 49, }, { - name: Locations.NewTokyoNoodleBar, + name: LocationName.NewTokyoNoodleBar, info: "", companyPositions: Object.assign({}, WaiterOnly, PartTimeWaiterOnly diff --git a/src/Company/data/CompanyPositionsMetadata.ts b/src/Company/data/CompanyPositionsMetadata.ts index ac30251d9..7276f7978 100644 --- a/src/Company/data/CompanyPositionsMetadata.ts +++ b/src/Company/data/CompanyPositionsMetadata.ts @@ -1,6 +1,6 @@ // Metadata used for constructing Company Positions import { IConstructorParams } from "../CompanyPosition"; -import * as posNames from "./CompanyPositionNames"; +import * as posNames from "./companypositionnames"; export const companyPositionMetadata: IConstructorParams[] = [ { diff --git a/src/Corporation/Corporation.jsx b/src/Corporation/Corporation.jsx index f751e21c3..b1c7889ae 100644 --- a/src/Corporation/Corporation.jsx +++ b/src/Corporation/Corporation.jsx @@ -18,8 +18,8 @@ import { BitNodeMultipliers } from "../BitNode/BitNode import { CONSTANTS } from "../Constants"; import { Factions } from "../Faction/Factions"; import { showLiterature } from "../Literature"; -import { Locations } from "../Locations"; import { createCityMap } from "../Locations/Cities"; +import { CityName } from "../Locations/data/CityNames"; import { Player } from "../Player"; import { numeralWrapper } from "../ui/numeralFormat"; @@ -113,15 +113,15 @@ $(document).mousedown(function(event) { var empManualAssignmentModeActive = false; function Industry(params={}) { this.offices = { //Maps locations to offices. 0 if no office at that location - [Locations.Aevum]: 0, - [Locations.Chongqing]: 0, - [Locations.Sector12]: new OfficeSpace({ - loc:Locations.Sector12, + [CityName.Aevum]: 0, + [CityName.Chongqing]: 0, + [CityName.Sector12]: new OfficeSpace({ + loc:CityName.Sector12, size:OfficeInitialSize, }), - [Locations.NewTokyo]: 0, - [Locations.Ishima]: 0, - [Locations.Volhaven]: 0 + [CityName.NewTokyo]: 0, + [CityName.Ishima]: 0, + [CityName.Volhaven]: 0 }; this.name = params.name ? params.name : 0; @@ -172,17 +172,17 @@ function Industry(params={}) { this.newInd = true; this.warehouses = { //Maps locations to warehouses. 0 if no warehouse at that location - [Locations.Aevum]: 0, - [Locations.Chonqing]: 0, - [Locations.Sector12]: new Warehouse({ + [CityName.Aevum]: 0, + [CityName.Chonqing]: 0, + [CityName.Sector12]: new Warehouse({ corp: params.corp, industry: this, - loc: Locations.Sector12, + loc: CityName.Sector12, size: WarehouseInitialSize, }), - [Locations.NewTokyo]: 0, - [Locations.Ishima]: 0, - [Locations.Volhaven]: 0 + [CityName.NewTokyo]: 0, + [CityName.Ishima]: 0, + [CityName.Volhaven]: 0 }; this.init(); @@ -571,7 +571,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) { const product = this.products[name]; let change = getRandomInt(0, 3) * 0.0004; if (change === 0) { continue; } - + if (this.type === Industries.Pharmaceutical || this.type === Industries.Software || this.type === Industries.Robotics) { change *= 3; diff --git a/src/Corporation/ui/MainPanel.jsx b/src/Corporation/ui/MainPanel.jsx index e219acdad..592fba38e 100644 --- a/src/Corporation/ui/MainPanel.jsx +++ b/src/Corporation/ui/MainPanel.jsx @@ -11,7 +11,7 @@ import { overviewPage } from "./Routing"; import { OfficeSpace } from "../Corporation"; -import { CityName } from "../../Locations/data/Cities"; +import { CityName } from "../../Locations/data/CityNames"; export class MainPanel extends BaseReactComponent { constructor(props) { diff --git a/src/Faction/FactionHelpers.js b/src/Faction/FactionHelpers.js index f73698b10..904ab1ac3 100644 --- a/src/Faction/FactionHelpers.js +++ b/src/Faction/FactionHelpers.js @@ -7,7 +7,6 @@ import { Engine } from "../engine"; import { Faction } from "./Faction"; import { Factions } from "./Factions"; import { FactionInfos } from "./FactionInfo"; -import { Locations} from "../Location"; import { HackingMission, setInMission } from "../Missions"; import { Player } from "../Player"; import { PurchaseAugmentationsOrderSetting } from "../Settings/SettingEnums"; diff --git a/src/IEngine.ts b/src/IEngine.ts new file mode 100644 index 000000000..a2c470060 --- /dev/null +++ b/src/IEngine.ts @@ -0,0 +1,10 @@ +/** + * TypeScript interface for the game engine (engine.js), which can't be converted + * to TypeScript at the moment + */ +export interface IEngine { + loadBladeburnerContent: () => void; + loadInfiltrationContent: () => void; + loadResleevingContent: () => void; + loadStockMarketContent: () => void; +} diff --git a/src/Infiltration.d.ts b/src/Infiltration.d.ts new file mode 100644 index 000000000..ae49d2b2d --- /dev/null +++ b/src/Infiltration.d.ts @@ -0,0 +1,7 @@ +import { LocationName } from "./Locations/data/LocationNames"; + +export declare function beginInfiltration(companyName: LocationName, + startLevel: number, + rewardVal: number, + maxClearance: number, + diff: number): void; diff --git a/src/InteractiveTutorial.js b/src/InteractiveTutorial.js index a1c604f08..976e8aa18 100644 --- a/src/InteractiveTutorial.js +++ b/src/InteractiveTutorial.js @@ -382,13 +382,13 @@ function iTutorialEvaluateStep() { //Flash 'City' menu and set its tutorial click handler cityMainMenu.setAttribute("class", "flashing-button"); cityMainMenu.addEventListener("click", function() { - Engine.loadWorldContent(); + Engine.loadLocationContent(); iTutorialNextStep(); return false; }); break; case iTutorialSteps.WorldDescription: - Engine.loadWorldContent(); + Engine.loadLocationContent(); iTutorialSetText("This page lists all of the different locations you can currently " + "travel to. Each location has something that you can do. " + "There's a lot of content out in the world, make sure " + diff --git a/src/LocationHelpers.js b/src/LocationHelpers.js deleted file mode 100644 index 0e791d01f..000000000 --- a/src/LocationHelpers.js +++ /dev/null @@ -1,2295 +0,0 @@ -import {Bladeburner} from "./Bladeburner"; -import {CompanyPositions} from "./Company/CompanyPositions"; -import {Companies} from "./Company/Companies"; -import {getJobRequirementText} from "./Company/GetJobRequirementText"; -import * as posNames from "./Company/data/CompanyPositionNames"; -import { Corporation } from "./Corporation/Corporation"; -import {CONSTANTS} from "./Constants"; -import { Crimes } from "./Crime/Crimes"; -import {Engine} from "./engine"; -import {beginInfiltration} from "./Infiltration"; -import {hasBladeburnerSF} from "./NetscriptFunctions"; -import {Locations} from "./Locations"; -import {Player} from "./Player"; -import { AllServers, - AddToAllServers } from "./Server/AllServers"; -import { Server } from "./Server/Server"; -import { getPurchaseServerCost, - purchaseServer, - purchaseRamForHomeComputer } from "./Server/ServerPurchases"; -import {Settings} from "./Settings/Settings"; -import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; -import { SpecialServerNames, - SpecialServerIps } from "./Server/SpecialServerIps"; - -import {numeralWrapper} from "./ui/numeralFormat"; - -import {dialogBoxCreate} from "../utils/DialogBox"; -import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners"; -import {createRandomIp} from "../utils/IPAddress"; -import {formatNumber} from "../utils/StringHelperFunctions"; -import {yesNoBoxCreate, yesNoTxtInpBoxCreate, - yesNoBoxGetYesButton, yesNoBoxGetNoButton, - yesNoTxtInpBoxGetYesButton, yesNoTxtInpBoxGetNoButton, - yesNoTxtInpBoxGetInput, yesNoBoxClose, - yesNoTxtInpBoxClose} from "../utils/YesNoBox"; - -import { createElement } from "../utils/uiHelpers/createElement"; -import { createPopup } from "../utils/uiHelpers/createPopup"; -import { createPopupCloseButton } from "../utils/uiHelpers/createPopupCloseButton"; -import { removeElementById } from "../utils/uiHelpers/removeElementById"; - - -function displayLocationContent() { - var returnToWorld = clearEventListeners("location-return-to-world-button"); - - var locationName = document.getElementById("location-name"); - - var locationInfo = document.getElementById("location-info"); - - var softwareJob = document.getElementById("location-software-job"); - var softwareConsultantJob = document.getElementById("location-software-consultant-job") - var itJob = document.getElementById("location-it-job"); - var securityEngineerJob = document.getElementById("location-security-engineer-job"); - var networkEngineerJob = document.getElementById("location-network-engineer-job"); - var businessJob = document.getElementById("location-business-job"); - var businessConsultantJob = document.getElementById("location-business-consultant-job"); - var securityJob = document.getElementById("location-security-job"); - var agentJob = document.getElementById("location-agent-job"); - var employeeJob = document.getElementById("location-employee-job"); - var employeePartTimeJob = document.getElementById("location-parttime-employee-job"); - var waiterJob = document.getElementById("location-waiter-job"); - var waiterPartTimeJob = document.getElementById("location-parttime-waiter-job"); - - var work = clearEventListeners("location-work"); - - var jobTitle = document.getElementById("location-job-title"); - var jobReputation = document.getElementById("location-job-reputation"); - var companyFavor = document.getElementById("location-company-favor"); - var locationTxtDiv1 = document.getElementById("location-text-divider-1"); - var locationTxtDiv2 = document.getElementById("location-text-divider-2"); - var locationTxtDiv3 = document.getElementById("location-text-divider-3"); - - var gymTrainStr = document.getElementById("location-gym-train-str"); - var gymTrainDef = document.getElementById("location-gym-train-def"); - var gymTrainDex = document.getElementById("location-gym-train-dex"); - var gymTrainAgi = document.getElementById("location-gym-train-agi"); - - var studyComputerScience = document.getElementById("location-study-computer-science"); - var classDataStructures = document.getElementById("location-data-structures-class"); - var classNetworks = document.getElementById("location-networks-class"); - var classAlgorithms = document.getElementById("location-algorithms-class"); - var classManagement = document.getElementById("location-management-class"); - var classLeadership = document.getElementById("location-leadership-class"); - - var purchase2gb = document.getElementById("location-purchase-2gb"); - var purchase4gb = document.getElementById("location-purchase-4gb"); - var purchase8gb = document.getElementById("location-purchase-8gb"); - var purchase16gb = document.getElementById("location-purchase-16gb"); - var purchase32gb = document.getElementById("location-purchase-32gb"); - var purchase64gb = document.getElementById("location-purchase-64gb"); - var purchase128gb = document.getElementById("location-purchase-128gb"); - var purchase256gb = document.getElementById("location-purchase-256gb"); - var purchase512gb = document.getElementById("location-purchase-512gb"); - var purchase1tb = document.getElementById("location-purchase-1tb"); - var purchaseTor = document.getElementById("location-purchase-tor"); - var purchaseHomeRam = document.getElementById("location-purchase-home-ram"); - var purchaseHomeCores = document.getElementById("location-purchase-home-cores"); - - var travelAgencyText = document.getElementById("location-travel-agency-text"); - var travelToAevum = document.getElementById("location-travel-to-aevum"); - var travelToChongqing = document.getElementById("location-travel-to-chongqing"); - var travelToSector12 = document.getElementById("location-travel-to-sector12"); - var travelToNewTokyo = document.getElementById("location-travel-to-newtokyo"); - var travelToIshima = document.getElementById("location-travel-to-ishima"); - var travelToVolhaven = document.getElementById("location-travel-to-volhaven"); - - var infiltrate = clearEventListeners("location-infiltrate"); - - var hospitalTreatment = document.getElementById("location-hospital-treatment"); - - var slumsDescText = document.getElementById("location-slums-description"); - var slumsShoplift = document.getElementById("location-slums-shoplift"); - var slumsRobStore = document.getElementById("location-slums-rob-store"); - var slumsMug = document.getElementById("location-slums-mug"); - var slumsLarceny = document.getElementById("location-slums-larceny"); - var slumsDealDrugs = document.getElementById("location-slums-deal-drugs"); - var slumsBondForgery = document.getElementById("location-slums-bond-forgery"); - var slumsTrafficArms = document.getElementById("location-slums-traffic-arms"); - var slumsHomicide = document.getElementById("location-slums-homicide"); - var slumsGta = document.getElementById("location-slums-gta"); - var slumsKidnap = document.getElementById("location-slums-kidnap"); - var slumsAssassinate = document.getElementById("location-slums-assassinate"); - var slumsHeist = document.getElementById("location-slums-heist"); - - var cityHallCreateCorporation = document.getElementById("location-cityhall-create-corporation"); - - var nsaBladeburner = document.getElementById("location-nsa-bladeburner"); - - const vitalifeResleeve = document.getElementById("location-vitalife-resleeve"); - - var loc = Player.location; - - returnToWorld.addEventListener("click", function() { - Engine.loadWorldContent(); - }); - - locationName.innerHTML = loc; - locationName.style.display = "block"; - - locationInfo.style.display = "block"; - - softwareJob.style.display = "none"; - softwareConsultantJob.style.display = "none"; - itJob.style.display = "none"; - securityEngineerJob.style.display = "none"; - networkEngineerJob.style.display = "none"; - businessJob.style.display = "none"; - businessConsultantJob.style.display = "none"; - securityJob.style.display = "none"; - agentJob.style.display = "none"; - employeeJob.style.display = "none"; - employeePartTimeJob.style.display = "none"; - waiterJob.style.display = "none"; - waiterPartTimeJob.style.display = "none"; - - softwareJob.innerHTML = "Apply for Software Job"; - softwareConsultantJob.innerHTML = "Apply for a Software Consultant job"; - itJob.innerHTML = "Apply for IT Job"; - securityEngineerJob.innerHTML = "Apply for Security Engineer Job"; - networkEngineerJob.innerHTML = "Apply for Network Engineer Job"; - businessJob.innerHTML = "Apply for Business Job"; - businessConsultantJob.innerHTML = "Apply for a Business Consultant Job"; - securityJob.innerHTML = "Apply for Security Job"; - agentJob.innerHTML = "Apply for Agent Job"; - employeeJob.innerHTML = "Apply to be an Employee"; - employeePartTimeJob.innerHTML = "Apply to be a Part-time Employee"; - waiterJob.innerHTML = "Apply to be a Waiter"; - waiterPartTimeJob.innerHTML = "Apply to be a Part-time Waiter" - - work.style.display = "none"; - - gymTrainStr.style.display = "none"; - gymTrainDef.style.display = "none"; - gymTrainDex.style.display = "none"; - gymTrainAgi.style.display = "none"; - - studyComputerScience.style.display = "none"; - classDataStructures.style.display = "none"; - classNetworks.style.display = "none"; - classAlgorithms.style.display = "none"; - classManagement.style.display = "none"; - classLeadership.style.display = "none"; - - purchase2gb.style.display = "none"; - purchase4gb.style.display = "none"; - purchase8gb.style.display = "none"; - purchase16gb.style.display = "none"; - purchase32gb.style.display = "none"; - purchase64gb.style.display = "none"; - purchase128gb.style.display = "none"; - purchase256gb.style.display = "none"; - purchase512gb.style.display = "none"; - purchase1tb.style.display = "none"; - purchaseTor.style.display = "none"; - purchaseHomeRam.style.display = "none"; - purchaseHomeCores.style.display = "none"; - - purchase2gb.innerHTML = "Purchase 2GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(2)); - purchase4gb.innerHTML = "Purchase 4GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(4)); - purchase8gb.innerHTML = "Purchase 8GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(8)); - purchase16gb.innerHTML = "Purchase 16GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(16)); - purchase32gb.innerHTML = "Purchase 32GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(32)); - purchase64gb.innerHTML = "Purchase 64GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(64)); - purchase128gb.innerHTML = "Purchase 128GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(128)); - purchase256gb.innerHTML = "Purchase 256GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(256)); - purchase512gb.innerHTML = "Purchase 512GB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(512)); - purchase1tb.innerHTML = "Purchase 1TB Server - " + numeralWrapper.formatMoney(getPurchaseServerCost(1024)); - if (!SpecialServerIps.hasOwnProperty("Darkweb Server")) { - purchaseTor.classList.add("a-link-button"); - purchaseTor.classList.remove("a-link-button-bought"); - purchaseTor.innerHTML = "Purchase TOR Router - $" + formatNumber(CONSTANTS.TorRouterCost, 2); - } else { - purchaseTor.classList.remove("a-link-button"); - purchaseTor.classList.add("a-link-button-bought"); - purchaseTor.innerHTML = "TOR Router - Purchased"; - } - - - travelAgencyText.style.display = "none"; - travelToAevum.style.display = "none"; - travelToChongqing.style.display = "none"; - travelToSector12.style.display = "none"; - travelToNewTokyo.style.display = "none"; - travelToIshima.style.display = "none"; - travelToVolhaven.style.display = "none"; - - infiltrate.style.display = "none"; - - hospitalTreatment.style.display = "none"; - - slumsDescText.style.display = "none"; - slumsShoplift.style.display = "none"; - slumsRobStore.style.display = "none"; - slumsMug.style.display = "none"; - slumsLarceny.style.display = "none"; - slumsDealDrugs.style.display = "none"; - slumsBondForgery.style.display = "none"; - slumsTrafficArms.style.display = "none"; - slumsHomicide.style.display = "none"; - slumsGta.style.display = "none"; - slumsKidnap.style.display = "none"; - slumsAssassinate.style.display = "none"; - slumsHeist.style.display = "none"; - - cityHallCreateCorporation.style.display = "none"; - nsaBladeburner.style.display = "none"; - vitalifeResleeve.style.display = "none"; - - //Check if the player is employed at this Location. If he is, display the "Work" button, - //update the job title, etc. - if (loc != "" && Object.keys(Player.jobs).includes(loc)) { - let company = Companies[loc]; - - jobTitle.style.display = "block"; - jobReputation.style.display = "inline"; - companyFavor.style.display = "inline"; - locationTxtDiv1.style.display = "block"; - locationTxtDiv2.style.display = "block"; - locationTxtDiv3.style.display = "block"; - jobTitle.innerHTML = `Job Title: ${Player.jobs[loc]}`; - let repGain = company.getFavorGain(); - if (repGain.length != 2) {repGain = 0;} - repGain = repGain[0]; - jobReputation.innerHTML = "Company reputation: " + formatNumber(company.playerReputation, 4) + - "You will earn " + - formatNumber(repGain, 0) + - " faction favor upon resetting after installing an Augmentation"; - companyFavor.innerHTML = "Company Favor: " + formatNumber(company.favor, 0) + - "Company favor increases the rate at which " + - "you earn reputation for this company by 1% per favor. Company favor " + - "is gained whenever you reset after installing an Augmentation. The amount of " + - "favor you gain depends on how much reputation you have with the company"; - work.style.display = "block"; - - let currPos = CompanyPositions[Player.jobs[loc]]; - if (currPos == null) { - throw new Error("Player's companyPosition property has an invalid value"); - } - - work.addEventListener("click", function() { - if (currPos.isPartTimeJob() || currPos.isSoftwareConsultantJob() || currPos.isBusinessConsultantJob()) { - Player.startWorkPartTime(loc); - } else { - Player.startWork(loc); - } - return false; - }); - - //Change the text for the corresponding position from "Apply for X Job" to "Apply for promotion" - if (currPos.isSoftwareJob()) { - softwareJob.innerHTML = "Apply for a promotion (Software)"; - } else if (currPos.isSoftwareConsultantJob()) { - softwareConsultantJob.innerHTML = "Apply for a promotion (Software Consultant)"; - } else if (currPos.isITJob()) { - itJob.innerHTML = "Apply for a promotion (IT)"; - } else if (currPos.isSecurityEngineerJob()) { - securityEngineerJob.innerHTML = "Apply for a promotion (Security Engineer)"; - } else if (currPos.isNetworkEngineerJob()) { - networkEngineerJob.innerHTML = "Apply for a promotion (Network Engineer)"; - } else if (currPos.isBusinessJob()) { - businessJob.innerHTML = "Apply for a promotion (Business)"; - } else if (currPos.isBusinessConsultantJob()) { - businessConsultantJob.innerHTML = "Apply for a promotion (Business Consultant)"; - } else if (currPos.isSecurityJob()) { - securityJob.innerHTML = "Apply for a promotion (Security)"; - } else if (currPos.isAgentJob()) { - agentJob.innerHTML = "Apply for a promotion (Agent)"; - } - } else { - jobTitle.style.display = "none"; - jobReputation.style.display = "none"; - companyFavor.style.display = "none"; - locationTxtDiv1.style.display = "none"; - locationTxtDiv2.style.display = "none"; - locationTxtDiv3.style.display = "none"; - } - - //Calculate hospital Cost - if (Player.hp < 0) {Player.hp = 0;} - var hospitalTreatmentCost = (Player.max_hp - Player.hp) * CONSTANTS.HospitalCostPerHp; - - //Set tooltip for job requirements - setJobRequirementTooltip(loc, CompanyPositions[posNames.SoftwareCompanyPositions[0]], softwareJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], softwareConsultantJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.ITCompanyPositions[0]], itJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], securityEngineerJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], networkEngineerJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessCompanyPositions[0]], businessJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], businessConsultantJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.SecurityCompanyPositions[2]], securityJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.AgentCompanyPositions[0]], agentJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[1]], employeeJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[1]], employeePartTimeJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.MiscCompanyPositions[0]], waiterJob); - setJobRequirementTooltip(loc, CompanyPositions[posNames.PartTimeCompanyPositions[0]], waiterPartTimeJob); - - switch (loc) { - case Locations.AevumTravelAgency: - travelAgencyText.style.display = "block"; - travelToChongqing.style.display = "block"; - travelToSector12.style.display = "block"; - travelToNewTokyo.style.display = "block"; - travelToIshima.style.display = "block"; - travelToVolhaven.style.display = "block"; - break; - - case Locations.AevumSummitUniversity: - var costMult = 4, expMult = 3; - displayUniversityLocationContent(costMult); - setUniversityLocationButtons(costMult, expMult); - break; - - case Locations.AevumECorp: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - - purchase128gb.style.display = "block"; - purchase256gb.style.display = "block"; - purchase512gb.style.display = "block"; - purchase1tb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumECorp, - 4800, 116, 150, 6); - break; - - case Locations.AevumBachmanAndAssociates: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumBachmanAndAssociates, - 1350, 42, 60, 4.1); - break; - - case Locations.AevumClarkeIncorporated: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumClarkeIncorporated, - 1800, 34, 75, 3.6); - break; - - case Locations.AevumFulcrumTechnologies: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - - purchase128gb.style.display = "block"; - purchase256gb.style.display = "block"; - purchase512gb.style.display = "block"; - purchase1tb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumFulcrumTechnologies, - 4140, 96, 100, 6.2); - break; - - case Locations.AevumAeroCorp: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumAeroCorp, - 1350, 32, 50, 4.4); - break; - - case Locations.AevumGalacticCybersystems: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumGalacticCybersystems, - 1260, 30, 50, 3.95); - break; - - case Locations.AevumWatchdogSecurity: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - agentJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumWatchdogSecurity, - 690, 20, 30, 3); - break; - - case Locations.AevumRhoConstruction: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumRhoConstruction, - 485, 16, 20, 1.9); - break; - - case Locations.AevumPolice: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumPolice, - 565, 18, 25, 2.2); - break; - - case Locations.AevumNetLinkTechnologies: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - - purchase2gb.style.display = "block"; - purchase4gb.style.display = "block"; - purchase8gb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.AevumNetLinkTechnologies, - 144, 10, 25, 1.4); - break; - - case Locations.AevumCrushFitnessGym: - var costMult = 3, expMult = 2; - displayGymLocationContent(costMult); - setGymLocationButtons(costMult, expMult); - break; - - case Locations.AevumSnapFitnessGym: - var costMult = 10, expMult = 5; - displayGymLocationContent(costMult); - setGymLocationButtons(costMult, expMult); - break; - - case Locations.ChongqingTravelAgency: - travelAgencyText.style.display = "block"; - travelToAevum.style.display = "block"; - travelToSector12.style.display = "block"; - travelToNewTokyo.style.display = "block"; - travelToIshima.style.display = "block"; - travelToVolhaven.style.display = "block"; - break; - - case Locations.ChongqingKuaiGongInternational: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.ChongqingKuaiGongInternational, - 4450, 100, 100, 6.1); - break; - - case Locations.ChongqingSolarisSpaceSystems: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.ChongqingSolarisSpaceSystems, - 2915, 52, 75, 6); - break; - - - case Locations.Sector12TravelAgency: - travelAgencyText.style.display = "block"; - travelToAevum.style.display = "block"; - travelToChongqing.style.display = "block"; - travelToNewTokyo.style.display = "block"; - travelToIshima.style.display = "block"; - travelToVolhaven.style.display = "block"; - break; - - case Locations.Sector12RothmanUniversity: - var costMult = 3, expMult = 2; - displayUniversityLocationContent(costMult); - setUniversityLocationButtons(costMult, expMult); - break; - - case Locations.Sector12MegaCorp: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12MegaCorp, - 4500, 114, 125, 6.75); - break; - - case Locations.Sector12BladeIndustries: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12BladeIndustries, - 2160, 46, 100, 4.2); - break; - - case Locations.Sector12FourSigma: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12FourSigma, - 1350, 58, 100, 7); - break; - - case Locations.Sector12IcarusMicrosystems: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12IcarusMicrosystems, - 730, 32, 70, 5.4); - break; - - case Locations.Sector12UniversalEnergy: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12UniversalEnergy, - 700, 24, 50, 4.3); - break; - - case Locations.Sector12DeltaOne: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12DeltaOne, - 970, 38, 75, 4.5); - break; - - case Locations.Sector12CIA: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - agentJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12CIA, - 1170, 44, 80, 4.6); - break; - - case Locations.Sector12NSA: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - agentJob.style.display = "block"; - if (Player.bitNodeN === 6 || hasBladeburnerSF === true) { - if (Player.bitNodeN === 8) {break;} - if (Player.bladeburner instanceof Bladeburner) { - //Note: Can't infiltrate NSA when part of bladeburner - nsaBladeburner.innerText = "Enter Bladeburner Headquarters"; - } else { - setInfiltrateButton(infiltrate, Locations.Sector12NSA, - 1135, 40, 80, 5); - nsaBladeburner.innerText = "Apply to Bladeburner Division"; - } - nsaBladeburner.style.display = "block"; - } else { - setInfiltrateButton(infiltrate, Locations.Sector12NSA, - 1135, 40, 80, 5); - } - break; - - case Locations.Sector12AlphaEnterprises: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - businessJob.style.display = "block"; - purchase2gb.style.display = "block"; - purchase4gb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12AlphaEnterprises, - 200, 14, 40, 2.25); - break; - - case Locations.Sector12CarmichaelSecurity: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - agentJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12CarmichaelSecurity, - 405, 18, 60, 2.5); - break; - - case Locations.Sector12FoodNStuff: - locationInfo.innerHTML = Companies[loc].info; - - employeeJob.style.display = "block"; - employeePartTimeJob.style.display = "block"; - break; - - case Locations.Sector12JoesGuns: - locationInfo.innerHTML = Companies[loc].info; - - employeeJob.style.display = "block"; - employeePartTimeJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.Sector12JoesGuns, - 120, 8, 20, 1.8); - break; - - case Locations.Sector12IronGym: - var costMult = 1, expMult = 1; - displayGymLocationContent(costMult); - setGymLocationButtons(costMult, expMult); - break; - - case Locations.Sector12PowerhouseGym: - var costMult = 20, expMult = 10; - displayGymLocationContent(costMult); - setGymLocationButtons(costMult, expMult); - break; - - case Locations.Sector12CityHall: - cityHallCreateCorporation.style.display = "block"; - if (Player.corporation instanceof Corporation) { - cityHallCreateCorporation.className = "a-link-button-inactive"; - } else { - cityHallCreateCorporation.className = "a-link-button"; - } - break; - - case Locations.NewTokyoTravelAgency: - travelAgencyText.style.display = "block"; - travelToAevum.style.display = "block"; - travelToChongqing.style.display = "block"; - travelToSector12.style.display = "block"; - travelToIshima.style.display = "block"; - travelToVolhaven.style.display = "block"; - break; - - case Locations.NewTokyoDefComm: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.NewTokyoDefComm, - 1050, 28, 70, 4); - break; - - case Locations.NewTokyoVitaLife: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife, - 605, 22, 100, 3.5); - if (Player.bitNodeN === 10 || SourceFileFlags[10]) { - vitalifeResleeve.style.display = "block"; - } - - break; - - case Locations.NewTokyoGlobalPharmaceuticals: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.NewTokyoGlobalPharmaceuticals, - 700, 24, 80, 3.8); - break; - - case Locations.NewTokyoNoodleBar: - locationInfo.innerHTML = Companies[loc].info; - - waiterJob.style.display = "block"; - waiterPartTimeJob.style.display = "block"; - break; - - case Locations.IshimaTravelAgency: - travelAgencyText.style.display = "block"; - travelToAevum.style.display = "block"; - travelToChongqing.style.display = "block"; - travelToSector12.style.display = "block"; - travelToNewTokyo.style.display = "block"; - travelToVolhaven.style.display = "block"; - break; - - case Locations.IshimaStormTechnologies: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "none"; - agentJob.style.display = "none"; - employeeJob.style.display = "none"; - waiterJob.style.display = "none"; - - purchase32gb.style.display = "block"; - purchase64gb.style.display = "block"; - purchase128gb.style.display = "block"; - purchase256gb.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.IshimaStormTechnologies, - 570, 24, 100, 4.1); - break; - - case Locations.IshimaNovaMedical: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.IshimaNovaMedical, - 485, 20, 50, 3.2); - break; - - case Locations.IshimaOmegaSoftware: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - businessJob.style.display = "block"; - - purchase4gb.style.display = "block"; - purchase8gb.style.display = "block"; - purchase16gb.style.display = "block"; - purchase32gb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.IshimaOmegaSoftware, - 130, 10, 40, 1.6); - break; - - case Locations.VolhavenTravelAgency: - travelAgencyText.style.display = "block"; - travelToAevum.style.display = "block"; - travelToChongqing.style.display = "block"; - travelToSector12.style.display = "block"; - travelToNewTokyo.style.display = "block"; - travelToIshima.style.display = "block"; - break; - - case Locations.VolhavenZBInstituteOfTechnology: - var costMult = 5, expMult = 4; - displayUniversityLocationContent(costMult); - setUniversityLocationButtons(costMult, expMult); - break; - - case Locations.VolhavenOmniTekIncorporated: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - - purchase128gb.style.display = "block"; - purchase256gb.style.display = "block"; - purchase512gb.style.display = "block"; - purchase1tb.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenOmniTekIncorporated, - 1215, 44, 100, 4.4); - break; - - case Locations.VolhavenNWO: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenNWO, - 1460, 56, 200, 6.8); - break; - - case Locations.VolhavenHeliosLabs: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenHeliosLabs, - 1080, 28, 75, 3); - break; - - case Locations.VolhavenOmniaCybersystems: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenOmniaCybersystems, - 725, 28, 90, 4.9); - break; - - case Locations.VolhavenLexoCorp: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - businessJob.style.display = "block"; - securityJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenLexoCorp, - 340, 14, 60, 2); - break; - - case Locations.VolhavenSysCoreSecurities: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenSysCoreSecurities, - 430, 18, 75, 2.4); - break; - - case Locations.VolhavenCompuTek: - locationInfo.innerHTML = Companies[loc].info; - - softwareJob.style.display = "block"; - softwareConsultantJob.style.display = "block"; - itJob.style.display = "block"; - securityEngineerJob.style.display = "block"; - networkEngineerJob.style.display = "block"; - - purchase8gb.style.display = "block"; - purchase16gb.style.display = "block"; - purchase32gb.style.display = "block"; - purchase64gb.style.display = "block"; - purchase128gb.style.display = "block"; - purchase256gb.style.display = "block"; - purchaseTor.style.display = "block"; - purchaseHomeRam.style.display = "block"; - purchaseHomeCores.style.display = "block"; - setInfiltrateButton(infiltrate, Locations.VolhavenCompuTek, - 195, 12, 60, 2.1); - break; - - case Locations.VolhavenMilleniumFitnessGym: - var costMult = 7, expMult = 4; - displayGymLocationContent(costMult); - setGymLocationButtons(costMult, expMult); - break; - - //All Slums - case Locations.AevumSlums: - case Locations.ChongqingSlums: - case Locations.Sector12Slums: - case Locations.NewTokyoSlums: - case Locations.IshimaSlums: - case Locations.VolhavenSlums: - var shopliftChance = Crimes.Shoplift.successRate(Player); - var robStoreChance = Crimes.RobStore.successRate(Player); - var mugChance = Crimes.Mug.successRate(Player); - var larcenyChance = Crimes.Larceny.successRate(Player); - var drugsChance = Crimes.DealDrugs.successRate(Player); - var bondChance = Crimes.BondForgery.successRate(Player); - var armsChance = Crimes.TraffickArms.successRate(Player); - var homicideChance = Crimes.Homicide.successRate(Player); - var gtaChance = Crimes.GrandTheftAuto.successRate(Player); - var kidnapChance = Crimes.Kidnap.successRate(Player); - var assassinateChance = Crimes.Assassination.successRate(Player); - var heistChance = Crimes.Heist.successRate(Player); - - slumsDescText.style.display = "block"; - slumsShoplift.style.display = "block"; - slumsShoplift.innerHTML = "Shoplift (" + (shopliftChance*100).toFixed(3) + "% chance of success)"; - slumsShoplift.innerHTML += ' Attempt to shoplift from a low-end retailer '; - slumsRobStore.style.display = "block"; - slumsRobStore.innerHTML = "Rob store(" + (robStoreChance*100).toFixed(3) + "% chance of success)"; - slumsRobStore.innerHTML += 'Attempt to commit armed robbery on a high-end store '; - slumsMug.style.display = "block"; - slumsMug.innerHTML = "Mug someone (" + (mugChance*100).toFixed(3) + "% chance of success)"; - slumsMug.innerHTML += ' Attempt to mug a random person on the street '; - slumsLarceny.style.display = "block"; - slumsLarceny.innerHTML = "Larceny (" + (larcenyChance*100).toFixed(3) + "% chance of success)"; - slumsLarceny.innerHTML +=" Attempt to rob property from someone's house "; - slumsDealDrugs.style.display = "block"; - slumsDealDrugs.innerHTML = "Deal Drugs (" + (drugsChance*100).toFixed(3) + "% chance of success)"; - slumsDealDrugs.innerHTML += ' Attempt to deal drugs '; - slumsBondForgery.style.display = "block"; - slumsBondForgery.innerHTML = "Bond Forgery (" + (bondChance*100).toFixed(3) + "% chance of success)"; - slumsBondForgery.innerHTML += " Attempt to forge corporate bonds"; - slumsTrafficArms.style.display = "block"; - slumsTrafficArms.innerHTML = "Traffick Illegal Arms (" + (armsChance*100).toFixed(3) + "% chance of success)"; - slumsTrafficArms.innerHTML += ' Attempt to smuggle illegal arms into the city and sell them to gangs and criminal organizations '; - slumsHomicide.style.display = "block"; - slumsHomicide.innerHTML = "Homicide (" + (homicideChance*100).toFixed(3) + "% chance of success)"; - slumsHomicide.innerHTML += ' Attempt to murder a random person on the street'; - slumsGta.style.display = "block"; - slumsGta.innerHTML = "Grand Theft Auto (" + (gtaChance*100).toFixed(3) + "% chance of success)"; - slumsGta.innerHTML += ' Attempt to commit grand theft auto '; - slumsKidnap.style.display = "block"; - slumsKidnap.innerHTML = "Kidnap and Ransom (" + (kidnapChance*100).toFixed(3) + "% chance of success)"; - slumsKidnap.innerHTML += ' Attempt to kidnap and ransom a high-profile target '; - slumsAssassinate.style.display = "block"; - slumsAssassinate.innerHTML = "Assassinate (" + (assassinateChance*100).toFixed(3) + "% chance of success)"; - slumsAssassinate.innerHTML += ' Attempt to assassinate a high-profile target '; - slumsHeist.style.display = "block"; - slumsHeist.innerHTML = "Heist (" + (heistChance*100).toFixed(3) + "% chance of success)"; - slumsHeist.innerHTML += ' Attempt to pull off the ultimate heist '; - break; - - //Hospital - case Locations.Hospital: - hospitalTreatment.innerText = "Get treatment for wounds - $" + formatNumber(hospitalTreatmentCost, 2).toString(); - hospitalTreatment.style.display = "block"; - break; - - default: - console.log("ERROR: INVALID LOCATION"); - } - - // Make the "Apply to be Employee and Waiter" texts disappear if you already hold the job - // Includes part-time stuff - if (Object.keys(Player.jobs).includes(loc)) { - var currPos = Player.jobs[loc]; - - if (currPos == "Employee") { - employeeJob.style.display = "none"; - } else if (currPos == "Waiter") { - waiterJob.style.display = "none"; - } else if (currPos == "Part-time Employee") { - employeePartTimeJob.style.display = "none"; - } else if (currPos == "Part-time Waiter") { - waiterPartTimeJob.style.display = "none"; - } - } -} - -function initLocationButtons() { - //Buttons to travel to different locations in World - let aevumTravelAgency = document.getElementById("aevum-travelagency"); - aevumTravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumTravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let aevumHospital = document.getElementById("aevum-hospital"); - aevumHospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let aevumSummitUniversity = document.getElementById("aevum-summituniversity"); - aevumSummitUniversity.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumSummitUniversity; - Engine.loadLocationContent(); - return false; - }); - - let aevumECorp = document.getElementById("aevum-ecorp"); - aevumECorp.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumECorp; - Engine.loadLocationContent(); - return false; - }); - - let aevumBachmanAndAssociates = document.getElementById("aevum-bachmanandassociates"); - aevumBachmanAndAssociates.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumBachmanAndAssociates; - Engine.loadLocationContent(); - return false; - }); - - let aevumClarkeIncorporated = document.getElementById("aevum-clarkeincorporated"); - aevumClarkeIncorporated.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumClarkeIncorporated; - Engine.loadLocationContent(); - return false; - }); - - let aevumFulcrumTechnologies = document.getElementById("aevum-fulcrumtechnologies"); - aevumFulcrumTechnologies.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumFulcrumTechnologies; - Engine.loadLocationContent(); - return false; - }); - - let aevumAeroCorp = document.getElementById("aevum-aerocorp"); - aevumAeroCorp.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumAeroCorp; - Engine.loadLocationContent(); - return false; - }); - - let aevumGalacticCybersystems = document.getElementById("aevum-galacticcybersystems"); - aevumGalacticCybersystems.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumGalacticCybersystems; - Engine.loadLocationContent(); - return false; - }); - - let aevumWatchdogSecurity = document.getElementById("aevum-watchdogsecurity"); - aevumWatchdogSecurity.addEventListener("click", function() { - Player.location = Locations.AevumWatchdogSecurity; - Engine.loadLocationContent(); - return false; - }); - - let aevumRhoConstruction = document.getElementById("aevum-rhoconstruction"); - aevumRhoConstruction.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumRhoConstruction; - Engine.loadLocationContent(); - return false; - }); - - let aevumPolice = document.getElementById("aevum-aevumpolice"); - aevumPolice.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumPolice; - Engine.loadLocationContent(); - return false; - }); - - let aevumNetLinkTechnologies = document.getElementById("aevum-netlinktechnologies"); - aevumNetLinkTechnologies.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumNetLinkTechnologies; - Engine.loadLocationContent(); - return false; - }); - - let aevumCrushFitnessGym = document.getElementById("aevum-crushfitnessgym"); - aevumCrushFitnessGym.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumCrushFitnessGym; - Engine.loadLocationContent(); - return false; - }); - - let aevumSnapFitnessGym = document.getElementById("aevum-snapfitnessgym"); - aevumSnapFitnessGym.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumSnapFitnessGym; - Engine.loadLocationContent(); - return false; - }); - - let aevumSlums = document.getElementById("aevum-slums"); - aevumSlums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.AevumSlums; - Engine.loadLocationContent(); - return false; - }); - - let chongqingTravelAgency = document.getElementById("chongqing-travelagency"); - chongqingTravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.ChongqingTravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let chongqingHospital = document.getElementById("chongqing-hospital"); - chongqingHospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let chongqingKuaiGongInternational = document.getElementById("chongqing-kuaigonginternational"); - chongqingKuaiGongInternational.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.ChongqingKuaiGongInternational; - Engine.loadLocationContent(); - return false; - }); - - let chongqingSolarisSpaceSystems = document.getElementById("chongqing-solarisspacesystems"); - chongqingSolarisSpaceSystems.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.ChongqingSolarisSpaceSystems; - Engine.loadLocationContent(); - return false; - }); - - let chongqingSlums = document.getElementById("chongqing-slums"); - chongqingSlums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.ChongqingSlums; - Engine.loadLocationContent(); - return false; - }); - - let sector12TravelAgency = document.getElementById("sector12-travelagency"); - sector12TravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12TravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let sector12Hospital = document.getElementById("sector12-hospital"); - sector12Hospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let sector12RothmanUniversity = document.getElementById("sector12-rothmanuniversity"); - sector12RothmanUniversity.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12RothmanUniversity; - Engine.loadLocationContent(); - return false; - }); - - let sector12MegaCorp = document.getElementById("sector12-megacorp"); - sector12MegaCorp.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12MegaCorp; - Engine.loadLocationContent(); - return false; - }); - - let sector12BladeIndustries = document.getElementById("sector12-bladeindustries"); - sector12BladeIndustries.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12BladeIndustries; - Engine.loadLocationContent(); - return false; - }); - - let sector12FourSigma = document.getElementById("sector12-foursigma"); - sector12FourSigma.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12FourSigma; - Engine.loadLocationContent(); - return false; - }); - - let sector12IcarusMicrosystems = document.getElementById("sector12-icarusmicrosystems"); - sector12IcarusMicrosystems.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12IcarusMicrosystems; - Engine.loadLocationContent(); - return false; - }); - - let sector12UniversalEnergy = document.getElementById("sector12-universalenergy"); - sector12UniversalEnergy.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12UniversalEnergy; - Engine.loadLocationContent(); - return false; - }); - - let sector12DeltaOne = document.getElementById("sector12-deltaone"); - sector12DeltaOne.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12DeltaOne; - Engine.loadLocationContent(); - return false; - }); - - let sector12CIA = document.getElementById("sector12-cia"); - sector12CIA.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12CIA; - Engine.loadLocationContent(); - return false; - }); - - let sector12NSA = document.getElementById("sector12-nsa"); - sector12NSA.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12NSA; - Engine.loadLocationContent(); - return false; - }); - - let sector12AlphaEnterprises = document.getElementById("sector12-alphaenterprises"); - sector12AlphaEnterprises.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12AlphaEnterprises; - Engine.loadLocationContent(); - return false; - }); - - let sector12CarmichaelSecurity = document.getElementById("sector12-carmichaelsecurity"); - sector12CarmichaelSecurity.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12CarmichaelSecurity; - Engine.loadLocationContent(); - return false; - }); - - let sector12FoodNStuff = document.getElementById("sector12-foodnstuff"); - sector12FoodNStuff.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12FoodNStuff; - Engine.loadLocationContent(); - return false; - }); - - let sector12JoesGuns = document.getElementById("sector12-joesguns"); - sector12JoesGuns.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12JoesGuns; - Engine.loadLocationContent(); - return false; - }); - - let sector12IronGym = document.getElementById("sector12-irongym"); - sector12IronGym.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12IronGym; - Engine.loadLocationContent(); - return false; - }); - - let sector12PowerhouseGym = document.getElementById("sector12-powerhousegym"); - sector12PowerhouseGym.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12PowerhouseGym; - Engine.loadLocationContent(); - return false; - }); - - let sector12Slums = document.getElementById("sector12-slums"); - sector12Slums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12Slums; - Engine.loadLocationContent(); - return false; - }); - - let sector12CityHall = document.getElementById("sector12-cityhall"); - sector12CityHall.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Sector12CityHall; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoTravelAgency = document.getElementById("newtokyo-travelagency"); - newTokyoTravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoTravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoHospital = document.getElementById("newtokyo-hospital"); - newTokyoHospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoDefComm = document.getElementById("newtokyo-defcomm"); - newTokyoDefComm.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoDefComm; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoVitaLife = document.getElementById("newtokyo-vitalife"); - newTokyoVitaLife.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoVitaLife; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoGlobalPharmaceuticals = document.getElementById("newtokyo-globalpharmaceuticals"); - newTokyoGlobalPharmaceuticals.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoGlobalPharmaceuticals; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoNoodleBar = document.getElementById("newtokyo-noodlebar"); - newTokyoNoodleBar.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoNoodleBar; - Engine.loadLocationContent(); - return false; - }); - - let newTokyoSlums = document.getElementById("newtokyo-slums"); - newTokyoSlums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.NewTokyoSlums; - Engine.loadLocationContent(); - return false; - }); - - let ishimaTravelAgency = document.getElementById("ishima-travelagency"); - ishimaTravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.IshimaTravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let ishimaHospital = document.getElementById("ishima-hospital"); - ishimaHospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let ishimaStormTechnologies = document.getElementById("ishima-stormtechnologies"); - ishimaStormTechnologies.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.IshimaStormTechnologies; - Engine.loadLocationContent(); - return false; - }); - - let ishimaNovaMedical = document.getElementById("ishima-novamedical"); - ishimaNovaMedical.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.IshimaNovaMedical; - Engine.loadLocationContent(); - return false; - }); - - let ishimaOmegaSoftware = document.getElementById("ishima-omegasoftware"); - ishimaOmegaSoftware.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.IshimaOmegaSoftware; - Engine.loadLocationContent(); - return false; - }); - - let ishimaSlums = document.getElementById("ishima-slums"); - ishimaSlums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.IshimaSlums; - Engine.loadLocationContent(); - return false; - }); - - let volhavenTravelAgency = document.getElementById("volhaven-travelagency"); - volhavenTravelAgency.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenTravelAgency; - Engine.loadLocationContent(); - return false; - }); - - let volhavenHospital = document.getElementById("volhaven-hospital"); - volhavenHospital.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.Hospital; - Engine.loadLocationContent(); - return false; - }); - - let volhavenZBInstituteOfTechnology = document.getElementById("volhaven-zbinstituteoftechnology"); - volhavenZBInstituteOfTechnology.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenZBInstituteOfTechnology; - Engine.loadLocationContent(); - return false; - }); - - let volhavenOmniTekIncorporated = document.getElementById("volhaven-omnitekincorporated"); - volhavenOmniTekIncorporated.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenOmniTekIncorporated; - Engine.loadLocationContent(); - return false; - }); - - let volhavenNWO = document.getElementById("volhaven-nwo"); - volhavenNWO.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenNWO; - Engine.loadLocationContent(); - return false; - }); - - let volhavenHeliosLabs = document.getElementById("volhaven-helioslabs"); - volhavenHeliosLabs.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenHeliosLabs; - Engine.loadLocationContent(); - return false; - }); - - let volhavenOmniaCybersystems = document.getElementById("volhaven-omniacybersystems"); - volhavenOmniaCybersystems.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenOmniaCybersystems; - Engine.loadLocationContent(); - return false; - }); - - let volhavenLexoCorp = document.getElementById("volhaven-lexocorp"); - volhavenLexoCorp.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenLexoCorp; - Engine.loadLocationContent(); - return false; - }); - - let volhavenSysCoreSecurities = document.getElementById("volhaven-syscoresecurities"); - volhavenSysCoreSecurities.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenSysCoreSecurities; - Engine.loadLocationContent(); - return false; - }); - - let volhavenCompuTek = document.getElementById("volhaven-computek"); - volhavenCompuTek.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenCompuTek; - Engine.loadLocationContent(); - return false; - }); - - let volhavenMilleniumFitnessGym = document.getElementById("volhaven-milleniumfitnessgym"); - volhavenMilleniumFitnessGym.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenMilleniumFitnessGym; - Engine.loadLocationContent(); - return false; - }); - - let volhavenSlums = document.getElementById("volhaven-slums"); - volhavenSlums.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.location = Locations.VolhavenSlums; - Engine.loadLocationContent(); - return false; - }); - - //Buttons to interact at a location (apply for job/promotion, train, purchase, etc.) - var softwareJob = document.getElementById("location-software-job"); - var softwareConsultantJob = document.getElementById("location-software-consultant-job") - var itJob = document.getElementById("location-it-job"); - var securityEngineerJob = document.getElementById("location-security-engineer-job"); - var networkEngineerJob = document.getElementById("location-network-engineer-job"); - var businessJob = document.getElementById("location-business-job"); - var businessConsultantJob = document.getElementById("location-business-consultant-job"); - var securityJob = document.getElementById("location-security-job"); - var agentJob = document.getElementById("location-agent-job"); - var employeeJob = document.getElementById("location-employee-job"); - var employeePartTimeJob = document.getElementById("location-parttime-employee-job"); - var waiterJob = document.getElementById("location-waiter-job"); - var waiterPartTimeJob = document.getElementById("location-parttime-waiter-job"); - - var work = document.getElementById("location-work"); - - var purchase2gb = document.getElementById("location-purchase-2gb"); - var purchase4gb = document.getElementById("location-purchase-4gb"); - var purchase8gb = document.getElementById("location-purchase-8gb"); - var purchase16gb = document.getElementById("location-purchase-16gb"); - var purchase32gb = document.getElementById("location-purchase-32gb"); - var purchase64gb = document.getElementById("location-purchase-64gb"); - var purchase128gb = document.getElementById("location-purchase-128gb"); - var purchase256gb = document.getElementById("location-purchase-256gb"); - var purchase512gb = document.getElementById("location-purchase-512gb"); - var purchase1tb = document.getElementById("location-purchase-1tb"); - var purchaseTor = document.getElementById("location-purchase-tor"); - var purchaseHomeRam = document.getElementById("location-purchase-home-ram"); - var purchaseHomeCores = document.getElementById("location-purchase-home-cores"); - - var travelToAevum = document.getElementById("location-travel-to-aevum"); - var travelToChongqing = document.getElementById("location-travel-to-chongqing"); - var travelToSector12 = document.getElementById("location-travel-to-sector12"); - var travelToNewTokyo = document.getElementById("location-travel-to-newtokyo"); - var travelToIshima = document.getElementById("location-travel-to-ishima"); - var travelToVolhaven = document.getElementById("location-travel-to-volhaven"); - - var slumsShoplift = document.getElementById("location-slums-shoplift"); - var slumsRobStore = document.getElementById("location-slums-rob-store"); - var slumsMug = document.getElementById("location-slums-mug"); - var slumsLarceny = document.getElementById("location-slums-larceny"); - var slumsDealDrugs = document.getElementById("location-slums-deal-drugs"); - var slumsBondForgery = document.getElementById("location-slums-bond-forgery"); - var slumsTrafficArms = document.getElementById("location-slums-traffic-arms"); - var slumsHomicide = document.getElementById("location-slums-homicide"); - var slumsGta = document.getElementById("location-slums-gta"); - var slumsKidnap = document.getElementById("location-slums-kidnap"); - var slumsAssassinate = document.getElementById("location-slums-assassinate"); - var slumsHeist = document.getElementById("location-slums-heist"); - - var cityHallCreateCorporation = document.getElementById("location-cityhall-create-corporation"); - - var nsaBladeburner = document.getElementById("location-nsa-bladeburner"); - - const vitalifeResleeve = document.getElementById("location-vitalife-resleeve"); - - var hospitalTreatment = document.getElementById("location-hospital-treatment"); - - softwareJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForSoftwareJob(); - return false; - }); - - softwareConsultantJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForSoftwareConsultantJob(); - return false; - }); - - itJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForItJob(); - return false; - }); - - securityEngineerJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForSecurityEngineerJob(); - return false; - }); - - networkEngineerJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForNetworkEngineerJob(); - return false; - }); - - businessJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForBusinessJob(); - return false; - }); - - businessConsultantJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForBusinessConsultantJob(); - return false; - }); - - securityJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForSecurityJob(); - return false; - }); - - agentJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForAgentJob(); - return false; - }); - - employeeJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForEmployeeJob(); - return false; - }); - - employeePartTimeJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForPartTimeEmployeeJob(); - return false; - }); - - waiterJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForWaiterJob(); - return false; - }); - - waiterPartTimeJob.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Player.applyForPartTimeWaiterJob(); - return false; - }); - - purchase2gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(2); - return false; - }); - - purchase4gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(4); - return false; - }); - - purchase8gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(8); - return false; - }); - - purchase16gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(16); - return false; - }); - - purchase32gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(32); - return false; - }); - - purchase64gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(64); - return false; - }); - - purchase128gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(128); - return false; - }); - - purchase256gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(256); - return false; - }); - - purchase512gb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(512); - return false; - }); - - purchase1tb.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseServerBoxCreate(1024); - return false; - }); - - purchaseTor.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - purchaseTorRouter(); - return false; - }); - - purchaseHomeRam.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - const cost = Player.getUpgradeHomeRamCost(); - const ram = Player.getHomeComputer().maxRam; - - var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); - yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel"; - yesBtn.addEventListener("click", ()=>{ - purchaseRamForHomeComputer(cost); - yesNoBoxClose(); - }); - noBtn.addEventListener("click", ()=>{ - yesNoBoxClose(); - }); - yesNoBoxCreate("Would you like to purchase additional RAM for your home computer?

    " + - "This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB.

    " + - "This will cost " + numeralWrapper.format(cost, '$0.000a')); - }); - - purchaseHomeCores.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - var currentCores = Player.getHomeComputer().cpuCores; - if (currentCores >= 8) {return;} //Max of 8 cores - - //Cost of purchasing another cost is found by indexing this array with number of current cores - var cost = [0, - 10000000000, //1->2 Cores - 10 bn - 250000000000, //2->3 Cores - 250 bn - 5000000000000, //3->4 Cores - 5 trillion - 100000000000000, //4->5 Cores - 100 trillion - 1000000000000000, //5->6 Cores - 1 quadrillion - 20000000000000000, //6->7 Cores - 20 quadrillion - 200000000000000000]; //7->8 Cores - 200 quadrillion - cost = cost[currentCores]; - var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); - yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel"; - yesBtn.addEventListener("click", ()=>{ - if (Player.money.lt(cost)) { - dialogBoxCreate("You do not have enough money to purchase an additional CPU Core for your home computer!"); - } else { - Player.loseMoney(cost); - Player.getHomeComputer().cpuCores++; - dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " + - Player.getHomeComputer().cpuCores + " cores."); - } - yesNoBoxClose(); - }); - noBtn.addEventListener("click", ()=>{ - yesNoBoxClose(); - }); - yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " + - "lets you start with an additional Core Node in Hacking Missions.

    " + - "Purchasing an additional core (for a total of " + (Player.getHomeComputer().cpuCores + 1) + ") will " + - "cost " + numeralWrapper.format(cost, '$0.000a')); - }); - - travelToAevum.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.Aevum, CONSTANTS.TravelCost); - return false; - }); - - travelToChongqing.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.Chongqing, CONSTANTS.TravelCost); - return false; - }); - - travelToSector12.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.Sector12, CONSTANTS.TravelCost); - return false; - }); - - travelToNewTokyo.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.NewTokyo, CONSTANTS.TravelCost); - return false; - }); - - travelToIshima.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.Ishima, CONSTANTS.TravelCost); - return false; - }); - - travelToVolhaven.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - travelBoxCreate(Locations.Volhaven, CONSTANTS.TravelCost); - return false; - }); - - slumsShoplift.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Shoplift.commit(Player); - return false; - }); - - slumsRobStore.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.RobStore.commit(Player); - return false; - }); - - slumsMug.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Mug.commit(Player); - return false; - }); - - slumsLarceny.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Larceny.commit(Player); - return false; - }); - - slumsDealDrugs.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.DealDrugs.commit(Player); - return false; - }); - - slumsBondForgery.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.BondForgery.commit(Player); - return false; - }); - - slumsTrafficArms.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.TraffickArms.commit(Player); - return false; - }); - - slumsHomicide.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Homicide.commit(Player); - return false; - }); - - slumsGta.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.GrandTheftAuto.commit(Player); - return false; - }); - - slumsKidnap.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Kidnap.commit(Player); - return false; - }); - - slumsAssassinate.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Assassination.commit(Player); - return false; - }); - - slumsHeist.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - Crimes.Heist.commit(Player); - return false; - }); - - cityHallCreateCorporation.addEventListener("click", function() { - const popupId = "create-corporation-popup"; - const txt = createElement("p", { - innerHTML: "Would you like to start a corporation? This will require $150b for registration " + - "and initial funding. This $150b can either be self-funded, or you can obtain " + - "the seed money from the government in exchange for 500 million shares

    " + - "If you would like to start one, please enter a name for your corporation below:", - }); - - const nameInput = createElement("input", { - placeholder: "Corporation Name", - }); - - const selfFundedButton = createElement("button", { - class: "popup-box-button", - innerText: "Self-Fund", - clickListener: () => { - if (Player.money.lt(150e9)) { - dialogBoxCreate("You don't have enough money to create a corporation! You need $150b"); - return false; - } - Player.loseMoney(150e9); - - const companyName = nameInput.value; - if (companyName == null || companyName == "") { - dialogBoxCreate("Invalid company name!"); - return false; - } - - Player.corporation = new Corporation({ - name: companyName, - }); - - displayLocationContent(); - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - dialogBoxCreate("Congratulations! You just self-funded your own corporation. You can visit " + - "and manage your company in the City"); - removeElementById(popupId); - return false; - } - }); - - const seedMoneyButton = createElement("button", { - class: "popup-box-button", - innerText: "Use Seed Money", - clickListener: () => { - const companyName = nameInput.value; - if (companyName == null || companyName == "") { - dialogBoxCreate("Invalid company name!"); - return false; - } - - Player.corporation = new Corporation({ - name: companyName, - }); - Player.corporation.totalShares += 500e6; - - displayLocationContent(); - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - dialogBoxCreate("Congratulations! You just started your own corporation with government seed money. " + - "You can visit and manage your company in the City"); - removeElementById(popupId); - return false; - } - }) - - const cancelBtn = createPopupCloseButton(popupId, { class: "popup-box-button" }); - - if (Player.corporation instanceof Corporation) { - return; - } else { - createPopup(popupId, [txt, nameInput, cancelBtn, selfFundedButton, seedMoneyButton]); - nameInput.focus(); - } - }); - - nsaBladeburner.addEventListener("click", function() { - if (Player.bladeburner && Player.bladeburner instanceof Bladeburner) { - //Enter Bladeburner division - Engine.loadBladeburnerContent(); - } else { - //Apply for Bladeburner division - if (Player.strength >= 100 && Player.defense >= 100 && - Player.dexterity >= 100 && Player.agility >= 100) { - Player.bladeburner = new Bladeburner({new:true}); - dialogBoxCreate("You have been accepted into the Bladeburner division!"); - displayLocationContent(); - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - } else { - dialogBoxCreate("Rejected! Please apply again when you have 100 of each combat stat (str, def, dex, agi)"); - } - } - }); - - vitalifeResleeve.addEventListener("click", function() { - Engine.loadResleevingContent(); - }); - - hospitalTreatment.addEventListener("click", function(e) { - if (!e.isTrusted) {return false;} - if (Player.hp < 0) {Player.hp = 0;} - var price = (Player.max_hp - Player.hp) * CONSTANTS.HospitalCostPerHp; - Player.loseMoney(price); - dialogBoxCreate("You were healed to full health! The hospital billed " + - "you for $" + formatNumber(price, 2).toString()); - Player.hp = Player.max_hp; - displayLocationContent(); - return false; - }); -} - -function travelToCity(destCityName, cost) { - if (Player.firstTimeTraveled === false) { - Player.firstTimeTraveled = true; - document.getElementById("travel-tab").style.display = "list-item"; - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - } - - if (Player.money.lt(cost)) { - dialogBoxCreate("You cannot afford to travel to " + destCityName); - return; - } - Player.loseMoney(cost); - - Player.city = destCityName; - dialogBoxCreate("You are now in " + destCityName + "!"); - Engine.loadWorldContent(); -} - -function purchaseTorRouter() { - if (Player.money.lt(CONSTANTS.TorRouterCost)) { - dialogBoxCreate("You cannot afford to purchase the Tor router"); - return; - } - Player.loseMoney(CONSTANTS.TorRouterCost); - - var darkweb = new Server({ - ip:createRandomIp(), hostname:"darkweb", organizationName:"", - isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1 - }); - AddToAllServers(darkweb); - SpecialServerIps.addIp("Darkweb Server", darkweb.ip); - - const purchaseTor = document.getElementById("location-purchase-tor"); - purchaseTor.setAttribute("class", "a-link-button-bought"); - purchaseTor.innerHTML = "TOR Router - Purchased"; - - Player.getHomeComputer().serversOnNetwork.push(darkweb.ip); - darkweb.serversOnNetwork.push(Player.getHomeComputer().ip); - dialogBoxCreate("You have purchased a Tor router!
    You now have access to the dark web from your home computer
    Use the scan/scan-analyze commands to search for the dark web connection."); -} - -function displayUniversityLocationContent(costMult) { - var studyComputerScienceButton = document.getElementById("location-study-computer-science"); - var classDataStructuresButton = document.getElementById("location-data-structures-class"); - var classNetworksButton = document.getElementById("location-networks-class"); - var classAlgorithmsButton = document.getElementById("location-algorithms-class"); - var classManagementButton = document.getElementById("location-management-class"); - var classLeadershipButton = document.getElementById("location-leadership-class"); - studyComputerScienceButton.style.display = "block"; - classDataStructuresButton.style.display = "block"; - classNetworksButton.style.display = "block"; - classAlgorithmsButton.style.display = "block"; - classManagementButton.style.display = "block"; - classLeadershipButton.style.display = "block"; - - //Costs (per second) - var dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult; - var networksCost = CONSTANTS.ClassNetworksBaseCost * costMult; - var algorithmsCost = CONSTANTS.ClassAlgorithmsBaseCost * costMult; - var managementCost = CONSTANTS.ClassManagementBaseCost * costMult; - var leadershipCost = CONSTANTS.ClassLeadershipBaseCost * costMult; - - //Update button text to show cost - classDataStructuresButton.innerHTML = "Take Data Structures course ($" + dataStructuresCost + " / sec)"; - classNetworksButton.innerHTML = "Take Networks course ($" + networksCost + " / sec)"; - classAlgorithmsButton.innerHTML = "Take Algorithms course ($" + algorithmsCost + " / sec)"; - classManagementButton.innerHTML = "Take Management course ($" + managementCost + " / sec)"; - classLeadershipButton.innerHTML = "Take Leadership course ($" + leadershipCost + " / sec)"; -} - -function setUniversityLocationButtons(costMult, expMult) { - var newStudyCS = clearEventListeners("location-study-computer-science"); - newStudyCS.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassStudyComputerScience); - return false; - }); - - var newClassDataStructures = clearEventListeners("location-data-structures-class"); - newClassDataStructures.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassDataStructures); - return false; - }); - - var newClassNetworks = clearEventListeners("location-networks-class"); - newClassNetworks.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassNetworks); - return false; - }); - - var newClassAlgorithms = clearEventListeners("location-algorithms-class"); - newClassAlgorithms.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassAlgorithms); - return false; - }); - - var newClassManagement = clearEventListeners("location-management-class"); - newClassManagement.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassManagement); - return false; - }); - - var newClassLeadership = clearEventListeners("location-leadership-class"); - newClassLeadership.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassLeadership); - return false; - }); -} - -function displayGymLocationContent(costMult) { - var gymStrButton = document.getElementById("location-gym-train-str"); - var gymDefButton = document.getElementById("location-gym-train-def"); - var gymDexButton = document.getElementById("location-gym-train-dex"); - var gymAgiButton = document.getElementById("location-gym-train-agi"); - gymStrButton.style.display = "block"; - gymDefButton.style.display = "block"; - gymDexButton.style.display = "block"; - gymAgiButton.style.display = "block"; - - //Costs (per second) - var cost = CONSTANTS.ClassGymBaseCost * costMult; - - //Update button text to show cost - gymStrButton.innerHTML = "Train Strength ($" + cost + " / sec)"; - gymDefButton.innerHTML = "Train Defense ($" + cost + " / sec)"; - gymDexButton.innerHTML = "Train Dexterity ($" + cost + " / sec)"; - gymAgiButton.innerHTML = "Train Agility ($" + cost + " / sec)"; -} - -function setGymLocationButtons(costMult, expMult) { - var gymStr = clearEventListeners("location-gym-train-str"); - gymStr.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassGymStrength); - return false; - }); - - var gymDef = clearEventListeners("location-gym-train-def"); - gymDef.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassGymDefense); - return false; - }); - - var gymDex = clearEventListeners("location-gym-train-dex"); - gymDex.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassGymDexterity); - return false; - }); - - var gymAgi = clearEventListeners("location-gym-train-agi"); - gymAgi.addEventListener("click", function() { - Player.startClass(costMult, expMult, CONSTANTS.ClassGymAgility); - return false; - }); -} - -function setInfiltrateButton(btn, companyName, startLevel, val, maxClearance, difficulty) { - btn.style.display = "block"; - btn.addEventListener("click", function() { - Engine.loadInfiltrationContent(); - beginInfiltration(companyName, startLevel, val, maxClearance, difficulty) - return false; - }); -} - -//Finds the next target job for the player at the given company (loc) and -//adds the tooltiptext to the Application button, given by 'button' -function setJobRequirementTooltip(loc, entryPosType, btn) { - var company = Companies[loc]; - if (company == null) {return;} - var pos = Player.getNextCompanyPosition(company, entryPosType); - if (pos == null) { return }; - if (!company.hasPosition(pos)) { return; } - var reqText = getJobRequirementText(company, pos, true); - btn.innerHTML += "" + reqText + ""; -} - -function travelBoxCreate(destCityName, cost) { - if(Settings.SuppressTravelConfirmation) { - travelToCity(destCityName, cost); - return; - } - var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); - yesBtn.innerHTML = "Yes"; - noBtn.innerHTML = "No"; - noBtn.addEventListener("click", () => { - yesNoBoxClose(); - return false; - }); - yesBtn.addEventListener("click", () => { - yesNoBoxClose(); - travelToCity(destCityName, cost); - return false; - }); - yesNoBoxCreate("Would you like to travel to " + destCityName + "? The trip will cost $" + formatNumber(cost, 2) + "."); -} - -function purchaseServerBoxCreate(ram) { - const cost = getPurchaseServerCost(ram); - if (cost === Infinity) { - dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer"); - return; - } - - var yesBtn = yesNoTxtInpBoxGetYesButton(); - var noBtn = yesNoTxtInpBoxGetNoButton(); - yesBtn.innerHTML = "Purchase Server"; - noBtn.innerHTML = "Cancel"; - yesBtn.addEventListener("click", function() { - purchaseServer(ram); - yesNoTxtInpBoxClose(); - }); - noBtn.addEventListener("click", function() { - yesNoTxtInpBoxClose(); - }); - - yesNoTxtInpBoxCreate("Would you like to purchase a new server with " + ram + - "GB of RAM for $" + formatNumber(cost, 2) + "?

    " + - "Please enter the server hostname below:
    "); -} - -export {displayLocationContent, initLocationButtons}; diff --git a/src/Locations/Location.ts b/src/Locations/Location.ts index 8667e4d86..7c67efc85 100644 --- a/src/Locations/Location.ts +++ b/src/Locations/Location.ts @@ -5,8 +5,18 @@ import { CityName } from "./data/CityNames"; import { LocationName } from "./data/LocationNames"; import { LocationType } from "./LocationTypeEnum"; +interface IInfiltrationMetadata { + baseRewardValue: number; + difficulty: number; + maxClearanceLevel: number; + startingSecurityLevel: number; +} + export interface IConstructorParams { city?: CityName | null; + costMult?: number; + expMult?: number; + infiltrationData?: IInfiltrationMetadata; name?: LocationName; types?: LocationType[]; techVendorMaxRam?: number; @@ -20,6 +30,22 @@ export class Location { */ city: CityName | null = null; + /** + * Cost multiplier that influences how expensive a gym/university is + */ + costMult: number = 0; + + /** + * Exp multiplier that influences how effective a gym/university is + */ + expMult: number = 0; + + /** + * Companies can be infiltrated. This contains the data required for that + * infiltration event + */ + infiltrationData?: IInfiltrationMetadata; + /** * Identifier for location */ @@ -45,6 +71,9 @@ export class Location { constructor(p: IConstructorParams) { if (p.city) { this.city = p.city; } + if (p.costMult) { this.costMult = p.costMult; } + if (p.expMult) { this.expMult = p.expMult; } + if (p.infiltrationData) { this.infiltrationData = p.infiltrationData; } if (p.name) { this.name = p.name; } if (p.types) { this.types = p.types; } if (p.techVendorMaxRam) { this.techVendorMaxRam = p.techVendorMaxRam; } diff --git a/src/Locations/LocationsHelpers.js b/src/Locations/LocationsHelpers.js deleted file mode 100644 index cfa7e3b98..000000000 --- a/src/Locations/LocationsHelpers.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Location and traveling-related helper functions. - * Mostly used for UI - */ -import { Player } from "../Player"; - -import { Company } from "../Company/Company"; -import { getJobRequirementText } from "../Company/GetJobRequirementText"; -import * as posNames from "../Company/data/companypositionnames"; diff --git a/src/Locations/LocationsHelpers.ts b/src/Locations/LocationsHelpers.ts new file mode 100644 index 000000000..2ee71338c --- /dev/null +++ b/src/Locations/LocationsHelpers.ts @@ -0,0 +1,281 @@ +/** + * Location and traveling-related helper functions. + * Mostly used for UI + */ +import { CONSTANTS } from "../Constants"; + +import { CityName } from "./data/CityNames"; + +import { IPlayer } from "../PersonObjects/IPlayer"; +import { AllServers, + AddToAllServers } from "../Server/AllServers"; +import { Server } from "../Server/Server"; +import { getPurchaseServerCost, + purchaseRamForHomeComputer, + purchaseServer } from "../Server/ServerPurchases"; +import { SpecialServerIps } from "../Server/SpecialServerIps"; +import { Settings } from "../Settings/Settings"; + +import { numeralWrapper } from "../ui/numeralFormat"; + +import { dialogBoxCreate } from "../../utils/DialogBox"; +import { createRandomIp } from "../../utils/IPAddress"; +import { yesNoBoxGetYesButton, + yesNoBoxGetNoButton, + yesNoBoxClose, + yesNoBoxCreate, + yesNoTxtInpBoxGetYesButton, + yesNoTxtInpBoxGetNoButton, + yesNoTxtInpBoxClose, + yesNoTxtInpBoxCreate } from "../../utils/YesNoBox"; + +import { createElement } from "../../utils/uiHelpers/createElement"; +import { createPopup } from "../../utils/uiHelpers/createPopup"; +import { createPopupCloseButton } from "../../utils/uiHelpers/createPopupCloseButton"; +import { removeElementById } from "../../utils/uiHelpers/removeElementById"; + +/** + * Create a pop-up box that lets the player confirm traveling to a different city + * If settings are configured to suppress this popup, just instantly travel + * The actual "Travel" implementation is implemented in the UI, and is passed in + * as an argument + */ +type TravelFunction = (to: CityName) => void; +export function createTravelPopup(destination: CityName, travelFn: TravelFunction) { + const cost = CONSTANTS.TravelCost; + + if (Settings.SuppressTravelConfirmation) { + travelFn(destination); + return; + } + + const yesBtn = yesNoBoxGetYesButton(); + const noBtn = yesNoBoxGetNoButton(); + if (yesBtn == null || noBtn == null) { + console.warn(`Could nto find YesNo pop-up box buttons`); + return; + } + + yesBtn.innerHTML = "Yes"; + yesBtn.addEventListener("click", () => { + yesNoBoxClose(); + travelFn(destination); + return false; + }); + + noBtn.innerHTML = "No"; + noBtn.addEventListener("click", () => { + yesNoBoxClose(); + return false; + }); + + yesNoBoxCreate(`Would you like to travel to ${destination}? The trip will ` + + `cost ${numeralWrapper.formatMoney(cost)}`); +} + +/** + * Create a pop-up box that lets the player purchase a server. + * @param ram - Amount of RAM (GB) on server + * @param p - Player object + */ +export function createPurchaseServerPopup(ram: number, p: IPlayer) { + const cost = getPurchaseServerCost(ram); + if (cost === Infinity) { + dialogBoxCreate("Something went wrong when trying to purchase this server. Please contact developer"); + return; + } + + var yesBtn = yesNoTxtInpBoxGetYesButton(); + var noBtn = yesNoTxtInpBoxGetNoButton(); + if (yesBtn == null || noBtn == null) { return; } + yesBtn.innerHTML = "Purchase Server"; + noBtn.innerHTML = "Cancel"; + yesBtn.addEventListener("click", function() { + purchaseServer(ram, p); + yesNoTxtInpBoxClose(); + }); + noBtn.addEventListener("click", function() { + yesNoTxtInpBoxClose(); + }); + + yesNoTxtInpBoxCreate("Would you like to purchase a new server with " + ram + + "GB of RAM for $" + numeralWrapper.formatMoney(cost) + "?

    " + + "Please enter the server hostname below:
    "); +} + +/** + * Create a popup that lets the player start a Corporation + */ +export function createStartCorporationPopup(p: IPlayer) { + if (p.hasCorporation) { return; } + + const popupId = "create-corporation-popup"; + const txt = createElement("p", { + innerHTML: "Would you like to start a corporation? This will require $150b for registration " + + "and initial funding. This $150b can either be self-funded, or you can obtain " + + "the seed money from the government in exchange for 500 million shares

    " + + "If you would like to start one, please enter a name for your corporation below:", + }); + + const nameInput = createElement("input", { + placeholder: "Corporation Name", + }) as HTMLInputElement; + + const selfFundedButton = createElement("button", { + class: "popup-box-button", + innerText: "Self-Fund", + clickListener: () => { + if (!p.canAfford(150e9)) { + dialogBoxCreate("You don't have enough money to create a corporation! You need $150b"); + return false; + } + p.loseMoney(150e9); + + const companyName = nameInput.value; + if (companyName == null || companyName == "") { + dialogBoxCreate("Invalid company name!"); + return false; + } + + p.startCorporation(companyName); + + const worldHeader = document.getElementById("world-menu-header"); + if (worldHeader instanceof HTMLElement) { + worldHeader.click(); worldHeader.click(); + } + dialogBoxCreate("Congratulations! You just self-funded your own corporation. You can visit " + + "and manage your company in the City"); + removeElementById(popupId); + return false; + } + }); + + const seedMoneyButton = createElement("button", { + class: "popup-box-button", + innerText: "Use Seed Money", + clickListener: () => { + const companyName = nameInput.value; + if (companyName == null || companyName == "") { + dialogBoxCreate("Invalid company name!"); + return false; + } + + p.startCorporation(companyName, 500e6); + + const worldHeader = document.getElementById("world-menu-header"); + if (worldHeader instanceof HTMLElement) { + worldHeader.click(); worldHeader.click(); + } + dialogBoxCreate("Congratulations! You just started your own corporation with government seed money. " + + "You can visit and manage your company in the City"); + removeElementById(popupId); + return false; + } + }) + + const cancelBtn = createPopupCloseButton(popupId, { class: "popup-box-button" }); + + createPopup(popupId, [txt, nameInput, cancelBtn, selfFundedButton, seedMoneyButton]); + nameInput.focus(); +} + +/** + * Create a popup that lets the player upgrade the cores on his/her home computer + * @param p - Player object + */ +export function createUpgradeHomeCoresPopup(p: IPlayer) { + const currentCores = p.getHomeComputer().cpuCores; + if (currentCores >= 8) { return; } // Max of 8 cores + + //Cost of purchasing another cost is found by indexing this array with number of current cores + const allCosts = [0, + 10e9, // 1->2 Cores - 10 bn + 250e9, // 2->3 Cores - 250 bn + 5e12, // 3->4 Cores - 5 trillion + 100e12, // 4->5 Cores - 100 trillion + 1e15, // 5->6 Cores - 1 quadrillion + 20e15, // 6->7 Cores - 20 quadrillion + 200e15]; // 7->8 Cores - 200 quadrillion + const cost: number = allCosts[currentCores]; + + const yesBtn = yesNoBoxGetYesButton(); + const noBtn = yesNoBoxGetNoButton(); + if (yesBtn == null || noBtn == null) { return; } + + yesBtn.innerHTML = "Purchase"; + yesBtn.addEventListener("click", ()=>{ + if (!p.canAfford(cost)) { + dialogBoxCreate("You do not have enough money to purchase an additional CPU Core for your home computer!"); + } else { + p.loseMoney(cost); + p.getHomeComputer().cpuCores++; + dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " + + p.getHomeComputer().cpuCores + " cores."); + } + yesNoBoxClose(); + }); + + noBtn.innerHTML = "Cancel"; + noBtn.addEventListener("click", ()=>{ + yesNoBoxClose(); + }); + + yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " + + "lets you start with an additional Core Node in Hacking Missions.

    " + + "Purchasing an additional core (for a total of " + (p.getHomeComputer().cpuCores + 1) + ") will " + + "cost " + numeralWrapper.formatMoney(cost)); +} + +/** + * Create a popup that lets the player upgrade the RAM on his/her home computer + * @param p - Player object + */ +export function createUpgradeHomeRamPopup(p: IPlayer) { + const cost: number = p.getUpgradeHomeRamCost(); + const ram: number = p.getHomeComputer().maxRam; + + const yesBtn = yesNoBoxGetYesButton(); + const noBtn = yesNoBoxGetNoButton(); + if (yesBtn == null || noBtn == null) { return; } + + yesBtn.innerText = "Purchase"; + yesBtn.addEventListener("click", ()=>{ + purchaseRamForHomeComputer(cost, p); + yesNoBoxClose(); + }); + + noBtn.innerText = "Cancel"; + noBtn.addEventListener("click", ()=>{ + yesNoBoxClose(); + }); + + yesNoBoxCreate("Would you like to purchase additional RAM for your home computer?

    " + + "This will upgrade your RAM from " + ram + "GB to " + ram*2 + "GB.

    " + + "This will cost " + numeralWrapper.format(cost, '$0.000a')); +} + + +/** + * Attempt to purchase a TOR router + * @param p - Player object + */ +export function purchaseTorRouter(p: IPlayer) { + if (!p.canAfford(CONSTANTS.TorRouterCost)) { + dialogBoxCreate("You cannot afford to purchase the Tor router"); + return; + } + p.loseMoney(CONSTANTS.TorRouterCost); + + const darkweb = new Server({ + ip: createRandomIp(), hostname:"darkweb", organizationName:"", + isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1 + }); + AddToAllServers(darkweb); + SpecialServerIps.addIp("Darkweb Server", darkweb.ip); + + p.getHomeComputer().serversOnNetwork.push(darkweb.ip); + darkweb.serversOnNetwork.push(p.getHomeComputer().ip); + dialogBoxCreate("You have purchased a Tor router!
    " + + "You now have access to the dark web from your home computer
    " + + "Use the scan/scan-analyze commands to search for the dark web connection."); +} diff --git a/src/Locations/data/LocationNames.ts b/src/Locations/data/LocationNames.ts index af0d56157..90ef33e04 100644 --- a/src/Locations/data/LocationNames.ts +++ b/src/Locations/data/LocationNames.ts @@ -21,17 +21,13 @@ export enum LocationName { AevumNetLinkTechnologies = "NetLink Technologies", AevumPolice = "Aevum Police Headquarters", AevumRhoConstruction = "Rho Construction", - AevumSlums = "Aevum Slums", // TODO Delete this and other Slums locations AevumSnapFitnessGym = "Snap Fitness Gym", AevumSummitUniversity = "Summit University", - AevumTravelAgency = "Aevum Travel Agency", // TODO Delete this and other travel agency locations AevumWatchdogSecurity = "Watchdog Security", // Chongqing locations ChongqingKuaiGongInternational = "KuaiGong International", - ChongqingSlums = "Chongqing Slums", ChongqingSolarisSpaceSystems = "Solaris Space Systems", - ChongqingTravelAgency = "Chongqing Travel Agency", // Sector 12 Sector12AlphaEnterprises = "Alpha Enterprises", @@ -49,24 +45,18 @@ export enum LocationName { Sector12NSA = "National Security Agency", Sector12PowerhouseGym = "Powerhouse Gym", Sector12RothmanUniversity = "Rothman University", - Sector12Slums = "Sector-12 Slums", - Sector12TravelAgency = "Sector-12 Travel Agency", Sector12UniversalEnergy = "Universal Energy", // New Tokyo NewTokyoDefComm = "DefComm", NewTokyoGlobalPharmaceuticals = "Global Pharmaceuticals", NewTokyoNoodleBar = "Noodle Bar", - NewTokyoSlums = "New Tokyo Slums", - NewTokyoTravelAgency = "New Tokyo Travel Agency", NewTokyoVitaLife = "VitaLife", // Ishima IshimaNovaMedical = "Nova Medical", IshimaOmegaSoftware = "Omega Software", - IshimaSlums = "Ishima Slums", IshimaStormTechnologies = "Storm Technologies", - IshimaTravelAgency = "Ishima Travel Agency", // Volhaven VolhavenCompuTek = "CompuTek", @@ -76,9 +66,7 @@ export enum LocationName { VolhavenNWO = "NWO", VolhavenOmniTekIncorporated = "OmniTek Incorporated", VolhavenOmniaCybersystems = "Omnia Cybersystems", - VolhavenSlums = "Volhaven Slums", VolhavenSysCoreSecurities = "SysCore Securities", - VolhavenTravelAgency = "Volhaven Travel Agency", VolhavenZBInstituteOfTechnology = "ZB Institute of Technology", // Generic locations diff --git a/src/Locations/data/LocationsMetadata.ts b/src/Locations/data/LocationsMetadata.ts index 0b80019d1..f8e4979ff 100644 --- a/src/Locations/data/LocationsMetadata.ts +++ b/src/Locations/data/LocationsMetadata.ts @@ -10,26 +10,52 @@ import { LocationType } from "../LocationTypeEnum"; export const LocationsMetadata: IConstructorParams[] = [ { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 32, + difficulty: 4.4, + maxClearanceLevel: 50, + startingSecurityLevel: 1350, + }, name: LocationName.AevumAeroCorp, types: [LocationType.Company], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 42, + difficulty: 4.1, + maxClearanceLevel: 60, + startingSecurityLevel: 1350, + }, name: LocationName.AevumBachmanAndAssociates, types: [LocationType.Company], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 34, + difficulty: 3.6, + maxClearanceLevel: 75, + startingSecurityLevel: 1800, + }, name: LocationName.AevumClarkeIncorporated, types: [LocationType.Company], }, { city: CityName.Aevum, + costMult: 3, + expMult: 2, name: LocationName.AevumCrushFitnessGym, types: [LocationType.Gym], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 116, + difficulty: 6, + maxClearanceLevel: 150, + startingSecurityLevel: 4800, + }, name: LocationName.AevumECorp, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 512, @@ -37,6 +63,12 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 96, + difficulty: 6.2, + maxClearanceLevel: 100, + startingSecurityLevel: 4140, + }, name: LocationName.AevumFulcrumTechnologies, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 1024, @@ -44,11 +76,23 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 30, + difficulty: 3.95, + maxClearanceLevel: 50, + startingSecurityLevel: 1260, + }, name: LocationName.AevumGalacticCybersystems, types: [LocationType.Company], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 10, + difficulty: 1.4, + maxClearanceLevel: 25, + startingSecurityLevel: 144, + }, name: LocationName.AevumNetLinkTechnologies, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 64, @@ -56,46 +100,92 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 18, + difficulty: 2.2, + maxClearanceLevel: 25, + startingSecurityLevel: 565, + }, name: LocationName.AevumPolice, types: [LocationType.Company], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 16, + difficulty: 1.9, + maxClearanceLevel: 20, + startingSecurityLevel: 485, + }, name: LocationName.AevumRhoConstruction, types: [LocationType.Company], }, { city: CityName.Aevum, + costMult: 10, + expMult: 5, name: LocationName.AevumSnapFitnessGym, types: [LocationType.Gym], }, { city: CityName.Aevum, + costMult: 4, + expMult: 3, name: LocationName.AevumSummitUniversity, types: [LocationType.University], }, { city: CityName.Aevum, + infiltrationData: { + baseRewardValue: 20, + difficulty: 3, + maxClearanceLevel: 30, + startingSecurityLevel: 690, + }, name: LocationName.AevumWatchdogSecurity, types: [LocationType.Company], }, { city: CityName.Chongqing, + infiltrationData: { + baseRewardValue: 100, + difficulty: 6.1, + maxClearanceLevel: 100, + startingSecurityLevel: 4450, + }, name: LocationName.ChongqingKuaiGongInternational, types: [LocationType.Company], }, { city: CityName.Chongqing, + infiltrationData: { + baseRewardValue: 52, + difficulty: 6, + maxClearanceLevel: 75, + startingSecurityLevel: 2915, + }, name: LocationName.ChongqingSolarisSpaceSystems, types: [LocationType.Company], }, { city: CityName.Ishima, + infiltrationData: { + baseRewardValue: 20, + difficulty: 3.2, + maxClearanceLevel: 50, + startingSecurityLevel: 485, + }, name: LocationName.IshimaNovaMedical, types: [LocationType.Company], }, { city: CityName.Ishima, + infiltrationData: { + baseRewardValue: 10, + difficulty: 1.6, + maxClearanceLevel: 40, + startingSecurityLevel: 130, + }, name: LocationName.IshimaOmegaSoftware, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 128, @@ -103,6 +193,12 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Ishima, + infiltrationData: { + baseRewardValue: 24, + difficulty: 4.1, + maxClearanceLevel: 100, + startingSecurityLevel: 570, + }, name: LocationName.IshimaStormTechnologies, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 512, @@ -110,11 +206,23 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.NewTokyo, + infiltrationData: { + baseRewardValue: 28, + difficulty: 4, + maxClearanceLevel: 70, + startingSecurityLevel: 1050, + }, name: LocationName.NewTokyoDefComm, types: [LocationType.Company], }, { city: CityName.NewTokyo, + infiltrationData: { + baseRewardValue: 24, + difficulty: 3.8, + maxClearanceLevel: 80, + startingSecurityLevel: 700, + }, name: LocationName.NewTokyoGlobalPharmaceuticals, types: [LocationType.Company], }, @@ -125,11 +233,23 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.NewTokyo, + infiltrationData: { + baseRewardValue: 22, + difficulty: 3.5, + maxClearanceLevel: 100, + startingSecurityLevel: 605, + }, name: LocationName.NewTokyoVitaLife, types: [LocationType.Company, LocationType.Special], }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 14, + difficulty: 2.25, + maxClearanceLevel: 40, + startingSecurityLevel: 200, + }, name: LocationName.Sector12AlphaEnterprises, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 8, @@ -137,6 +257,12 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 46, + difficulty: 4.2, + maxClearanceLevel: 100, + startingSecurityLevel: 2160, + }, name: LocationName.Sector12BladeIndustries, types: [LocationType.Company], }, @@ -147,6 +273,12 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 18, + difficulty: 2.5, + maxClearanceLevel: 60, + startingSecurityLevel: 405, + }, name: LocationName.Sector12CarmichaelSecurity, types: [LocationType.Company], }, @@ -157,6 +289,12 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 24, + difficulty: 4.3, + maxClearanceLevel: 50, + startingSecurityLevel: 700, + }, name: LocationName.Sector12DeltaOne, types: [LocationType.Company], }, @@ -167,26 +305,52 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 58, + difficulty: 7, + maxClearanceLevel: 100, + startingSecurityLevel: 1350, + }, name: LocationName.Sector12FourSigma, types: [LocationType.Company], }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 32, + difficulty: 5.4, + maxClearanceLevel: 70, + startingSecurityLevel: 730, + }, name: LocationName.Sector12IcarusMicrosystems, types: [LocationType.Company], }, { city: CityName.Sector12, + expMult: 1, + costMult: 1, name: LocationName.Sector12IronGym, types: [LocationType.Gym], }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 8, + difficulty: 1.8, + maxClearanceLevel: 20, + startingSecurityLevel: 120, + }, name: LocationName.Sector12JoesGuns, types: [LocationType.Company], }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 114, + difficulty: 6.75, + maxClearanceLevel: 125, + startingSecurityLevel: 4500, + }, name: LocationName.Sector12MegaCorp, types: [LocationType.Company], }, @@ -197,21 +361,37 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Sector12, + costMult: 20, + expMult: 10, name: LocationName.Sector12PowerhouseGym, types: [LocationType.Gym], }, { city: CityName.Sector12, + costMult: 3, + expMult: 2, name: LocationName.Sector12RothmanUniversity, types: [LocationType.University], }, { city: CityName.Sector12, + infiltrationData: { + baseRewardValue: 24, + difficulty: 4.3, + maxClearanceLevel: 50, + startingSecurityLevel: 700, + }, name: LocationName.Sector12UniversalEnergy, types: [LocationType.Company], }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 12, + difficulty: 2.1, + maxClearanceLevel: 60, + startingSecurityLevel: 195, + }, name: LocationName.VolhavenCompuTek, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 256, @@ -219,26 +399,52 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 28, + difficulty: 3, + maxClearanceLevel: 75, + startingSecurityLevel: 1080, + }, name: LocationName.VolhavenHeliosLabs, types: [LocationType.Company], }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 14, + difficulty: 2, + maxClearanceLevel: 60, + startingSecurityLevel: 340, + }, name: LocationName.VolhavenLexoCorp, types: [LocationType.Company], }, { city: CityName.Volhaven, + costMult: 7, + expMult: 4, name: LocationName.VolhavenMilleniumFitnessGym, types: [LocationType.Gym], }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 56, + difficulty: 6.8, + maxClearanceLevel: 200, + startingSecurityLevel: 1460, + }, name: LocationName.VolhavenNWO, types: [LocationType.Company], }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 44, + difficulty: 4.4, + maxClearanceLevel: 100, + startingSecurityLevel: 1215, + }, name: LocationName.VolhavenOmniTekIncorporated, types: [LocationType.Company, LocationType.TechVendor], techVendorMaxRam: 1024, @@ -246,16 +452,30 @@ export const LocationsMetadata: IConstructorParams[] = [ }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 28, + difficulty: 4.9, + maxClearanceLevel: 90, + startingSecurityLevel: 725, + }, name: LocationName.VolhavenOmniaCybersystems, types: [LocationType.Company], }, { city: CityName.Volhaven, + infiltrationData: { + baseRewardValue: 18, + difficulty: 2.4, + maxClearanceLevel: 75, + startingSecurityLevel: 430, + }, name: LocationName.VolhavenSysCoreSecurities, types: [LocationType.Company], }, { city: CityName.Volhaven, + costMult: 5, + expMult: 4, name: LocationName.VolhavenZBInstituteOfTechnology, types: [LocationType.University], }, diff --git a/src/Locations/ui/ApplyToJobButton.tsx b/src/Locations/ui/ApplyToJobButton.tsx new file mode 100644 index 000000000..993cfce68 --- /dev/null +++ b/src/Locations/ui/ApplyToJobButton.tsx @@ -0,0 +1,46 @@ +/** + * React Component for a button that's used to apply for a job + */ +import * as React from "react"; + +import { Company } from "../../Company/Company"; +import { CompanyPosition } from "../../Company/CompanyPosition"; +import { getJobRequirementText } from "../../Company/GetJobRequirementText"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { StdButton } from "../../ui/React/StdButton"; + +type IProps = { + company: Company; + entryPosType: CompanyPosition; + onClick: (e: React.MouseEvent) => void; + p: IPlayer; + text: string; +} + +export class ApplyToJobButton extends React.Component { + constructor(props: IProps) { + super(props); + + this.getJobRequirementTooltip = this.getJobRequirementTooltip.bind(this); + } + + getJobRequirementTooltip(): string { + const pos = this.props.p.getNextCompanyPosition(this.props.company, this.props.entryPosType); + if (pos == null) { return "" }; + + if (!this.props.company.hasPosition(pos)) { return ""; } + + return getJobRequirementText(this.props.company, pos, true); + } + + render() { + return ( + + ) + } +} diff --git a/src/Locations/ui/CompanyLocation.tsx b/src/Locations/ui/CompanyLocation.tsx index fb8147d64..204c28310 100644 --- a/src/Locations/ui/CompanyLocation.tsx +++ b/src/Locations/ui/CompanyLocation.tsx @@ -1,19 +1,29 @@ /** - * React Component for displaying a location's UI, when that location is a company + * React Subcomponent for displaying a location's UI, when that location is a company + * + * This subcomponent renders all of the buttons for applying to jobs at a company */ import * as React from "react"; -import { LocationName } from "../data/LocationNames"; +import { ApplyToJobButton } from "./ApplyToJobButton"; -import { Companies } from "../../Company/Companies"; -import { Company } from "../../Company/Company"; -import { CompanyPosition } from "../../Company/CompanyPosition"; -import { IPlayer } from "../../PersonObjects/IPlayer"; +import { Location } from "../Location"; +import { Locations } from "../Locations"; +import { LocationName } from "../data/LocationNames"; -import { StdButton } from "../../ui/React/StdButton"; -import { StdButtonWithTooltip } from "../../ui/React/StdButtonWithTooltip"; +import { IEngine } from "../../IEngine"; +import { beginInfiltration } from "../../Infiltration"; + +import { Companies } from "../../Company/Companies"; +import { Company } from "../../Company/Company"; +import { CompanyPositions } from "../../Company/CompanyPositions"; +import * as posNames from "../../Company/data/companypositionnames"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { StdButton } from "../../ui/React/StdButton"; type IProps = { + engine: IEngine; locName: LocationName; p: IPlayer; } @@ -25,6 +35,11 @@ export class CompanyLocation extends React.Component { */ company: Company; + /** + * Reference to the Location that this component is being rendered for + */ + location: Location; + constructor(props: IProps) { super(props); @@ -39,6 +54,12 @@ export class CompanyLocation extends React.Component { this.applyForSoftwareConsultantJob = this.applyForSoftwareConsultantJob.bind(this); this.applyForSoftwareJob = this.applyForSoftwareJob.bind(this); this.applyForWaiterJob = this.applyForWaiterJob.bind(this); + this.startInfiltration = this.startInfiltration.bind(this); + + this.location = Locations[props.locName]; + if (this.location == null) { + throw new Error(`CompanyLocation component constructed with invalid location: ${props.locName}`); + } this.company = Companies[props.locName]; if (this.company == null) { @@ -101,24 +122,136 @@ export class CompanyLocation extends React.Component { this.props.p.applyForWaiterJob(); } - getJobRequirementTooltip(company: Company, entryPosType: CompanyPosition) { - if (!(company instanceof Company)) { return; } + startInfiltration(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + const loc = this.location; - const pos = this.props.p.getNextCompanyPosition(company, entryPosType); - if (pos == null) { return }; + this.props.engine.loadInfiltrationContent(); - if (!company.hasPosition(pos)) { return; } - - return getJobRequirementText(company, pos, true); + const data = loc.infiltrationData; + if (data == null) { return false; } + beginInfiltration(this.props.locName, data.startingSecurityLevel, data.baseRewardValue, data.maxClearanceLevel, data.difficulty); } - render() { return (
    { this.company.hasAgentPositions() && - + } + { + this.company.hasBusinessConsultantPositions() && + + } + { + this.company.hasBusinessPositions() && + + } + { + this.company.hasEmployeePositions() && + + } + { + this.company.hasEmployeePositions() && + + } + { + this.company.hasITPositions() && + + } + { + this.company.hasSecurityPositions() && + + } + { + this.company.hasSoftwareConsultantPositions() && + + } + { + this.company.hasSoftwarePositions() && + + } + { + this.company.hasWaiterPositions() && + + } + { + this.company.hasWaiterPositions() && + + } + { + (this.location.infiltrationData != null) && + }
    ) diff --git a/src/Locations/ui/GenericLocation.tsx b/src/Locations/ui/GenericLocation.tsx index e5c37d32a..6ed4038fa 100644 --- a/src/Locations/ui/GenericLocation.tsx +++ b/src/Locations/ui/GenericLocation.tsx @@ -6,36 +6,33 @@ */ import * as React from "react"; -import { Location } from "../Location"; -import { Locations } from "../Locations"; -import { LocationType } from "../LocationTypeEnum"; -import { LocationName } from "../data/LocationNames"; +import { CompanyLocation } from "./CompanyLocation"; +import { GymLocation } from "./GymLocation"; +import { HospitalLocation } from "./HospitalLocation"; +import { SlumsLocation } from "./SlumsLocation"; +import { SpecialLocation } from "./SpecialLocation"; +import { TechVendorLocation } from "./TechVendorLocation"; +import { TravelAgencyLocation } from "./TravelAgencyLocation"; +import { UniversityLocation } from "./UniversityLocation"; -import { IPlayer } from "../../PersonObjects/IPlayer"; +import { Location } from "../Location"; +import { LocationType } from "../LocationTypeEnum"; +import { CityName } from "../data/CityNames"; -import { StdButton } from "../../ui/React/StdButton"; +import { IEngine } from "../../IEngine"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { StdButton } from "../../ui/React/StdButton"; type IProps = { - locName: LocationName; + engine: IEngine; + loc: Location; p: IPlayer; returnToCity: () => void; + travel: (to: CityName) => void; } export class GenericLocation extends React.Component { - /** - * 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 @@ -43,41 +40,79 @@ export class GenericLocation extends React.Component { getLocationSpecificContent(): React.ReactNode[] { const content: React.ReactNode[] = []; - if (this.loc.types.includes(LocationType.Company)) { - + if (this.props.loc.types.includes(LocationType.Company)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.Gym)) { - + if (this.props.loc.types.includes(LocationType.Gym)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.Hospital)) { - + if (this.props.loc.types.includes(LocationType.Hospital)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.Slums)) { - + if (this.props.loc.types.includes(LocationType.Slums)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.Special)) { - + if (this.props.loc.types.includes(LocationType.Special)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.StockMarket)) { - + if (this.props.loc.types.includes(LocationType.TechVendor)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.TechVendor)) { - + if (this.props.loc.types.includes(LocationType.TravelAgency)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.TravelAgency)) { - + if (this.props.loc.types.includes(LocationType.University)) { + content.push( + + ) } - if (this.loc.types.includes(LocationType.University)) { - - } + return content; } render() { @@ -87,7 +122,7 @@ export class GenericLocation extends React.Component {

    -

    this.loc.name

    +

    {this.props.loc.name}

    {locContent}
    ) diff --git a/src/Locations/ui/GymLocation.tsx b/src/Locations/ui/GymLocation.tsx new file mode 100644 index 000000000..7c54c9863 --- /dev/null +++ b/src/Locations/ui/GymLocation.tsx @@ -0,0 +1,78 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a gym + * + * This subcomponent renders all of the buttons for training at the gym + */ +import * as React from "react"; + +import { Location } from "../Location"; + +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { StdButton } from "../../ui/React/StdButton"; + +type IProps = { + loc: Location; + p: IPlayer; +} + +export class GymLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.trainStrength = this.trainStrength.bind(this); + this.trainDefense = this.trainDefense.bind(this); + this.trainDexterity = this.trainDexterity.bind(this); + this.trainAgility = this.trainAgility.bind(this); + } + + train(stat: string) { + const loc = this.props.loc; + this.props.p.startClass(loc.costMult, loc.expMult, stat); + } + + trainStrength() { + return this.train(CONSTANTS.ClassGymStrength); + } + + trainDefense() { + return this.train(CONSTANTS.ClassGymDefense); + } + + trainDexterity() { + return this.train(CONSTANTS.ClassGymDexterity); + } + + trainAgility() { + return this.train(CONSTANTS.ClassGymAgility); + } + + render() { + const costMult: number = this.props.loc.costMult; + + const cost = CONSTANTS.ClassGymBaseCost * costMult; + + return ( +
    + + + + +
    + ) + } +} diff --git a/src/Locations/ui/HospitalLocation.tsx b/src/Locations/ui/HospitalLocation.tsx new file mode 100644 index 000000000..cfd4c5e38 --- /dev/null +++ b/src/Locations/ui/HospitalLocation.tsx @@ -0,0 +1,55 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a hospital + * + * This subcomponent renders all of the buttons for hospital options + */ +import * as React from "react"; + +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton"; + +import { dialogBoxCreate } from "../../../utils/DialogBox"; + +type IProps = { + p: IPlayer; +} + +export class HospitalLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.getCost = this.getCost.bind(this); + this.getHealed = this.getHealed.bind(this); + } + + getCost(): number { + return (this.props.p.max_hp - this.props.p.hp) * CONSTANTS.HospitalCostPerHp; + } + + getHealed(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + + if (this.props.p.hp < 0) { this.props.p.hp = 0; } + if (this.props.p.hp >= this.props.p.max_hp) { return; } + + const cost = this.getCost(); + this.props.p.loseMoney(cost); + this.props.p.hp = this.props.p.max_hp; + + dialogBoxCreate(`You were healed to full health! The hospital billed you for ${numeralWrapper.formatMoney(cost)}`); + } + + render() { + const cost = this.getCost(); + + return ( + + ) + } +} diff --git a/src/Locations/ui/Root.tsx b/src/Locations/ui/Root.tsx index 01f61e349..fa73a7a6a 100644 --- a/src/Locations/ui/Root.tsx +++ b/src/Locations/ui/Root.tsx @@ -4,13 +4,23 @@ 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 = { + engine: IEngine; p: IPlayer; } @@ -30,16 +40,8 @@ export class LocationRoot extends React.Component { 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 - }); - } + this.travel = this.travel.bind(this); } enterLocation(to: LocationName): void { @@ -64,10 +66,15 @@ export class LocationRoot extends React.Component { * 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 (

    {this.state.city}

    - +
    ) } @@ -76,11 +83,61 @@ export class LocationRoot extends React.Component { * 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 ( - + ) } + /** + * 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(`You are now in ${to}!`); + + // 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({ + city: to + }); + } + } + render() { if (this.state.inCity) { return this.renderCity(); diff --git a/src/Locations/ui/SlumsLocation.tsx b/src/Locations/ui/SlumsLocation.tsx new file mode 100644 index 000000000..ea9a5cc8f --- /dev/null +++ b/src/Locations/ui/SlumsLocation.tsx @@ -0,0 +1,187 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a slum + * + * This subcomponent renders all of the buttons for committing crimes + */ +import * as React from "react"; + +import { Crimes } from "../../Crime/Crimes"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton"; + +type IProps = { + p: IPlayer; +} + +export class SlumsLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.shoplift = this.shoplift.bind(this); + this.robStore = this.robStore.bind(this); + this.mug = this.mug.bind(this); + this.larceny = this.larceny.bind(this); + this.dealDrugs = this.dealDrugs.bind(this); + this.bondForgery = this.bondForgery.bind(this); + this.traffickArms = this.traffickArms.bind(this); + this.homicide = this.homicide.bind(this); + this.grandTheftAuto = this.grandTheftAuto.bind(this); + this.kidnap = this.kidnap.bind(this); + this.assassinate = this.assassinate.bind(this); + this.heist = this.heist.bind(this); + } + + shoplift(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Shoplift.commit(this.props.p); + } + + robStore(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.RobSTore.commit(this.props.p); + } + + mug(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.mug.commit(this.props.p); + } + + larceny(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Larceny.commit(this.props.p); + } + + dealDrugs(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.DealDrugs.commit(this.props.p); + } + + bondForgery(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.BondForgery.commit(this.props.p); + } + + traffickArms(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.TraffickArms.commit(this.props.p); + } + + homicide(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Homicide.commit(this.props.p); + } + + grandTheftAuto(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.GrandTheftAuto.commit(this.props.p); + } + + kidnap(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Kidnap.commit(this.props.p); + } + + assassinate(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Assassination.commit(this.props.p); + } + + heist(e: React.MouseEvent): void { + if (!e.isTrusted) { return; } + Crimes.Heist.commit(this.props.p); + } + + render() { + const shopliftChance = Crimes.Shoplift.successRate(this.props.p); + const robStoreChance = Crimes.RobStore.successRate(this.props.p); + const mugChance = Crimes.Mug.successRate(this.props.p); + const larcenyChance = Crimes.Larceny.successRate(this.props.p); + const drugsChance = Crimes.DealDrugs.successRate(this.props.p); + const bondChance = Crimes.BondForgery.successRate(this.props.p); + const armsChance = Crimes.TraffickArms.successRate(this.props.p); + const homicideChance = Crimes.Homicide.successRate(this.props.p); + const gtaChance = Crimes.GrandTheftAuto.successRate(this.props.p); + const kidnapChance = Crimes.Kidnap.successRate(this.props.p); + const assassinateChance = Crimes.Assassination.successRate(this.props.p); + const heistChance = Crimes.Heist.successRate(this.props.p); + + return ( +
    + + + + + + + + + + + + +
    + ) + } +} diff --git a/src/Locations/ui/SpecialLocation.tsx b/src/Locations/ui/SpecialLocation.tsx new file mode 100644 index 000000000..afa1b3955 --- /dev/null +++ b/src/Locations/ui/SpecialLocation.tsx @@ -0,0 +1,136 @@ +/** + * React Subcomponent for displaying a location's UI, when that location has special + * actions/options/properties + * + * Examples: + * - Bladeburner @ NSA + * - Re-sleeving @ VitaLife + * - Create Corporation @ City Hall + * + * This subcomponent creates all of the buttons for interacting with those special + * properties + */ +import * as React from "react"; + +import { Location } from "../Location"; +import { createStartCorporationPopup } from "../LocationsHelpers"; +import { LocationName } from "../data/LocationNames"; + +import { IEngine } from "../../IEngine"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { AutoupdatingStdButton } from "../../ui/React/AutoupdatingStdButton"; +import { StdButton } from "../../ui/React/StdButton"; + +import { dialogBoxCreate } from "../../../utils/DialogBox"; + +type IProps = { + engine: IEngine; + loc: Location; + p: IPlayer; +} + +type IState = { + inBladeburner: boolean; +} + +export class SpecialLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.createCorporationPopup = this.createCorporationPopup.bind(this); + this.handleBladeburner = this.handleBladeburner.bind(this); + this.handleResleeving = this.handleResleeving.bind(this); + + this.state = { + inBladeburner: this.props.p.inBladeburner(), + } + } + + /** + * Click handler for "Create Corporation" button at Sector-12 City Hall + */ + createCorporationPopup() { + createStartCorporationPopup(this.props.p); + } + + /** + * Click handler for Bladeburner button at Sector-12 NSA + */ + handleBladeburner() { + const p = this.props.p; + if (p.inBladeburner()) { + // Enter Bladeburner division + this.props.engine.loadBladeburnerContent(); + } else { + // Apply for Bladeburner division + if (p.strength >= 100 && p.defense >= 100 && p.dexterity >= 100 && p.agility >= 100) { + p.startBladeburner({ new: true }); + dialogBoxCreate("You have been accepted into the Bladeburner division!"); + this.setState({ + inBladeburner: true, + }); + + const worldHeader = document.getElementById("world-menu-header"); + if (worldHeader instanceof HTMLElement) { + worldHeader.click(); worldHeader.click(); + } + } else { + dialogBoxCreate("Rejected! Please apply again when you have 100 of each combat stat (str, def, dex, agi)"); + } + } + } + + /** + * Click handler for Resleeving button at New Tokyo VitaLife + */ + handleResleeving() { + this.props.engine.loadResleevingContent(); + } + + renderBladeburner(): React.ReactNode { + const text = this.state.inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division"; + return ( + + ) + } + + renderCreateCorporation(): React.ReactNode { + return ( + + ) + } + + renderResleeving(): React.ReactNode { + return ( + + ) + } + + render() { + switch (this.props.loc.name) { + case LocationName.NewTokyoVitaLife: { + return this.renderResleeving(); + } + case LocationName.Sector12CityHall: { + return this.renderCreateCorporation(); + } + case LocationName.Sector12NSA: { + return this.renderBladeburner(); + } + default: + console.error(`Location ${this.props.loc.name} doesn't have any special properties`); + break; + } + } +} diff --git a/src/Locations/ui/TechVendorLocation.tsx b/src/Locations/ui/TechVendorLocation.tsx new file mode 100644 index 000000000..90aadfacd --- /dev/null +++ b/src/Locations/ui/TechVendorLocation.tsx @@ -0,0 +1,94 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a tech vendor + * + * This subcomponent renders all of the buttons for purchasing things from tech vendors + */ +import * as React from "react"; + +import { Location } from "../Location"; +import { createPurchaseServerPopup, + createUpgradeHomeCoresPopup, + createUpgradeHomeRamPopup, + purchaseTorRouter } from "../LocationsHelpers"; + +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; +import { getPurchaseServerCost } from "../../Server/ServerPurchases"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { StdButtonPurchased } from "../../ui/React/StdButtonPurchased"; +import { StdButton } from "../../ui/React/StdButton"; + +type IProps = { + loc: Location; + p: IPlayer; +} + +export class TechVendorLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.state = { + torPurchased: props.p.hasTorRouter(), + } + + this.createUpgradeHomeCoresPopup = this.createUpgradeHomeCoresPopup.bind(this); + this.createUpgradeHomeRamPopup = this.createUpgradeHomeRamPopup.bind(this); + this.purchaseTorRouter = this.purchaseTorRouter.bind(this); + } + + createUpgradeHomeCoresPopup() { + createUpgradeHomeCoresPopup(this.props.p); + } + + createUpgradeHomeRamPopup() { + createUpgradeHomeRamPopup(this.props.p); + } + + purchaseTorRouter() { + purchaseTorRouter(this.props.p); + } + + render() { + const loc: Location = this.props.loc; + + const purchaseServerButtons: React.ReactNode[] = []; + for (let i = loc.techVendorMinRam; i <= loc.techVendorMaxRam; i *= 2) { + const cost = getPurchaseServerCost(i); + purchaseServerButtons.push( + createPurchaseServerPopup(i, this.props.p)} + text={`Purchase ${i}GB Server - ${numeralWrapper.formatMoney(cost)}`} + /> + ) + } + + return ( +
    + {purchaseServerButtons} + { + this.state.torPurchased ? ( + + ) : ( + + ) + + } + + +
    + ) + } +} diff --git a/src/Locations/ui/TravelAgencyLocation.tsx b/src/Locations/ui/TravelAgencyLocation.tsx new file mode 100644 index 000000000..4b5364b87 --- /dev/null +++ b/src/Locations/ui/TravelAgencyLocation.tsx @@ -0,0 +1,54 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a Travel Agency + * + * This subcomponent renders all of the buttons for traveling to different cities + */ +import * as React from "react"; + +import { CityName } from "../data/CityNames"; +import { createTravelPopup } from "../LocationsHelpers"; + +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { StdButton } from "../../ui/React/StdButton"; + +type IProps = { + p: IPlayer; + travel: (to: CityName) => void; +} + +export class TravelAgencyLocation extends React.Component { + constructor(props: IProps) { + super(props); + } + + render() { + const travelBtns: React.ReactNode[] = []; + for (const key in CityName) { + const city = CityName[key]; + + // Skip current city + if (city === this.props.p.city) { continue; } + + travelBtns.push( + + ) + } + + return ( +
    +

    + From here, you can travel to any other city! A ticket costs + {numeralWrapper.formatMoney(CONSTANTS.TravelCost)} +

    + {travelBtns} +
    + ) + } +} diff --git a/src/Locations/ui/UniversityLocation.tsx b/src/Locations/ui/UniversityLocation.tsx new file mode 100644 index 000000000..934b66856 --- /dev/null +++ b/src/Locations/ui/UniversityLocation.tsx @@ -0,0 +1,100 @@ +/** + * React Subcomponent for displaying a location's UI, when that location is a university + * + * This subcomponent renders all of the buttons for studying/taking courses + */ +import * as React from "react"; + +import { Location } from "../Location"; + +import { CONSTANTS } from "../../Constants"; +import { IPlayer } from "../../PersonObjects/IPlayer"; + +import { numeralWrapper } from "../../ui/numeralFormat"; +import { StdButton } from "../../ui/React/StdButton"; + +type IProps = { + loc: Location; + p: IPlayer; +} + +export class UniversityLocation extends React.Component { + constructor(props: IProps) { + super(props); + + this.take = this.take.bind(this); + this.dataStructures = this.dataStructures.bind(this); + this.networks = this.networks.bind(this); + this.algorithms = this.algorithms.bind(this); + this.management = this.management.bind(this); + this.leadership = this.leadership.bind(this); + } + + take(stat: string) { + const loc = this.props.loc; + this.props.p.startClass(loc.costMult, loc.expMult, stat); + } + + study() { + return this.take(CONSTANTS.ClassStudyComputerScience); + } + + dataStructures() { + return this.take(CONSTANTS.ClassDataStructures); + } + + networks() { + return this.take(CONSTANTS.ClassNetworks); + } + + algorithms() { + return this.take(CONSTANTS.ClassAlgorithms); + } + + management() { + return this.take(CONSTANTS.ClassManagement); + } + + leadership() { + return this.take(CONSTANTS.ClassLeadership); + } + + render() { + const costMult: number = this.props.loc.costMult; + + const dataStructuresCost = CONSTANTS.ClassDataStructuresBaseCost * costMult; + const networksCost = CONSTANTS.ClassNetworksBaseCost * costMult; + const algorithmsCost = CONSTANTS.ClassAlgorithmsBaseCost * costMult; + const managementCost = CONSTANTS.ClassManagementBaseCost * costMult; + const leadershipCost = CONSTANTS.ClassLeadershipBaseCost * costMult; + + return ( +
    + + + + + + +
    + ) + } +} diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index fa9dbaef1..fc802e4b3 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -31,7 +31,8 @@ import { joinFaction, import { FactionWorkType } from "./Faction/FactionWorkTypeEnum"; import { getCostOfNextHacknetNode, purchaseHacknet } from "./Hacknet/HacknetNode"; -import {Locations} from "./Locations"; +import { CityName } from "./Locations/data/CityNames"; +import { LocationName } from "./Locations/data/LocationNames"; import { Message } from "./Message/Message"; import { Messages } from "./Message/MessageHelpers"; import {inMission} from "./Missions"; @@ -2584,30 +2585,30 @@ function NetscriptFunctions(workerScript) { var costMult, expMult; switch(universityName.toLowerCase()) { - case Locations.AevumSummitUniversity.toLowerCase(): - if (Player.city != Locations.Aevum) { + case LocationName.AevumSummitUniversity.toLowerCase(): + if (Player.city != CityName.Aevum) { workerScript.scriptRef.log("ERROR: You cannot study at Summit University because you are not in Aevum. universityCourse() failed"); return false; } - Player.location = Locations.AevumSummitUniversity; + Player.gotoLocation(LocationName.AevumSummitUniversity); costMult = 4; expMult = 3; break; - case Locations.Sector12RothmanUniversity.toLowerCase(): - if (Player.city != Locations.Sector12) { + case LocationName.Sector12RothmanUniversity.toLowerCase(): + if (Player.city != CityName.Sector12) { workerScript.scriptRef.log("ERROR: You cannot study at Rothman University because you are not in Sector-12. universityCourse() failed"); return false; } - Player.location = Locations.Sector12RothmanUniversity; + Player.location = LocationName.Sector12RothmanUniversity; costMult = 3; expMult = 2; break; - case Locations.VolhavenZBInstituteOfTechnology.toLowerCase(): - if (Player.city != Locations.Volhaven) { + case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): + if (Player.city != CityName.Volhaven) { workerScript.scriptRef.log("ERROR: You cannot study at ZB Institute of Technology because you are not in Volhaven. universityCourse() failed"); return false; } - Player.location = Locations.VolhavenZBInstituteOfTechnology; + Player.location = LocationName.VolhavenZBInstituteOfTechnology; costMult = 5; expMult = 4; break; @@ -2672,48 +2673,48 @@ function NetscriptFunctions(workerScript) { } var costMult, expMult; switch(gymName.toLowerCase()) { - case Locations.AevumCrushFitnessGym.toLowerCase(): - if (Player.city != Locations.Aevum) { + case LocationName.AevumCrushFitnessGym.toLowerCase(): + if (Player.city != CityName.Aevum) { workerScript.scriptRef.log("ERROR: You cannot workout at Crush Fitness because you are not in Aevum. gymWorkout() failed"); return false; } - Player.location = Locations.AevumCrushFitnessGym; + Player.location = LocationName.AevumCrushFitnessGym; costMult = 3; expMult = 2; break; - case Locations.AevumSnapFitnessGym.toLowerCase(): - if (Player.city != Locations.Aevum) { + case LocationName.AevumSnapFitnessGym.toLowerCase(): + if (Player.city != CityName.Aevum) { workerScript.scriptRef.log("ERROR: You cannot workout at Snap Fitness because you are not in Aevum. gymWorkout() failed"); return false; } - Player.location = Locations.AevumSnapFitnessGym; + Player.location = LocationName.AevumSnapFitnessGym; costMult = 10; expMult = 5; break; - case Locations.Sector12IronGym.toLowerCase(): - if (Player.city != Locations.Sector12) { + case LocationName.Sector12IronGym.toLowerCase(): + if (Player.city != CityName.Sector12) { workerScript.scriptRef.log("ERROR: You cannot workout at Iron Gym because you are not in Sector-12. gymWorkout() failed"); return false; } - Player.location = Locations.Sector12IronGym; + Player.location = LocationName.Sector12IronGym; costMult = 1; expMult = 1; break; - case Locations.Sector12PowerhouseGym.toLowerCase(): - if (Player.city != Locations.Sector12) { + case LocationName.Sector12PowerhouseGym.toLowerCase(): + if (Player.city != CityName.Sector12) { workerScript.scriptRef.log("ERROR: You cannot workout at Powerhouse Gym because you are not in Sector-12. gymWorkout() failed"); return false; } - Player.location = Locations.Sector12PowerhouseGym; + Player.location = LocationName.Sector12PowerhouseGym; costMult = 20; expMult = 10; break; - case Locations.VolhavenMilleniumFitnessGym.toLowerCase(): - if (Player.city != Locations.Volhaven) { + case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): + if (Player.city != CityName.Volhaven) { workerScript.scriptRef.log("ERROR: You cannot workout at Millenium Fitness Gym because you are not in Volhaven. gymWorkout() failed"); return false; } - Player.location = Locations.VolhavenMilleniumFitnessGym; + Player.location = LocationName.VolhavenMilleniumFitnessGym; costMult = 7; expMult = 4; break; @@ -2764,12 +2765,12 @@ function NetscriptFunctions(workerScript) { } switch(cityname) { - case Locations.Aevum: - case Locations.Chongqing: - case Locations.Sector12: - case Locations.NewTokyo: - case Locations.Ishima: - case Locations.Volhaven: + case CityName.Aevum: + case CityName.Chongqing: + case CityName.Sector12: + case CityName.NewTokyo: + case CityName.Ishima: + case CityName.Volhaven: if(Player.money.lt(CONSTANTS.TravelCost)) { workerScript.scriptRef.log("ERROR: not enough money to travel with travelToCity()."); throw makeRuntimeRejectMsg(workerScript, "ERROR: not enough money to travel with travelToCity()."); @@ -3587,29 +3588,8 @@ function NetscriptFunctions(workerScript) { } } - //Set Location to slums - switch(Player.city) { - case Locations.Aevum: - Player.location = Locations.AevumSlums; - break; - case Locations.Chongqing: - Player.location = Locations.ChongqingSlums; - break; - case Locations.Sector12: - Player.location = Locations.Sector12Slums; - break; - case Locations.NewTokyo: - Player.location = Locations.NewTokyoSlums; - break; - case Locations.Ishima: - Player.location = Locations.IshimaSlums; - break; - case Locations.Volhaven: - Player.location = Locations.VolhavenSlums; - break; - default: - console.log("Invalid Player.city value"); - } + // Set Location to slums + Player.gotoLocation(LocationName.Slums); const crime = findCrime(crimeRoughName.toLowerCase()); if(crime == null) { // couldn't find crime diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts index fe94353e0..ed89e6084 100644 --- a/src/PersonObjects/IPlayer.ts +++ b/src/PersonObjects/IPlayer.ts @@ -1,8 +1,8 @@ -// Interface for an object that represents the player (PlayerObject) -// Used because at the time of implementation, the PlayerObject -// cant be converted to TypeScript. -// -// Only contains the needed properties for Sleeve implementation +/** + * Interface for an object that represents the player (PlayerObject) + * Used because at the time of implementation, the PlayerObject + * cant be converted to TypeScript. + */ import { Resleeve } from "./Resleeving/Resleeve"; import { Sleeve } from "./Sleeve/Sleeve"; @@ -12,9 +12,10 @@ import { IPlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugment import { Company } from "../Company/Company"; import { CompanyPosition } from "../Company/CompanyPosition"; import { CityName } from "../Locations/data/CityNames"; +import { HashManager } from "../Hacknet/HashManager"; import { HacknetNode } from "../Hacknet/HacknetNode"; -import { HacknetServer } from "../Hacknet/HacknetServer"; import { LocationName } from "../Locations/data/LocationNames"; +import { Server } from "../Server/Server"; import { IPlayerOwnedSourceFile } from "../SourceFile/PlayerOwnedSourceFile"; import { MoneySourceTracker } from "../utils/MoneySourceTracker"; @@ -28,11 +29,15 @@ export interface IPlayer { corporation: any; currentServer: string; factions: string[]; + firstTimeTraveled: boolean; hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server + hashManager: HashManager; hasWseAccount: boolean; + hp: number; jobs: IMap; karma: number; location: LocationName; + max_hp: number; money: any; moneySourceA: MoneySourceTracker; moneySourceB: MoneySourceTracker; @@ -114,15 +119,22 @@ export interface IPlayer { gainAgilityExp(exp: number): void; gainCharismaExp(exp: number): void; gainMoney(money: number): void; + getHomeComputer(): Server; getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition; + getUpgradeHomeRamCost(): number; hasCorporation(): boolean; + hasTorRouter(): boolean; inBladeburner(): boolean; inGang(): boolean; isQualified(company: Company, position: CompanyPosition): boolean; loseMoney(money: number): void; reapplyAllAugmentations(resetMultipliers: boolean): void; reapplyAllSourceFiles(): void; + regenerateHp(amt: number): void; recordMoneySource(amt: number, source: string): void; + startBladeburner(p: object): void; + startClass(costMult: number, expMult: number, className: string): void; + startCorporation(corpName: string, additionalShares?: number): void; startCrime(crimeType: string, hackExp: number, strExp: number, diff --git a/src/PersonObjects/Player/PlayerGeneralMethods.js b/src/PersonObjects/Player/PlayerGeneralMethods.js deleted file mode 100644 index df585e69a..000000000 --- a/src/PersonObjects/Player/PlayerGeneralMethods.js +++ /dev/null @@ -1,12 +0,0 @@ -import { PlayerObject } from "../../Player"; -import { Cities } from "../../Locations/Cities"; - -PlayerObject.prototype.travel = function(to) { - if (Cities[to] == null) { - console.warn(`Player.travel() called with invalid city: ${to}`); - return false; - } - this.city = to; - - return true; -} diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 48c21e833..c60f5c39b 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -22,8 +22,6 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { Crime } from "../../Crime/Crime"; import { Crimes } from "../../Crime/Crimes"; -import { CityName } from "../../Locations/data/CityNames"; - import { Companies } from "../../Company/Companies"; import { Company } from "../../Company/Company"; import { CompanyPosition } from "../../Company/CompanyPosition"; @@ -35,7 +33,8 @@ import { Faction } from "../../Faction/Faction"; import { Factions } from "../../Faction/Factions"; import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum"; -import { Locations } from "../../Locations"; +import { CityName } from "../../Locations/data/CityNames"; +import { LocationName } from "../../Locations/data/LocationNames"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../../utils/JSONReviver"; @@ -586,21 +585,21 @@ export class Sleeve extends Person { let costMult: number = 1; let expMult: number = 1; switch (universityName.toLowerCase()) { - case Locations.AevumSummitUniversity.toLowerCase(): + case LocationName.AevumSummitUniversity.toLowerCase(): if (this.city !== CityName.Aevum) { return false; } - this.currentTaskLocation = Locations.AevumSummitUniversity; + this.currentTaskLocation = LocationName.AevumSummitUniversity; costMult = 4; expMult = 3; break; - case Locations.Sector12RothmanUniversity.toLowerCase(): + case LocationName.Sector12RothmanUniversity.toLowerCase(): if (this.city !== CityName.Sector12) { return false; } - this.currentTaskLocation = Locations.Sector12RothmanUniversity; + this.currentTaskLocation = LocationName.Sector12RothmanUniversity; costMult = 3; expMult = 2; break; - case Locations.VolhavenZBInstituteOfTechnology.toLowerCase(): + case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): if (this.city !== CityName.Volhaven) { return false; } - this.currentTaskLocation = Locations.VolhavenZBInstituteOfTechnology; + this.currentTaskLocation = LocationName.VolhavenZBInstituteOfTechnology; costMult = 5; expMult = 4; break; @@ -781,33 +780,33 @@ export class Sleeve extends Person { let costMult: number = 1; let expMult: number = 1; switch (gymName.toLowerCase()) { - case Locations.AevumCrushFitnessGym.toLowerCase(): + case LocationName.AevumCrushFitnessGym.toLowerCase(): if (this.city != CityName.Aevum) { return false; } - this.currentTaskLocation = Locations.AevumCrushFitnessGym; + this.currentTaskLocation = LocationName.AevumCrushFitnessGym; costMult = 3; expMult = 2; break; - case Locations.AevumSnapFitnessGym.toLowerCase(): + case LocationName.AevumSnapFitnessGym.toLowerCase(): if (this.city != CityName.Aevum) { return false; } - this.currentTaskLocation = Locations.AevumSnapFitnessGym; + this.currentTaskLocation = LocationName.AevumSnapFitnessGym; costMult = 10; expMult = 5; break; - case Locations.Sector12IronGym.toLowerCase(): + case LocationName.Sector12IronGym.toLowerCase(): if (this.city != CityName.Sector12) { return false; } - this.currentTaskLocation = Locations.Sector12IronGym; + this.currentTaskLocation = LocationName.Sector12IronGym; costMult = 1; expMult = 1; break; - case Locations.Sector12PowerhouseGym.toLowerCase(): + case LocationName.Sector12PowerhouseGym.toLowerCase(): if (this.city != CityName.Sector12) { return false; } - this.currentTaskLocation = Locations.Sector12PowerhouseGym; + this.currentTaskLocation = LocationName.Sector12PowerhouseGym; costMult = 20; expMult = 10; break; - case Locations.VolhavenMilleniumFitnessGym: + case LocationName.VolhavenMilleniumFitnessGym: if (this.city != CityName.Volhaven) { return false; } - this.currentTaskLocation = Locations.VolhavenMilleniumFitnessGym; + this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym; costMult = 7; expMult = 4; break; diff --git a/src/PersonObjects/Sleeve/SleeveUI.ts b/src/PersonObjects/Sleeve/SleeveUI.ts index 86fd9af0a..98c68dc85 100644 --- a/src/PersonObjects/Sleeve/SleeveUI.ts +++ b/src/PersonObjects/Sleeve/SleeveUI.ts @@ -9,15 +9,16 @@ import { SleeveFaq } from "./data/SleeveFaq"; import { IPlayer } from "../IPlayer"; import { CONSTANTS } from "../../Constants"; -import { Locations } from "../../Locations"; import { Faction } from "../../Faction/Faction"; import { Factions } from "../../Faction/Factions"; import { FactionWorkType } from "../../Faction/FactionWorkTypeEnum"; -import { Cities } from "../../Locations/Cities"; import { Crime } from "../../Crime/Crime"; import { Crimes } from "../../Crime/Crimes"; +import { Cities } from "../../Locations/Cities"; +import { CityName } from "../../Locations/data/CityNames"; +import { LocationName } from "../../Locations/data/LocationNames"; import { numeralWrapper } from "../../ui/numeralFormat"; import { Page, @@ -243,20 +244,20 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems { `Traveling to a different city costs ${numeralWrapper.formatMoney(CONSTANTS.TravelCost)}. ` + "It will also CANCEL the sleeve's current task (setting it to idle)", })); - for (const label in Cities) { - if (sleeve.city === Cities[label]) { continue; } - (function(sleeve, label) { + for (const cityName in Cities) { + if (sleeve.city === cityName) { continue; } + (function(sleeve, cityName) { popupArguments.push(createElement("div", { // Reusing this css class. It adds a border and makes it so that // the background color changes when you hover class: "cmpy-mgmt-find-employee-option", - innerText: Cities[label], + innerText: cityName, clickListener: () => { if (!playerRef!.canAfford(CONSTANTS.TravelCost)) { dialogBoxCreate("You cannot afford to have this sleeve travel to another city", false); return false; } - sleeve.city = Cities[label]; + sleeve.city = cityName; playerRef!.loseMoney(CONSTANTS.TravelCost); sleeve.resetTaskStatus(); removeElementById(popupId); @@ -265,7 +266,7 @@ function createSleeveUi(sleeve: Sleeve, allSleeves: Sleeve[]): ISleeveUIElems { return false; } })); - })(sleeve, label); + })(sleeve, cityName); } createPopup(popupId, popupArguments); @@ -569,14 +570,14 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee // Second selector has which university switch (sleeve.city) { - case Cities.Aevum: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSummitUniversity)); + case CityName.Aevum: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumSummitUniversity)); break; - case Cities.Sector12: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12RothmanUniversity)); + case CityName.Sector12: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12RothmanUniversity)); break; - case Cities.Volhaven: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenZBInstituteOfTechnology)); + case CityName.Volhaven: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.VolhavenZBInstituteOfTechnology)); break; default: elems.taskDetailsSelector2!.add(createOptionElement("No university available in city!")); @@ -597,30 +598,30 @@ function updateSleeveTaskSelector(sleeve: Sleeve, elems: ISleeveUIElems, allSlee // Second selector has gym // In this switch statement we also set the initial value of the second selector switch (sleeve.city) { - case Cities.Aevum: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumCrushFitnessGym)); - elems.taskDetailsSelector2!.add(createOptionElement(Locations.AevumSnapFitnessGym)); + case CityName.Aevum: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumCrushFitnessGym)); + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.AevumSnapFitnessGym)); // Set initial value - if (sleeve.currentTaskLocation === Locations.AevumCrushFitnessGym) { + if (sleeve.currentTaskLocation === LocationName.AevumCrushFitnessGym) { elems.taskDetailsSelector2!.selectedIndex = 0; - } else if (sleeve.currentTaskLocation === Locations.AevumSnapFitnessGym) { + } else if (sleeve.currentTaskLocation === LocationName.AevumSnapFitnessGym) { elems.taskDetailsSelector2!.selectedIndex = 1; } break; - case Cities.Sector12: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12IronGym)); - elems.taskDetailsSelector2!.add(createOptionElement(Locations.Sector12PowerhouseGym)); + case CityName.Sector12: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12IronGym)); + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.Sector12PowerhouseGym)); // Set initial value - if (sleeve.currentTaskLocation === Locations.Sector12IronGym) { + if (sleeve.currentTaskLocation === LocationName.Sector12IronGym) { elems.taskDetailsSelector2!.selectedIndex = 0; - } else if (sleeve.currentTaskLocation === Locations.Sector12PowerhouseGym) { + } else if (sleeve.currentTaskLocation === LocationName.Sector12PowerhouseGym) { elems.taskDetailsSelector2!.selectedIndex = 1; } break; - case Cities.Volhaven: - elems.taskDetailsSelector2!.add(createOptionElement(Locations.VolhavenMilleniumFitnessGym)); + case CityName.Volhaven: + elems.taskDetailsSelector2!.add(createOptionElement(LocationName.VolhavenMilleniumFitnessGym)); break; default: elems.taskDetailsSelector2!.add(createOptionElement("No gym available in city!")); diff --git a/src/Player.js b/src/Player.js index a42e021fc..65ab700ee 100644 --- a/src/Player.js +++ b/src/Player.js @@ -10,7 +10,7 @@ import { Companies } from "./Company/Companies"; import { getNextCompanyPosition } from "./Company/GetNextCompanyPosition"; import { getJobRequirementText } from "./Company/GetJobRequirementText"; import { CompanyPositions } from "./Company/CompanyPositions"; -import * as posNames from "./Company/data/CompanyPositionNames"; +import * as posNames from "./Company/data/companypositionnames"; import {CONSTANTS} from "./Constants"; import { Corporation } from "./Corporation/Corporation"; import { Programs } from "./Programs/Programs"; @@ -23,7 +23,10 @@ import { displayFactionContent } from "./Faction/FactionHelpers"; import {Gang, resetGangs} from "./Gang"; import { hasHacknetServers } from "./Hacknet/HacknetHelpers"; import { HashManager } from "./Hacknet/HashManager"; -import {Locations} from "./Locations"; +import { Cities } from "./Locations/Cities"; +import { Locations } from "./Locations/Locations"; +import { CityName } from "./Locations/data/CityNames"; +import { LocationName } from "./Locations/data/LocationNames"; import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions"; import { Sleeve } from "./PersonObjects/Sleeve/Sleeve"; import { AllServers, @@ -33,12 +36,14 @@ import {Settings} from "./Settings/Settings"; import {SpecialServerIps, SpecialServerNames} from "./Server/SpecialServerIps"; import {SourceFiles, applySourceFile} from "./SourceFile"; import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; + import Decimal from "decimal.js"; + import {numeralWrapper} from "./ui/numeralFormat"; import { MoneySourceTracker } from "./utils/MoneySourceTracker"; -import {dialogBoxCreate} from "../utils/DialogBox"; -import {clearEventListeners} from "../utils/uiHelpers/clearEventListeners"; -import {createRandomIp} from "../utils/IPAddress"; +import {dialogBoxCreate} from "./../utils/DialogBox"; +import {clearEventListeners} from "./../utils/uiHelpers/clearEventListeners"; +import {createRandomIp} from "./../utils/IPAddress"; import {Reviver, Generic_toJSON, Generic_fromJSON} from "../utils/JSONReviver"; import {convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions"; @@ -102,7 +107,7 @@ function PlayerObject() { this.homeComputer = ""; //Location information - this.city = Locations.Sector12; + this.city = CityName.Sector12; this.location = ""; // Jobs that the player holds @@ -271,7 +276,7 @@ PlayerObject.prototype.prestigeAugmentation = function() { this.money = new Decimal(1000); - this.city = Locations.Sector12; + this.city = CityName.Sector12; this.location = ""; this.companyName = ""; @@ -364,7 +369,7 @@ PlayerObject.prototype.prestigeSourceFile = function() { this.money = new Decimal(1000); - this.city = Locations.Sector12; + this.city = CityName.Sector12; this.location = ""; this.companyName = ""; @@ -445,26 +450,6 @@ PlayerObject.prototype.prestigeSourceFile = function() { this.hp = this.max_hp; } -PlayerObject.prototype.getCurrentServer = function() { - return AllServers[this.currentServer]; -} - -PlayerObject.prototype.getHomeComputer = function() { - return AllServers[this.homeComputer]; -} - -PlayerObject.prototype.getUpgradeHomeRamCost = function() { - //Calculate how many times ram has been upgraded (doubled) - const currentRam = this.getHomeComputer().maxRam; - const numUpgrades = Math.log2(currentRam); - - //Calculate cost - //Have cost increase by some percentage each time RAM has been upgraded - const mult = Math.pow(1.58, numUpgrades); - var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost; - return cost; -} - PlayerObject.prototype.receiveInvite = function(factionName) { if(this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) { return; @@ -494,7 +479,7 @@ PlayerObject.prototype.updateSkillLevels = function() { var ratio = this.hp / this.max_hp; this.max_hp = Math.floor(10 + this.defense / 10); - Player.hp = Math.round(this.max_hp * ratio); + this.hp = Math.round(this.max_hp * ratio); } PlayerObject.prototype.resetMultipliers = function() { @@ -538,8 +523,8 @@ PlayerObject.prototype.resetMultipliers = function() { } PlayerObject.prototype.hasProgram = function(programName) { - var home = Player.getHomeComputer(); - if (home == null) {return false;} + const home = this.getHomeComputer(); + if (home == null) { return false; } for (var i = 0; i < home.programs.length; ++i) { if (programName.toLowerCase() == home.programs[i].toLowerCase()) {return true;} @@ -661,13 +646,13 @@ PlayerObject.prototype.gainIntelligenceExp = function(exp) { //Given a string expression like "str" or "strength", returns the given stat PlayerObject.prototype.queryStatFromString = function(str) { const tempStr = str.toLowerCase(); - if (tempStr.includes("hack")) {return Player.hacking_skill;} - if (tempStr.includes("str")) {return Player.strength;} - if (tempStr.includes("def")) {return Player.defense;} - if (tempStr.includes("dex")) {return Player.dexterity;} - if (tempStr.includes("agi")) {return Player.agility;} - if (tempStr.includes("cha")) {return Player.charisma;} - if (tempStr.includes("int")) {return Player.intelligence;} + if (tempStr.includes("hack")) { return this.hacking_skill; } + if (tempStr.includes("str")) { return this.strength; } + if (tempStr.includes("def")) { return this.defense; } + if (tempStr.includes("dex")) { return this.dexterity; } + if (tempStr.includes("agi")) { return this.agility; } + if (tempStr.includes("cha")) { return this.charisma; } + if (tempStr.includes("int")) { return this.intelligence; } } /******* Working functions *******/ @@ -752,7 +737,7 @@ PlayerObject.prototype.startWork = function(companyName) { var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); newCancelButton.innerHTML = "Cancel Work"; newCancelButton.addEventListener("click", function() { - Player.finishWork(true); + this.finishWork(true); return false; }); @@ -875,7 +860,7 @@ PlayerObject.prototype.startWorkPartTime = function(companyName) { var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); newCancelButton.innerHTML = "Stop Working"; newCancelButton.addEventListener("click", function() { - Player.finishWorkPartTime(); + this.finishWorkPartTime(); return false; }); @@ -985,7 +970,7 @@ PlayerObject.prototype.startFactionWork = function(faction) { var cancelButton = clearEventListeners("work-in-progress-cancel-button"); cancelButton.innerHTML = "Stop Faction Work"; cancelButton.addEventListener("click", function() { - Player.finishFactionWork(true); + this.finishFactionWork(true); return false; }); @@ -1322,7 +1307,7 @@ PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqL var cancelButton = clearEventListeners("work-in-progress-cancel-button"); cancelButton.innerHTML = "Cancel work on creating program"; cancelButton.addEventListener("click", function() { - Player.finishCreateProgramWork(true); + this.finishCreateProgramWork(true); return false; }); @@ -1464,7 +1449,7 @@ PlayerObject.prototype.startClass = function(costMult, expMult, className) { cancelButton.innerHTML = "Stop taking course"; } cancelButton.addEventListener("click", function() { - Player.finishClass(); + this.finishClass(); return false; }); @@ -1562,7 +1547,7 @@ PlayerObject.prototype.startCrime = function(crimeType, hackExp, strExp, defExp, var newCancelButton = clearEventListeners("work-in-progress-cancel-button") newCancelButton.innerHTML = "Cancel crime" newCancelButton.addEventListener("click", function() { - Player.finishCrime(true); + this.finishCrime(true); return false; }); @@ -1604,8 +1589,8 @@ PlayerObject.prototype.finishCrime = function(cancelled) { console.log(this.crimeType); dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer"); } - Player.gainMoney(this.workMoneyGained); - Player.recordMoneySource(this.workMoneyGained, "crime"); + this.gainMoney(this.workMoneyGained); + this.recordMoneySource(this.workMoneyGained, "crime"); this.karma -= crime.karma; this.numPeopleKilled += crime.kills; if(crime.intelligence_exp > 0) { @@ -1720,7 +1705,7 @@ PlayerObject.prototype.singularityStopWork = function() { } -//Returns true if hospitalized, false otherwise +// Returns true if hospitalized, false otherwise PlayerObject.prototype.takeDamage = function(amt) { if (typeof amt !== "number") { console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`); @@ -2126,14 +2111,14 @@ PlayerObject.prototype.checkForFactionInvitations = function() { //ECorp var ecorpFac = Factions["ECorp"]; if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && - checkMegacorpRequirements(Locations.AevumECorp)) { + checkMegacorpRequirements(LocationName.AevumECorp)) { invitedFactions.push(ecorpFac); } //MegaCorp var megacorpFac = Factions["MegaCorp"]; if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && - checkMegacorpRequirements(Locations.Sector12MegaCorp)) { + checkMegacorpRequirements(LocationName.Sector12MegaCorp)) { invitedFactions.push(megacorpFac); } @@ -2141,42 +2126,42 @@ PlayerObject.prototype.checkForFactionInvitations = function() { var bachmanandassociatesFac = Factions["Bachman & Associates"]; if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && !bachmanandassociatesFac.alreadyInvited && - checkMegacorpRequirements(Locations.AevumBachmanAndAssociates)) { + checkMegacorpRequirements(LocationName.AevumBachmanAndAssociates)) { invitedFactions.push(bachmanandassociatesFac); } //Blade Industries var bladeindustriesFac = Factions["Blade Industries"]; if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && - checkMegacorpRequirements(Locations.Sector12BladeIndustries)) { + checkMegacorpRequirements(LocationName.Sector12BladeIndustries)) { invitedFactions.push(bladeindustriesFac); } //NWO var nwoFac = Factions["NWO"]; if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && - checkMegacorpRequirements(Locations.VolhavenNWO)) { + checkMegacorpRequirements(LocationName.VolhavenNWO)) { invitedFactions.push(nwoFac); } //Clarke Incorporated var clarkeincorporatedFac = Factions["Clarke Incorporated"]; if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && - checkMegacorpRequirements(Locations.AevumClarkeIncorporated)) { + checkMegacorpRequirements(LocationName.AevumClarkeIncorporated)) { invitedFactions.push(clarkeincorporatedFac); } //OmniTek Incorporated var omnitekincorporatedFac = Factions["OmniTek Incorporated"]; if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && - checkMegacorpRequirements(Locations.VolhavenOmniTekIncorporated)) { + checkMegacorpRequirements(LocationName.VolhavenOmniTekIncorporated)) { invitedFactions.push(omnitekincorporatedFac); } //Four Sigma var foursigmaFac = Factions["Four Sigma"]; if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && - checkMegacorpRequirements(Locations.Sector12FourSigma)) { + checkMegacorpRequirements(LocationName.Sector12FourSigma)) { invitedFactions.push(foursigmaFac); } @@ -2184,7 +2169,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() { var kuaigonginternationalFac = Factions["KuaiGong International"]; if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && !kuaigonginternationalFac.alreadyInvited && - checkMegacorpRequirements(Locations.ChongqingKuaiGongInternational)) { + checkMegacorpRequirements(LocationName.ChongqingKuaiGongInternational)) { invitedFactions.push(kuaigonginternationalFac); } @@ -2197,7 +2182,7 @@ PlayerObject.prototype.checkForFactionInvitations = function() { if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && !fulcrumsecrettechonologiesFac.alreadyInvited && fulcrumSecretServer.manuallyHacked && - checkMegacorpRequirements(Locations.AevumFulcrumTechnologies, 250e3)) { + checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)) { invitedFactions.push(fulcrumsecrettechonologiesFac); } } @@ -2236,42 +2221,42 @@ PlayerObject.prototype.checkForFactionInvitations = function() { //Chongqing var chongqingFac = Factions["Chongqing"]; if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && - this.money.gte(20000000) && this.city == Locations.Chongqing) { + this.money.gte(20000000) && this.city == CityName.Chongqing) { invitedFactions.push(chongqingFac); } //Sector-12 var sector12Fac = Factions["Sector-12"]; if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && - this.money.gte(15000000) && this.city == Locations.Sector12) { + this.money.gte(15000000) && this.city == CityName.Sector12) { invitedFactions.push(sector12Fac); } //New Tokyo var newtokyoFac = Factions["New Tokyo"]; if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && - this.money.gte(20000000) && this.city == Locations.NewTokyo) { + this.money.gte(20000000) && this.city == CityName.NewTokyo) { invitedFactions.push(newtokyoFac); } //Aevum var aevumFac = Factions["Aevum"]; if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && - this.money.gte(40000000) && this.city == Locations.Aevum) { + this.money.gte(40000000) && this.city == CityName.Aevum) { invitedFactions.push(aevumFac); } //Ishima var ishimaFac = Factions["Ishima"]; if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && - this.money.gte(30000000) && this.city == Locations.Ishima) { + this.money.gte(30000000) && this.city == CityName.Ishima) { invitedFactions.push(ishimaFac); } //Volhaven var volhavenFac = Factions["Volhaven"]; if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && - this.money.gte(50000000) && this.city == Locations.Volhaven) { + this.money.gte(50000000) && this.city == CityName.Volhaven) { invitedFactions.push(volhavenFac); } @@ -2280,8 +2265,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() { if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && - this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) && - !allCompanies.includes(Locations.Sector12NSA)) { + this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && + !allCompanies.includes(LocationName.Sector12NSA)) { invitedFactions.push(speakersforthedeadFac); } @@ -2289,9 +2274,9 @@ PlayerObject.prototype.checkForFactionInvitations = function() { var thedarkarmyFac = Factions["The Dark Army"]; if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && - this.dexterity >= 300 && this.agility >= 300 && this.city == Locations.Chongqing && - this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(Locations.Sector12CIA) && - !allCompanies.includes(Locations.Sector12NSA)) { + this.dexterity >= 300 && this.agility >= 300 && this.city == CityName.Chongqing && + this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && + !allCompanies.includes(LocationName.Sector12NSA)) { invitedFactions.push(thedarkarmyFac); } @@ -2300,9 +2285,9 @@ PlayerObject.prototype.checkForFactionInvitations = function() { if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && this.dexterity >= 200 && this.agility >= 200 && - (this.city == Locations.Aevum || this.city == Locations.Sector12) && + (this.city == CityName.Aevum || this.city == CityName.Sector12) && this.money.gte(10000000) && this.karma <= -90 && - !allCompanies.includes(Locations.Sector12CIA) && !allCompanies.includes(Locations.Sector12NSA)) { + !allCompanies.includes(LocationName.Sector12CIA) && !allCompanies.includes(LocationName.Sector12NSA)) { invitedFactions.push(thesyndicateFac); } @@ -2319,8 +2304,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() { //Tetrads var tetradsFac = Factions["Tetrads"]; if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && - (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || - this.city == Locations.Ishima) && this.strength >= 75 && this.defense >= 75 && + (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || + this.city == CityName.Ishima) && this.strength >= 75 && this.defense >= 75 && this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { invitedFactions.push(tetradsFac); } @@ -2362,8 +2347,8 @@ PlayerObject.prototype.checkForFactionInvitations = function() { var tiandihuiFac = Factions["Tian Di Hui"]; if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && this.money.gte(1000000) && this.hacking_skill >= 50 && - (this.city == Locations.Chongqing || this.city == Locations.NewTokyo || - this.city == Locations.Ishima)) { + (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || + this.city == CityName.Ishima)) { invitedFactions.push(tiandihuiFac); } @@ -2392,18 +2377,6 @@ PlayerObject.prototype.startGang = function(factionName, hacking) { this.gang = new Gang(factionName, hacking); } -/*************** Corporation ****************/ -PlayerObject.prototype.hasCorporation = function() { - if (this.corporation == null) { return false; } - return (this.corporation instanceof Corporation); -} - -/*************** Bladeburner ****************/ -PlayerObject.prototype.inBladeburner = function() { - if (this.bladeburner == null) { return false; } - return (this.bladeburner instanceof Bladeburner); -} - /************* BitNodes **************/ PlayerObject.prototype.setBitNodeNumber = function(n) { this.bitNodeN = n; @@ -2489,8 +2462,85 @@ PlayerObject.prototype.gainCodingContractReward = function(reward, difficulty=1) /* eslint-enable no-case-declarations */ } -/* Functions for saving and loading the Player data */ -function loadPlayer(saveString) { +PlayerObject.prototype.travel = function(to) { + if (Cities[to] == null) { + console.warn(`Player.travel() called with invalid city: ${to}`); + return false; + } + this.city = to; + + return true; +} + +PlayerObject.prototype.gotoLocation = function(to) { + if (Locations[to] == null) { + console.warn(`Player.gotoLocation() called with invalid location: ${to}`); + return false; + } + this.location = to; + + return true; +} + +PlayerObject.prototype.hasTorRouter = function() { + return SpecialServerIps.hasOwnProperty("Darkweb Server"); +} + +PlayerObject.prototype.getCurrentServer = function() { + return AllServers[this.currentServer]; +} + +PlayerObject.prototype.getHomeComputer = function() { + return AllServers[this.homeComputer]; +} + +PlayerObject.prototype.getUpgradeHomeRamCost = function() { + //Calculate how many times ram has been upgraded (doubled) + const currentRam = this.getHomeComputer().maxRam; + const numUpgrades = Math.log2(currentRam); + + //Calculate cost + //Have cost increase by some percentage each time RAM has been upgraded + const mult = Math.pow(1.58, numUpgrades); + var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost; + return cost; +} + +PlayerObject.prototype.inBladeburner = function() { + if (this.bladeburner == null) { return false; } + return (this.bladeburner instanceof Bladeburner); +} + +PlayerObject.prototype.startBladeburner = function() { + this.bladeburner = new Bladeburner({ new: true }); +} + +PlayerObject.prototype.hasCorporation = function() { + if (this.corporation == null) { return false; } + return (this.corporation instanceof Corporation); +} + +PlayerObject.prototype.startCorporation = function(corpName, additionalShares=0) { + this.corporation = new Corporation({ + name: corpName + }); + + this.corporation.totalShares += additionalShares; +} + +PlayerObject.prototype.toJSON = function() { + return Generic_toJSON("PlayerObject", this); +} + +PlayerObject.fromJSON = function(value) { + return Generic_fromJSON(PlayerObject, value.data); +} + +Reviver.constructors.PlayerObject = PlayerObject; + +export let Player = new PlayerObject(); + +export function loadPlayer(saveString) { Player = JSON.parse(saveString, Reviver); //Parse Decimal.js objects @@ -2510,16 +2560,3 @@ function loadPlayer(saveString) { } } } - -PlayerObject.prototype.toJSON = function() { - return Generic_toJSON("PlayerObject", this); -} - -PlayerObject.fromJSON = function(value) { - return Generic_fromJSON(PlayerObject, value.data); -} - -Reviver.constructors.PlayerObject = PlayerObject; - -let Player = new PlayerObject(); -export {Player, loadPlayer}; diff --git a/src/Prestige.js b/src/Prestige.js index c764c5a37..792be3ccb 100755 --- a/src/Prestige.js +++ b/src/Prestige.js @@ -15,7 +15,6 @@ import { Factions, initFactions } from "./Faction/Factions"; import { joinFaction } from "./Faction/FactionHelpers"; import {deleteGangDisplayContent} from "./Gang"; -import {Locations} from "./Location"; import { Message } from "./Message/Message"; import { initMessages, Messages } from "./Message/MessageHelpers"; diff --git a/src/Server/BaseServer.ts b/src/Server/BaseServer.ts index b09ff9534..a505c73d9 100644 --- a/src/Server/BaseServer.ts +++ b/src/Server/BaseServer.ts @@ -20,7 +20,7 @@ interface IConstructorParams { organizationName?: string; } -export abstract class BaseServer { +export class BaseServer { // Coding Contract files on this server contracts: CodingContract[] = []; diff --git a/src/Server/ServerPurchases.js b/src/Server/ServerPurchases.ts similarity index 80% rename from src/Server/ServerPurchases.js rename to src/Server/ServerPurchases.ts index 7805206f3..401f8efc5 100644 --- a/src/Server/ServerPurchases.js +++ b/src/Server/ServerPurchases.ts @@ -4,9 +4,8 @@ */ import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { CONSTANTS } from "../Constants"; -import { Player } from "../Player"; -import { AllServers, - AddToAllServers } from "../Server/AllServers"; +import { IPlayer } from "../PersonObjects/IPlayer"; +import { AddToAllServers } from "../Server/AllServers"; import { Server } from "../Server/Server"; import { dialogBoxCreate } from "../../utils/DialogBox"; import { createRandomIp } from "../../utils/IPAddress"; @@ -15,7 +14,11 @@ import { isPowerOfTwo } from "../../utils/helpers/isPowerOfT // Returns the cost of purchasing a server with the given RAM // Returns Infinity for invalid 'ram' arguments -export function getPurchaseServerCost(ram) { +/** + * @param ram Amount of RAM on purchased server (GB) + * @returns Cost of purchasing the given server. Returns infinity for invalid arguments + */ +export function getPurchaseServerCost(ram: number) { const sanitizedRam = Math.round(ram); if (isNaN(sanitizedRam) || !isPowerOfTwo(sanitizedRam)) { return Infinity; @@ -40,17 +43,17 @@ export function getPurchaseServerMaxRam() { } // Manually purchase a server (NOT through Netscript) -export function purchaseServer(ram) { +export function purchaseServer(ram: number, p: IPlayer) { const cost = getPurchaseServerCost(ram); //Check if player has enough money - if (Player.money.lt(cost)) { - dialogBoxCreate("You don't have enough money to purchase this server!"); + if (!p.canAfford(cost)) { + dialogBoxCreate("You don't have enough money to purchase this server!", false); return; } //Maximum server limit - if (Player.purchasedServers.length >= getPurchaseServerLimit()) { + if (p.purchasedServers.length >= getPurchaseServerLimit()) { dialogBoxCreate("You have reached the maximum limit of " + getPurchaseServerLimit() + " servers. " + "You cannot purchase any more. You can " + "delete some of your purchased servers using the deleteServer() Netscript function in a script"); @@ -71,26 +74,26 @@ export function purchaseServer(ram) { AddToAllServers(newServ); //Add to Player's purchasedServers array - Player.purchasedServers.push(newServ.ip); + p.purchasedServers.push(newServ.ip); //Connect new server to home computer - var homeComputer = Player.getHomeComputer(); + var homeComputer = p.getHomeComputer(); homeComputer.serversOnNetwork.push(newServ.ip); newServ.serversOnNetwork.push(homeComputer.ip); - Player.loseMoney(cost); + p.loseMoney(cost); dialogBoxCreate("Server successfully purchased with hostname " + hostname); } // Manually upgrade RAM on home computer (NOT through Netscript) -export function purchaseRamForHomeComputer(cost) { - if (Player.money.lt(cost)) { +export function purchaseRamForHomeComputer(cost: number, p: IPlayer) { + if (!p.canAfford(cost)) { dialogBoxCreate("You do not have enough money to purchase additional RAM for your home computer"); return; } - const homeComputer = Player.getHomeComputer(); + const homeComputer = p.getHomeComputer(); if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) { dialogBoxCreate(`You cannot upgrade your home computer RAM because it is at its maximum possible value`); return; @@ -98,7 +101,7 @@ export function purchaseRamForHomeComputer(cost) { homeComputer.maxRam *= 2; - Player.loseMoney(cost); + p.loseMoney(cost); dialogBoxCreate("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM."); } diff --git a/src/StockMarket/StockMarket.js b/src/StockMarket/StockMarket.js index ee3a5edfe..5b84da52d 100644 --- a/src/StockMarket/StockMarket.js +++ b/src/StockMarket/StockMarket.js @@ -3,7 +3,7 @@ import { getStockMarket4SDataCost, getStockMarket4STixApiCost } from "./StockMarketCosts"; import {CONSTANTS} from "../Constants"; -import {Locations} from "../Locations"; +import { LocationName } from "../Locations/data/LocationNames"; import {hasWallStreetSF, wallStreetSFLvl} from "../NetscriptFunctions"; import {WorkerScript} from "../NetscriptWorker"; import {Player} from "../Player"; @@ -190,34 +190,34 @@ function loadStockMarket(saveString) { function initStockSymbols() { //Stocks for companies at which you can work - StockSymbols[Locations.AevumECorp] = "ECP"; - StockSymbols[Locations.Sector12MegaCorp] = "MGCP"; - StockSymbols[Locations.Sector12BladeIndustries] = "BLD"; - StockSymbols[Locations.AevumClarkeIncorporated] = "CLRK"; - StockSymbols[Locations.VolhavenOmniTekIncorporated] = "OMTK"; - StockSymbols[Locations.Sector12FourSigma] = "FSIG"; - StockSymbols[Locations.ChongqingKuaiGongInternational] = "KGI"; - StockSymbols[Locations.AevumFulcrumTechnologies] = "FLCM"; - StockSymbols[Locations.IshimaStormTechnologies] = "STM"; - StockSymbols[Locations.NewTokyoDefComm] = "DCOMM"; - StockSymbols[Locations.VolhavenHeliosLabs] = "HLS"; - StockSymbols[Locations.NewTokyoVitaLife] = "VITA"; - StockSymbols[Locations.Sector12IcarusMicrosystems] = "ICRS"; - StockSymbols[Locations.Sector12UniversalEnergy] = "UNV"; - StockSymbols[Locations.AevumAeroCorp] = "AERO"; - StockSymbols[Locations.VolhavenOmniaCybersystems] = "OMN"; - StockSymbols[Locations.ChongqingSolarisSpaceSystems] = "SLRS"; - StockSymbols[Locations.NewTokyoGlobalPharmaceuticals] = "GPH"; - StockSymbols[Locations.IshimaNovaMedical] = "NVMD"; - StockSymbols[Locations.AevumWatchdogSecurity] = "WDS"; - StockSymbols[Locations.VolhavenLexoCorp] = "LXO"; - StockSymbols[Locations.AevumRhoConstruction] = "RHOC"; - StockSymbols[Locations.Sector12AlphaEnterprises] = "APHE"; - StockSymbols[Locations.VolhavenSysCoreSecurities] = "SYSC"; - StockSymbols[Locations.VolhavenCompuTek] = "CTK"; - StockSymbols[Locations.AevumNetLinkTechnologies] = "NTLK"; - StockSymbols[Locations.IshimaOmegaSoftware] = "OMGA"; - StockSymbols[Locations.Sector12FoodNStuff] = "FNS"; + StockSymbols[LocationName.AevumECorp] = "ECP"; + StockSymbols[LocationName.Sector12MegaCorp] = "MGCP"; + StockSymbols[LocationName.Sector12BladeIndustries] = "BLD"; + StockSymbols[LocationName.AevumClarkeIncorporated] = "CLRK"; + StockSymbols[LocationName.VolhavenOmniTekIncorporated] = "OMTK"; + StockSymbols[LocationName.Sector12FourSigma] = "FSIG"; + StockSymbols[LocationName.ChongqingKuaiGongInternational] = "KGI"; + StockSymbols[LocationName.AevumFulcrumTechnologies] = "FLCM"; + StockSymbols[LocationName.IshimaStormTechnologies] = "STM"; + StockSymbols[LocationName.NewTokyoDefComm] = "DCOMM"; + StockSymbols[LocationName.VolhavenHeliosLabs] = "HLS"; + StockSymbols[LocationName.NewTokyoVitaLife] = "VITA"; + StockSymbols[LocationName.Sector12IcarusMicrosystems] = "ICRS"; + StockSymbols[LocationName.Sector12UniversalEnergy] = "UNV"; + StockSymbols[LocationName.AevumAeroCorp] = "AERO"; + StockSymbols[LocationName.VolhavenOmniaCybersystems] = "OMN"; + StockSymbols[LocationName.ChongqingSolarisSpaceSystems] = "SLRS"; + StockSymbols[LocationName.NewTokyoGlobalPharmaceuticals] = "GPH"; + StockSymbols[LocationName.IshimaNovaMedical] = "NVMD"; + StockSymbols[LocationName.AevumWatchdogSecurity] = "WDS"; + StockSymbols[LocationName.VolhavenLexoCorp] = "LXO"; + StockSymbols[LocationName.AevumRhoConstruction] = "RHOC"; + StockSymbols[LocationName.Sector12AlphaEnterprises] = "APHE"; + StockSymbols[LocationName.VolhavenSysCoreSecurities] = "SYSC"; + StockSymbols[LocationName.VolhavenCompuTek] = "CTK"; + StockSymbols[LocationName.AevumNetLinkTechnologies] = "NTLK"; + StockSymbols[LocationName.IshimaOmegaSoftware] = "OMGA"; + StockSymbols[LocationName.Sector12FoodNStuff] = "FNS"; //Stocks for other companies StockSymbols["Sigma Cosmetics"] = "SGC"; @@ -241,115 +241,115 @@ function initStockMarket() { const randInt = getRandomInt; - var ecorp = Locations.AevumECorp; + var ecorp = LocationName.AevumECorp; var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], randInt(40, 50) / 100, true, 19, randInt(17e3, 28e3), 2.4e12); StockMarket[ecorp] = ecorpStk; - var megacorp = Locations.Sector12MegaCorp; + var megacorp = LocationName.Sector12MegaCorp; var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], randInt(40,50)/100, true, 19, randInt(24e3, 34e3), 2.4e12); StockMarket[megacorp] = megacorpStk; - var blade = Locations.Sector12BladeIndustries; + var blade = LocationName.Sector12BladeIndustries; var bladeStk = new Stock(blade, StockSymbols[blade], randInt(70, 80)/100, true, 13, randInt(12e3, 25e3), 1.6e12); StockMarket[blade] = bladeStk; - var clarke = Locations.AevumClarkeIncorporated; + var clarke = LocationName.AevumClarkeIncorporated; var clarkeStk = new Stock(clarke, StockSymbols[clarke], randInt(65, 75)/100, true, 12, randInt(10e3, 25e3), 1.5e12); StockMarket[clarke] = clarkeStk; - var omnitek = Locations.VolhavenOmniTekIncorporated; + var omnitek = LocationName.VolhavenOmniTekIncorporated; var omnitekStk = new Stock(omnitek, StockSymbols[omnitek], randInt(60, 70)/100, true, 12, randInt(32e3, 43e3), 1.8e12); StockMarket[omnitek] = omnitekStk; - var foursigma = Locations.Sector12FourSigma; + var foursigma = LocationName.Sector12FourSigma; var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], randInt(100, 110)/100, true, 17, randInt(50e3, 80e3), 2e12); StockMarket[foursigma] = foursigmaStk; - var kuaigong = Locations.ChongqingKuaiGongInternational; + var kuaigong = LocationName.ChongqingKuaiGongInternational; var kuaigongStk = new Stock(kuaigong, StockSymbols[kuaigong], randInt(75, 85)/100, true, 10, randInt(16e3, 28e3), 1.9e12); StockMarket[kuaigong] = kuaigongStk; - var fulcrum = Locations.AevumFulcrumTechnologies; + var fulcrum = LocationName.AevumFulcrumTechnologies; var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], randInt(120, 130)/100, true, 16, randInt(29e3, 36e3), 2e12); StockMarket[fulcrum] = fulcrumStk; - var storm = Locations.IshimaStormTechnologies; + var storm = LocationName.IshimaStormTechnologies; var stormStk = new Stock(storm, StockSymbols[storm], randInt(80, 90)/100, true, 7, randInt(20e3, 25e3), 1.2e12); StockMarket[storm] = stormStk; - var defcomm = Locations.NewTokyoDefComm; + var defcomm = LocationName.NewTokyoDefComm; var defcommStk = new Stock(defcomm, StockSymbols[defcomm], randInt(60, 70)/100, true, 10, randInt(6e3, 19e3), 900e9); StockMarket[defcomm] = defcommStk; - var helios = Locations.VolhavenHeliosLabs; + var helios = LocationName.VolhavenHeliosLabs; var heliosStk = new Stock(helios, StockSymbols[helios], randInt(55, 65)/100, true, 9, randInt(10e3, 18e3), 825e9); StockMarket[helios] = heliosStk; - var vitalife = Locations.NewTokyoVitaLife; + var vitalife = LocationName.NewTokyoVitaLife; var vitalifeStk = new Stock(vitalife, StockSymbols[vitalife], randInt(70, 80)/100, true, 7, randInt(8e3, 14e3), 1e12); StockMarket[vitalife] = vitalifeStk; - var icarus = Locations.Sector12IcarusMicrosystems; + var icarus = LocationName.Sector12IcarusMicrosystems; var icarusStk = new Stock(icarus, StockSymbols[icarus], randInt(60, 70)/100, true, 7.5, randInt(12e3, 24e3), 800e9); StockMarket[icarus] = icarusStk; - var universalenergy = Locations.Sector12UniversalEnergy; + var universalenergy = LocationName.Sector12UniversalEnergy; var universalenergyStk = new Stock(universalenergy, StockSymbols[universalenergy], randInt(50, 60)/100, true, 10, randInt(16e3, 29e3), 900e9); StockMarket[universalenergy] = universalenergyStk; - var aerocorp = Locations.AevumAeroCorp; + var aerocorp = LocationName.AevumAeroCorp; var aerocorpStk = new Stock(aerocorp, StockSymbols[aerocorp], randInt(55, 65)/100, true, 6, randInt(8e3, 17e3), 640e9); StockMarket[aerocorp] = aerocorpStk; - var omnia = Locations.VolhavenOmniaCybersystems; + var omnia = LocationName.VolhavenOmniaCybersystems; var omniaStk = new Stock(omnia, StockSymbols[omnia], randInt(65, 75)/100, true, 4.5, randInt(6e3, 15e3), 600e9); StockMarket[omnia] = omniaStk; - var solaris = Locations.ChongqingSolarisSpaceSystems; + var solaris = LocationName.ChongqingSolarisSpaceSystems; var solarisStk = new Stock(solaris, StockSymbols[solaris], randInt(70, 80)/100, true, 8.5, randInt(14e3, 28e3), 705e9); StockMarket[solaris] = solarisStk; - var globalpharm = Locations.NewTokyoGlobalPharmaceuticals; + var globalpharm = LocationName.NewTokyoGlobalPharmaceuticals; var globalpharmStk = new Stock(globalpharm, StockSymbols[globalpharm], randInt(55, 65)/100, true, 10.5, randInt(12e3, 30e3), 695e9); StockMarket[globalpharm] = globalpharmStk; - var nova = Locations.IshimaNovaMedical; + var nova = LocationName.IshimaNovaMedical; var novaStk = new Stock(nova, StockSymbols[nova], randInt(70, 80)/100, true, 5, randInt(15e3, 27e3), 600e9); StockMarket[nova] = novaStk; - var watchdog = Locations.AevumWatchdogSecurity; + var watchdog = LocationName.AevumWatchdogSecurity; var watchdogStk = new Stock(watchdog, StockSymbols[watchdog], randInt(240, 260)/100, true, 1.5, randInt(4e3, 8.5e3), 450e9); StockMarket[watchdog] = watchdogStk; - var lexocorp = Locations.VolhavenLexoCorp; + var lexocorp = LocationName.VolhavenLexoCorp; var lexocorpStk = new Stock(lexocorp, StockSymbols[lexocorp], randInt(115, 135)/100, true, 6, randInt(4.5e3, 8e3), 300e9); StockMarket[lexocorp] = lexocorpStk; - var rho = Locations.AevumRhoConstruction; + var rho = LocationName.AevumRhoConstruction; var rhoStk = new Stock(rho, StockSymbols[rho], randInt(50, 70)/100, true, 1, randInt(2e3, 7e3), 180e9); StockMarket[rho] = rhoStk; - var alpha = Locations.Sector12AlphaEnterprises; + var alpha = LocationName.Sector12AlphaEnterprises; var alphaStk = new Stock(alpha, StockSymbols[alpha], randInt(175, 205)/100, true, 10, randInt(4e3, 8.5e3), 240e9); StockMarket[alpha] = alphaStk; - var syscore = Locations.VolhavenSysCoreSecurities; + var syscore = LocationName.VolhavenSysCoreSecurities; var syscoreStk = new Stock(syscore, StockSymbols[syscore], randInt(150, 170)/100, true, 3, randInt(3e3, 8e3), 200e9); StockMarket[syscore] = syscoreStk; - var computek = Locations.VolhavenCompuTek; + var computek = LocationName.VolhavenCompuTek; var computekStk = new Stock(computek, StockSymbols[computek], randInt(80, 100)/100, true, 4, randInt(1e3, 6e3), 185e9); StockMarket[computek] = computekStk; - var netlink = Locations.AevumNetLinkTechnologies; + var netlink = LocationName.AevumNetLinkTechnologies; var netlinkStk = new Stock(netlink, StockSymbols[netlink], randInt(400, 430)/100, true, 1, randInt(1e3, 5e3), 58e9); StockMarket[netlink] = netlinkStk; - var omega = Locations.IshimaOmegaSoftware; + var omega = LocationName.IshimaOmegaSoftware; var omegaStk = new Stock(omega, StockSymbols[omega], randInt(90, 110)/100, true, 0.5, randInt(1e3, 8e3), 60e9); StockMarket[omega] = omegaStk; - var fns = Locations.Sector12FoodNStuff; + var fns = LocationName.Sector12FoodNStuff; var fnsStk = new Stock(fns, StockSymbols[fns], randInt(70, 80)/100, false, 1, randInt(500, 4.5e3), 45e9); StockMarket[fns] = fnsStk; diff --git a/src/engine.jsx b/src/engine.jsx index b1e5064e2..165375964 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -27,15 +27,13 @@ import { displayFactionContent, joinFaction, processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers"; import { FconfSettings } from "./Fconf/FconfSettings"; -import {displayLocationContent, - initLocationButtons} from "./Location"; -import {Locations} from "./Locations"; import { hasHacknetServers, renderHacknetNodesUI, clearHacknetNodesUI, processHacknetEarnings } from "./Hacknet/HacknetHelpers"; import {iTutorialStart} from "./InteractiveTutorial"; import {initLiterature} from "./Literature"; +import { LocationRoot } from "./Locations/ui/Root"; import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers"; import {inMission, currMission} from "./Missions"; import {initSingularitySFFlags, @@ -174,7 +172,7 @@ $(document).keydown(function(e) { Engine.loadHacknetNodesContent(); } else if (e.keyCode === KEY.W && e.altKey) { e.preventDefault(); - Engine.loadWorldContent(); + Engine.loadLocationContent(); } else if (e.keyCode === KEY.J && e.altKey) { e.preventDefault(); Engine.loadJobContent(); @@ -233,7 +231,6 @@ const Engine = { scriptEditorContent: null, activeScriptsContent: null, hacknetNodesContent: null, - worldContent: null, createProgramContent: null, factionsContent: null, factionContent: null, @@ -302,14 +299,6 @@ const Engine = { MainMenuLinks.HacknetNodes.classList.add("active"); }, - loadWorldContent: function() { - Engine.hideAllContent(); - Engine.Display.worldContent.style.display = "block"; - Engine.displayWorldInfo(); - routing.navigateTo(Page.World); - MainMenuLinks.City.classList.add("active"); - }, - loadCreateProgramContent: function() { Engine.hideAllContent(); Engine.Display.createProgramContent.style.display = "block"; @@ -357,40 +346,17 @@ const Engine = { loadLocationContent: function() { Engine.hideAllContent(); Engine.Display.locationContent.style.display = "block"; - try { - displayLocationContent(); - } catch(e) { - exceptionAlert(e); - console.error(e); - } routing.navigateTo(Page.Location); + const rootComponent = + ReactDOM.render(rootComponent, Engine.Display.locationContent); }, loadTravelContent: function() { - switch(Player.city) { - case Locations.Aevum: - Player.location = Locations.AevumTravelAgency; - break; - case Locations.Chongqing: - Player.location = Locations.ChongqingTravelAgency; - break; - case Locations.Sector12: - Player.location = Locations.Sector12TravelAgency; - break; - case Locations.NewTokyo: - Player.location = Locations.NewTokyoTravelAgency; - break; - case Locations.Ishima: - Player.location = Locations.IshimaTravelAgency; - break; - case Locations.Volhaven: - Player.location = Locations.VolhavenTravelAgency; - break; - default: - dialogBoxCreate("ERROR: Invalid city. This is a bug please contact game dev"); - break; - } + Player.gotoLocation(LocationName.TravelAgency); Engine.loadLocationContent(); }, @@ -510,7 +476,6 @@ const Engine = { Engine.Display.scriptEditorContent.style.display = "none"; Engine.Display.activeScriptsContent.style.display = "none"; clearHacknetNodesUI(); - Engine.Display.worldContent.style.display = "none"; Engine.Display.createProgramContent.style.display = "none"; Engine.Display.factionsContent.style.display = "none"; Engine.Display.factionContent.style.display = "none"; @@ -542,14 +507,6 @@ const Engine = { clearResleevesPage(); clearSleevesPage(); - //Location lists - Engine.aevumLocationsList.style.display = "none"; - Engine.chongqingLocationsList.style.display = "none"; - Engine.sector12LocationsList.style.display = "none"; - Engine.newTokyoLocationsList.style.display = "none"; - Engine.ishimaLocationsList.style.display = "none"; - Engine.volhavenLocationsList.style.display = "none"; - //Make nav menu tabs inactive MainMenuLinks.Terminal.classList.remove("active"); MainMenuLinks.ScriptEditor.classList.remove("active"); @@ -592,99 +549,6 @@ const Engine = { displayCharacterInfo(Engine.Display.characterInfo, Player); }, - /* Display locations in the world*/ - aevumLocationsList: null, - chongqingLocationsList: null, - sector12LocationsList: null, - newTokyoLocationsList: null, - ishimaLocationsList: null, - volhavenLocationsList: null, - - displayWorldInfo: function() { - Engine.aevumLocationsList.style.display = "none"; - Engine.chongqingLocationsList.style.display = "none"; - Engine.sector12LocationsList.style.display = "none"; - Engine.newTokyoLocationsList.style.display = "none"; - Engine.ishimaLocationsList.style.display = "none"; - Engine.volhavenLocationsList.style.display = "none"; - - document.getElementById("world-city-name").innerHTML = Player.city; - var cityDesc = document.getElementById("world-city-desc"); //TODO - switch(Player.city) { - case Locations.Aevum: - Engine.aevumLocationsList.style.display = "inline"; - break; - case Locations.Chongqing: - Engine.chongqingLocationsList.style.display = "inline"; - break; - case Locations.Sector12: - Engine.sector12LocationsList.style.display = "inline"; - - //City hall only in BitNode-3/with Source-File 3 - if ((Player.bitNodeN === 3 || hasCorporationSF) && Player.bitNodeN !== 8) { - document.getElementById("sector12-cityhall-li").style.display = "block"; - } else { - document.getElementById("sector12-cityhall-li").style.display = "none"; - } - break; - case Locations.NewTokyo: - Engine.newTokyoLocationsList.style.display = "inline"; - break; - case Locations.Ishima: - Engine.ishimaLocationsList.style.display = "inline"; - break; - case Locations.Volhaven: - Engine.volhavenLocationsList.style.display = "inline"; - break; - default: - console.log("Invalid city value in Player object!"); - break; - } - - //Generic Locations (common to every city): - // World Stock Exchange - // Corporation (if applicable) - // Bladeburner HQ (if applicable); - var genericLocationsList = document.getElementById("generic-locations-list"); - genericLocationsList.style.display = "inline"; - removeChildrenFromElement(genericLocationsList); - var li = createElement("li"); - li.appendChild(createElement("a", { - innerText:"World Stock Exchange", class:"a-link-button", - clickListener:()=>{ - Player.location = Locations.WorldStockExchange; - Engine.loadStockMarketContent(); - return false; - } - })); - genericLocationsList.appendChild(li); - - if (Player.corporation instanceof Corporation && document.getElementById("location-corporation-button") == null) { - var li = createElement("li"); - li.appendChild(createElement("a", { - innerText:Player.corporation.name, id:"location-corporation-button", - class:"a-link-button", - clickListener:()=>{ - Engine.loadCorporationContent(); - return false; - } - })); - genericLocationsList.appendChild(li); - } - - if (Player.bladeburner instanceof Bladeburner) { - var li = createElement("li"); - li.appendChild(createElement("a", { - innerText:"Bladeburner Headquarters", class:"a-link-button", - clickListener:()=>{ - Engine.loadBladeburnerContent(); - return false; - } - })); - genericLocationsList.appendChild(li); - } - }, - displayFactionsInfo: function() { removeChildrenFromElement(Engine.Display.factionsContent); @@ -1343,9 +1207,6 @@ const Engine = { Engine.Display.hacknetNodesContent = document.getElementById("hacknet-nodes-container"); Engine.Display.hacknetNodesContent.style.display = "none"; - Engine.Display.worldContent = document.getElementById("world-container"); - Engine.Display.worldContent.style.display = "none"; - Engine.Display.createProgramContent = document.getElementById("create-program-container"); Engine.Display.createProgramContent.style.display = "none"; @@ -1378,22 +1239,12 @@ const Engine = { //Character info Engine.Display.characterInfo = document.getElementById("character-content"); - //Location lists - Engine.aevumLocationsList = document.getElementById("aevum-locations-list"); - Engine.chongqingLocationsList = document.getElementById("chongqing-locations-list"); - Engine.sector12LocationsList = document.getElementById("sector12-locations-list"); - Engine.newTokyoLocationsList = document.getElementById("newtokyo-locations-list"); - Engine.ishimaLocationsList = document.getElementById("ishima-locations-list"); - Engine.volhavenLocationsList = document.getElementById("volhaven-locations-list"); - //Location page (page that shows up when you visit a specific location in World) Engine.Display.locationContent = document.getElementById("location-container"); - //Engine.Display.locationContent.style.visibility = "hidden"; Engine.Display.locationContent.style.display = "none"; //Work In Progress Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container"); - //Engine.Display.workInProgressContent.style.visibility = "hidden"; Engine.Display.workInProgressContent.style.display = "none"; //Red Pill / Hack World Daemon @@ -1404,9 +1255,6 @@ const Engine = { Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container"); Engine.Display.cinematicTextContent.style.display = "none"; - //Init Location buttons - initLocationButtons(); - // Initialize references to main menu links if (!initializeMainMenuLinks()) { const errorMsg = "Failed to initialize Main Menu Links. Please try refreshing the page. " + @@ -1480,7 +1328,7 @@ const Engine = { }); MainMenuLinks.City.addEventListener("click", function() { - Engine.loadWorldContent(); + Engine.loadLocationContent(); return false; }); diff --git a/src/index.html b/src/index.html index 581d89543..3cf953026 100644 --- a/src/index.html +++ b/src/index.html @@ -206,11 +206,6 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
    - -
    - -
    -

    @@ -238,160 +233,41 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>

    Tutorial (AKA Links to Documentation)

    - Getting Started -

    + Getting Started

    - Servers & Networking -

    + Servers & Networking

    - Hacking -

    + Hacking

    - Scripts -

    + Scripts

    - Netscript Programming Language -

    + Netscript Programming Language

    - Traveling -

    + Traveling

    - Companies -

    + Companies

    - Infiltration -

    + Infiltration

    - Factions -

    + Factions

    - Augmentations -

    + Augmentations

    - Keyboard Shortcuts - + Keyboard Shortcuts
    - Return to World -

    -

    - -

    -

    ---------------

    -

    -

    ---------------

    -

    -

    ---------------

    - - - Apply for Software Job - Apply for Software Consultant Job - Apply for IT Job - Apply for Security Engineer Job - Apply for Network Engineer Job - Apply for Business Job - Apply for Business Consultant Job - Apply for Security Job - Apply to be an Agent - Apply to be an Employee - Apply to be a Part-time Employee - Apply to be a Waiter - Apply to be a Part-time Waiter - - Work - - - Train Strength - Train Defense - Train Dexterity - Train Agility - - - Study Computer Science (free) - Take Data Structures course - Take Networks course - Take Algorithms course - Take Management course - Take Leadership course - - - Purchase 2GB Server - $150,000 - Purchase 4GB Server - $300,000 - Purchase 8GB Server - $600,000 - Purchase 16GB Server - $1,200,000 - Purchase 32GB Server - $2,400,000 - Purchase 64GB Server - $4,800,000 - Purchase 128GB Server - $9,600,000 - Purchase 256GB Server - $19,200,000 - Purchase 512GB Server - $38,400,000 - Purchase 1TB Server - $75,000,000 - Purchase TOR Router - $100,000 - Purchase additional RAM for Home computer - Purchase additional Core for Home computer - - - Infiltrate Company - - Infiltrate this company's facility to try and steal their classified secrets! - Warning: You may end up hospitalized if you are unsuccessful! - - - - - Get Treatment for Wounds - - -

    - From here, you can travel to any other city! A ticket costs $200,000. -

    - Travel to Aevum - Travel to Chongqing - Travel to Sector-12 - Travel to New Tokyo - Travel to Ishima - Travel to Volhaven - - -

    - You have entered the Slums, a poverty-ridden district filled with gangs, criminals, and - other shadowy entities. The city's government and police have neglected this area for years... -


    - In the Slums, you can commit crimes to earn money and experience. Crime attempts are not always - successful. Your chance at successfully committing a crime is determined by your stats. -

    - Shoplift - Rob a store - Mug someone - Commit Larceny - Deal Drugs - Bond Forgery - Traffick Illegal Arms - Homicide - Grand Theft Auto - Kidnap and Ransom - Assassinate - Heist - - - Create a Corporation - - - Bladeburner Division - - - Re-Sleeve
    diff --git a/src/ui/React/AutoupdatingStdButton.tsx b/src/ui/React/AutoupdatingStdButton.tsx new file mode 100644 index 000000000..a2f9d5a6a --- /dev/null +++ b/src/ui/React/AutoupdatingStdButton.tsx @@ -0,0 +1,70 @@ +/** + * Basic stateless button that automatically re-renders itself every X seconds + * Uses the 'std-button' css class + * + * NOT recommended for usage - only if you really have to + */ +import * as React from "react"; + +interface IProps { + disabled?: boolean; + intervalTime?: number; + onClick?: (e: React.MouseEvent) => any; + style?: object; + text: string; + tooltip?: string; +} + +interface IState { + i: number; +} + +export class AutoupdatingStdButton extends React.Component { + /** + * Timer ID for auto-updating implementation (returned value from setInterval()) + */ + interval: number = 0; + + constructor(props: IProps) { + super(props); + this.state = { + i: 0, + } + } + + componentDidMount() { + const time = this.props.intervalTime ? this.props.intervalTime : 1000; + this.interval = setInterval(() => this.tick(), time); + } + + componentWillUnmount() { + clearInterval(this.interval); + } + + tick() { + this.setState(prevState => ({ + i: prevState.i + 1 + })); + } + + render() { + const hasTooltip = this.props.tooltip !== ""; + + let className = this.props.disabled ? "std-button-disabled" : "std-button"; + if (hasTooltip) { + className += " tooltip" + } + + return ( + + ) + } +} diff --git a/src/ui/React/StdButton.tsx b/src/ui/React/StdButton.tsx index ec3081f2c..ec3dfd5ee 100644 --- a/src/ui/React/StdButton.tsx +++ b/src/ui/React/StdButton.tsx @@ -4,20 +4,31 @@ */ import * as React from "react"; -export interface IStdButtonProps { +interface IStdButtonProps { disabled?: boolean; onClick?: (e: React.MouseEvent) => any; style?: object; text: string; + tooltip?: string; } export class StdButton extends React.Component { render() { - const className = this.props.disabled ? "std-button-disabled" : "std-button"; + const hasTooltip = this.props.tooltip !== ""; + let className = this.props.disabled ? "std-button-disabled" : "std-button"; + if (hasTooltip) { + className += " tooltip"; + } return ( ) } diff --git a/src/ui/React/StdButtonPurchased.tsx b/src/ui/React/StdButtonPurchased.tsx new file mode 100644 index 000000000..40e5ed7ce --- /dev/null +++ b/src/ui/React/StdButtonPurchased.tsx @@ -0,0 +1,20 @@ +/** + * Stateless button that represents something that has been purchased. + */ +import * as React from "react"; + +interface IStdButtonPurchasedProps { + onClick?: (e: React.MouseEvent) => any; + style?: object; + text: string; +} + +export class StdButtonPurchased extends React.Component { + render() { + return ( + + ) + } +} diff --git a/src/ui/React/StdButtonWithTooltip.tsx b/src/ui/React/StdButtonWithTooltip.tsx deleted file mode 100644 index 5b1f20aae..000000000 --- a/src/ui/React/StdButtonWithTooltip.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Basic stateless button with a tooltip - * Uses the 'std-button' css class - */ -import * as React from "react"; - -export interface IStdButtonWithTooltipProps { - disabled?: boolean; - onClick?: (e: React.MouseEvent) => any; - style?: object; - text: string; - tooltip: string; -} - -export class StdButtonWithTooltip extends React.Component { - render() { - const className = this.props.disabled ? "std-button-disabled tooltip" : "std-button tooltip"; - - return ( - - ) - } -} diff --git a/src/ui/navigationTracking.ts b/src/ui/navigationTracking.ts index e276dc7c8..8692f906b 100644 --- a/src/ui/navigationTracking.ts +++ b/src/ui/navigationTracking.ts @@ -28,11 +28,6 @@ export enum Page { */ HacknetNodes = "HacknetNodes", - /** - * View the city the player is currently in. - */ - World = "World", - /** * The list of programs the player could potentially build. */ @@ -64,7 +59,7 @@ export enum Page { DevMenu = "Dev Menu", /** - * Information about the specific location the player at (job, company, etc.); + * Visiting a location in the world */ Location = "Location", diff --git a/utils/DialogBox.d.ts b/utils/DialogBox.d.ts index 67b8e43f4..49f6c5a57 100644 --- a/utils/DialogBox.d.ts +++ b/utils/DialogBox.d.ts @@ -1,2 +1,2 @@ -export function dialogBoxCreate(txt: string, preformatted: boolean): void; -export var dialogBoxOpened: boolean; \ No newline at end of file +export function dialogBoxCreate(txt: string, preformatted?: boolean): void; +export var dialogBoxOpened: boolean; diff --git a/utils/YesNoBox.ts b/utils/YesNoBox.ts index 1114a93d5..0a6175c08 100644 --- a/utils/YesNoBox.ts +++ b/utils/YesNoBox.ts @@ -6,7 +6,8 @@ * 1. Just a Yes/No response from player * 2. Popup also includes a text input field in addition to the Yes/No response */ -import {clearEventListeners} from "./uiHelpers/clearEventListeners"; +import { clearEventListeners } from "./uiHelpers/clearEventListeners"; +import { KEY } from "./helpers/keyCodes"; export let yesNoBoxOpen: boolean = false; @@ -14,9 +15,9 @@ const yesNoBoxContainer: HTMLElement | null = document.getElementById("yes-no-bo const yesNoBoxTextElement: HTMLElement | null = document.getElementById("yes-no-box-text"); export function yesNoBoxHotkeyHandler(e: KeyboardEvent) { - if (e.keyCode === 27) { + if (e.keyCode === KEY.ESC) { yesNoBoxClose(); - } else if (e.keyCode === 13) { + } else if (e.keyCode === KEY.ENTER) { const yesBtn: HTMLElement | null = document.getElementById("yes-no-box-yes"); if (yesBtn) { yesBtn.click(); @@ -78,9 +79,9 @@ const yesNoTextInputBoxInput: HTMLInputElement | null = document.getElementById( const yesNoTextInputBoxTextElement: HTMLElement | null = document.getElementById("yes-no-text-input-box-text"); export function yesNoTxtInpBoxHotkeyHandler(e: KeyboardEvent) { - if (e.keyCode === 27) { + if (e.keyCode === KEY.ESC) { yesNoTxtInpBoxClose(); - } else if (e.keyCode === 13) { + } else if (e.keyCode === KEY.ENTER) { const yesBtn: HTMLElement | null = document.getElementById("yes-no-text-input-box-yes"); if (yesBtn) { yesBtn.click(); From bf9b837e3184506384188499bc93057e1aef217a Mon Sep 17 00:00:00 2001 From: danielyxie Date: Wed, 3 Apr 2019 17:08:11 -0700 Subject: [PATCH 4/4] Fixed bugs with Location code refactor --- src/Company/GetNextCompanyPosition.ts | 2 +- src/Locations/LocationsHelpers.ts | 2 +- src/Locations/ui/ApplyToJobButton.tsx | 2 + src/Locations/ui/City.tsx | 4 +- src/Locations/ui/CompanyLocation.tsx | 115 +- src/Locations/ui/GenericLocation.tsx | 22 +- src/Locations/ui/GymLocation.tsx | 11 + src/Locations/ui/HospitalLocation.tsx | 8 + src/Locations/ui/Root.tsx | 7 +- src/Locations/ui/SlumsLocation.tsx | 23 +- src/Locations/ui/SpecialLocation.tsx | 15 +- src/Locations/ui/TechVendorLocation.tsx | 12 + src/Locations/ui/TravelAgencyLocation.tsx | 12 +- src/Locations/ui/UniversityLocation.tsx | 14 + src/PersonObjects/IPlayer.ts | 7 + src/PersonObjects/Player/PlayerObject.js | 212 ++ .../Player/PlayerObjectBladeburnerMethods.js | 17 + .../Player/PlayerObjectCorporationMethods.js | 19 + .../Player/PlayerObjectGeneralMethods.js | 2301 +++++++++++++++ .../Player/PlayerObjectServerMethods.ts | 30 + src/Player.js | 2541 +---------------- src/engine.jsx | 53 +- src/ui/React/AutoupdatingStdButton.tsx | 18 +- src/ui/React/StdButton.tsx | 21 +- 24 files changed, 2897 insertions(+), 2571 deletions(-) create mode 100644 src/PersonObjects/Player/PlayerObject.js create mode 100644 src/PersonObjects/Player/PlayerObjectBladeburnerMethods.js create mode 100644 src/PersonObjects/Player/PlayerObjectCorporationMethods.js create mode 100644 src/PersonObjects/Player/PlayerObjectGeneralMethods.js create mode 100644 src/PersonObjects/Player/PlayerObjectServerMethods.ts diff --git a/src/Company/GetNextCompanyPosition.ts b/src/Company/GetNextCompanyPosition.ts index 61b1a8c2e..b6ca6118c 100644 --- a/src/Company/GetNextCompanyPosition.ts +++ b/src/Company/GetNextCompanyPosition.ts @@ -3,7 +3,7 @@ import { CompanyPosition } from "./CompanyPosition"; import { CompanyPositions } from "./CompanyPositions"; -export function getNextCompanyPosition(currPos: CompanyPosition | null): CompanyPosition | null { +export function getNextCompanyPositionHelper(currPos: CompanyPosition | null): CompanyPosition | null { if (currPos == null) { return null; } const nextPosName: string | null = currPos.nextPosition; diff --git a/src/Locations/LocationsHelpers.ts b/src/Locations/LocationsHelpers.ts index 2ee71338c..49ca28c8f 100644 --- a/src/Locations/LocationsHelpers.ts +++ b/src/Locations/LocationsHelpers.ts @@ -107,7 +107,7 @@ export function createPurchaseServerPopup(ram: number, p: IPlayer) { * Create a popup that lets the player start a Corporation */ export function createStartCorporationPopup(p: IPlayer) { - if (p.hasCorporation) { return; } + if (!p.canAccessCorporation() || p.hasCorporation) { return; } const popupId = "create-corporation-popup"; const txt = createElement("p", { diff --git a/src/Locations/ui/ApplyToJobButton.tsx b/src/Locations/ui/ApplyToJobButton.tsx index 993cfce68..58f464257 100644 --- a/src/Locations/ui/ApplyToJobButton.tsx +++ b/src/Locations/ui/ApplyToJobButton.tsx @@ -15,6 +15,7 @@ type IProps = { entryPosType: CompanyPosition; onClick: (e: React.MouseEvent) => void; p: IPlayer; + style?: object; text: string; } @@ -38,6 +39,7 @@ export class ApplyToJobButton extends React.Component { return ( diff --git a/src/Locations/ui/City.tsx b/src/Locations/ui/City.tsx index 91ad06f1a..9e93d3e3b 100644 --- a/src/Locations/ui/City.tsx +++ b/src/Locations/ui/City.tsx @@ -19,8 +19,8 @@ export class LocationCity extends React.Component { render() { const locationButtons = this.props.city.locations.map((locName) => { return ( -
  • - +
  • +
  • ) }); diff --git a/src/Locations/ui/CompanyLocation.tsx b/src/Locations/ui/CompanyLocation.tsx index 204c28310..e67842f2a 100644 --- a/src/Locations/ui/CompanyLocation.tsx +++ b/src/Locations/ui/CompanyLocation.tsx @@ -16,10 +16,12 @@ import { beginInfiltration } from "../../Infiltration"; import { Companies } from "../../Company/Companies"; import { Company } from "../../Company/Company"; +import { CompanyPosition } from "../../Company/CompanyPosition"; import { CompanyPositions } from "../../Company/CompanyPositions"; import * as posNames from "../../Company/data/companypositionnames"; import { IPlayer } from "../../PersonObjects/IPlayer"; +import { numeralWrapper } from "../../ui/numeralFormat"; import { StdButton } from "../../ui/React/StdButton"; type IProps = { @@ -28,21 +30,43 @@ type IProps = { p: IPlayer; } -export class CompanyLocation extends React.Component { +type IState = { + employedHere: boolean; +} + +export class CompanyLocation extends React.Component { /** * 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; + /** + * CompanyPosition object for the job that the player holds at this company + * (if he has one) + */ + companyPosition: CompanyPosition | null = null; + + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + /** * Reference to the Location that this component is being rendered for */ location: Location; + /** + * Name of company position that player holds, if applicable + */ + jobTitle: string | null = null; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.applyForAgentJob = this.applyForAgentJob.bind(this); this.applyForBusinessConsultantJob = this.applyForBusinessConsultantJob.bind(this); this.applyForBusinessJob = this.applyForBusinessJob.bind(this); @@ -54,7 +78,9 @@ export class CompanyLocation extends React.Component { this.applyForSoftwareConsultantJob = this.applyForSoftwareConsultantJob.bind(this); this.applyForSoftwareJob = this.applyForSoftwareJob.bind(this); this.applyForWaiterJob = this.applyForWaiterJob.bind(this); + this.checkIfEmployedHere = this.checkIfEmployedHere.bind(this); this.startInfiltration = this.startInfiltration.bind(this); + this.work = this.work.bind(this); this.location = Locations[props.locName]; if (this.location == null) { @@ -65,61 +91,91 @@ export class CompanyLocation extends React.Component { if (this.company == null) { throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`); } + + this.state = { + employedHere: false, + } + + this.checkIfEmployedHere(false); } applyForAgentJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForAgentJob(); + this.checkIfEmployedHere(); } applyForBusinessConsultantJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForBusinessConsultantJob(); + this.checkIfEmployedHere(); } applyForBusinessJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForBusinessJob(); + this.checkIfEmployedHere(); } applyForEmployeeJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForEmployeeJob(); + this.checkIfEmployedHere(); } applyForItJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForItJob(); + this.checkIfEmployedHere(); } applyForPartTimeEmployeeJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForPartTimeEmployeeJob(); + this.checkIfEmployedHere(); } applyForPartTimeWaiterJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForPartTimeWaiterJob(); + this.checkIfEmployedHere(); } applyForSecurityJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForSecurityJob(); + this.checkIfEmployedHere(); } applyForSoftwareConsultantJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForSoftwareConsultantJob(); + this.checkIfEmployedHere(); } applyForSoftwareJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForSoftwareJob(); + this.checkIfEmployedHere(); } applyForWaiterJob(e: React.MouseEvent) { if (!e.isTrusted) { return false; } this.props.p.applyForWaiterJob(); + this.checkIfEmployedHere(); + } + + checkIfEmployedHere(updateState=true) { + this.jobTitle = this.props.p.jobs[this.props.locName]; + if (this.jobTitle != null) { + this.companyPosition = CompanyPositions[this.jobTitle]; + } + + if (updateState) { + this.setState({ + employedHere: this.jobTitle != null + }); + } } startInfiltration(e: React.MouseEvent) { @@ -133,9 +189,54 @@ export class CompanyLocation extends React.Component { beginInfiltration(this.props.locName, data.startingSecurityLevel, data.baseRewardValue, data.maxClearanceLevel, data.difficulty); } + work(e: React.MouseEvent) { + if (!e.isTrusted) { return false; } + + const pos = this.companyPosition; + if (pos instanceof CompanyPosition) { + if (pos.isPartTimeJob() || pos.isSoftwareConsultantJob() || pos.isBusinessConsultantJob()) { + this.props.p.startWorkPartTime(this.props.locName); + } else { + this.props.p.startWork(this.props.locName); + } + } + } + render() { + const isEmployedHere = this.jobTitle != null; + const favorGain = this.company.getFavorGain(); + return (
    + { + isEmployedHere && +
    +

    Job Title: {this.jobTitle}

    +

    --------------------

    +

    + Company reputation: {numeralWrapper.format(this.company.playerReputation, "0,0.000")} + + You will earn ${numeralWrapper.format(favorGain[0], "0,0")} company + favor upon resetting after installing Augmentations + +

    +

    --------------------

    +

    + Company Favor: {numeralWrapper.format(this.company.favor, "0,0")} + + Company favor increases the rate at which you earn reputation for this company by + 1% per favor. Company favor is gained whenever you reset after installing Augmentations. The amount + of favor you gain depends on how much reputation you have with the comapny. + +

    + +
    + } { this.company.hasAgentPositions() && { entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]} onClick={this.applyForAgentJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Agent Job"} /> } @@ -153,6 +255,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]} onClick={this.applyForBusinessConsultantJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Business Consultant Job"} /> } @@ -163,6 +266,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]} onClick={this.applyForBusinessJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Business Job"} /> } @@ -173,6 +277,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]} onClick={this.applyForEmployeeJob} p={this.props.p} + style={this.btnStyle} text={"Apply to be an Employee"} /> } @@ -183,6 +288,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]} onClick={this.applyForPartTimeEmployeeJob} p={this.props.p} + style={this.btnStyle} text={"Apply to be a part-time Employee"} /> } @@ -193,6 +299,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]} onClick={this.applyForItJob} p={this.props.p} + style={this.btnStyle} text={"Apply for IT Job"} /> } @@ -203,6 +310,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]} onClick={this.applyForSecurityJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Security Job"} /> } @@ -213,6 +321,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]} onClick={this.applyForSoftwareConsultantJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Software Consultant Job"} /> } @@ -223,6 +332,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]} onClick={this.applyForSoftwareJob} p={this.props.p} + style={this.btnStyle} text={"Apply for Software Job"} /> } @@ -233,6 +343,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]} onClick={this.applyForWaiterJob} p={this.props.p} + style={this.btnStyle} text={"Apply to be a Waiter"} /> } @@ -243,6 +354,7 @@ export class CompanyLocation extends React.Component { entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]} onClick={this.applyForPartTimeWaiterJob} p={this.props.p} + style={this.btnStyle} text={"Apply to be a part-time Waiter"} /> } @@ -250,6 +362,7 @@ export class CompanyLocation extends React.Component { (this.location.infiltrationData != null) && } diff --git a/src/Locations/ui/GenericLocation.tsx b/src/Locations/ui/GenericLocation.tsx index 6ed4038fa..d04e15fce 100644 --- a/src/Locations/ui/GenericLocation.tsx +++ b/src/Locations/ui/GenericLocation.tsx @@ -33,6 +33,17 @@ type IProps = { } export class GenericLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + + constructor(props: IProps) { + super(props); + + this.btnStyle = { display: "block" }; + } + /** * Determine what needs to be rendered for this location based on the locations * type. Returns an array of React components that should be rendered @@ -44,6 +55,7 @@ export class GenericLocation extends React.Component { content.push( @@ -53,6 +65,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.Gym)) { content.push( @@ -62,6 +75,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.Hospital)) { content.push( ) @@ -70,6 +84,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.Slums)) { content.push( ) @@ -79,6 +94,7 @@ export class GenericLocation extends React.Component { content.push( @@ -88,6 +104,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.TechVendor)) { content.push( @@ -97,6 +114,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.TravelAgency)) { content.push( @@ -106,6 +124,7 @@ export class GenericLocation extends React.Component { if (this.props.loc.types.includes(LocationType.University)) { content.push( @@ -120,8 +139,7 @@ export class GenericLocation extends React.Component { return (
    - -
    +

    {this.props.loc.name}

    {locContent}
    diff --git a/src/Locations/ui/GymLocation.tsx b/src/Locations/ui/GymLocation.tsx index 7c54c9863..e3a4c1519 100644 --- a/src/Locations/ui/GymLocation.tsx +++ b/src/Locations/ui/GymLocation.tsx @@ -19,9 +19,16 @@ type IProps = { } export class GymLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.trainStrength = this.trainStrength.bind(this); this.trainDefense = this.trainDefense.bind(this); this.trainDexterity = this.trainDexterity.bind(this); @@ -58,18 +65,22 @@ export class GymLocation extends React.Component {
    diff --git a/src/Locations/ui/HospitalLocation.tsx b/src/Locations/ui/HospitalLocation.tsx index cfd4c5e38..ca033af01 100644 --- a/src/Locations/ui/HospitalLocation.tsx +++ b/src/Locations/ui/HospitalLocation.tsx @@ -18,9 +18,16 @@ type IProps = { } export class HospitalLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.getCost = this.getCost.bind(this); this.getHealed = this.getHealed.bind(this); } @@ -48,6 +55,7 @@ export class HospitalLocation extends React.Component { return ( ) diff --git a/src/Locations/ui/Root.tsx b/src/Locations/ui/Root.tsx index fa73a7a6a..351741c19 100644 --- a/src/Locations/ui/Root.tsx +++ b/src/Locations/ui/Root.tsx @@ -20,6 +20,7 @@ import { IPlayer } from "../../PersonObjects/IPlayer"; import { dialogBoxCreate } from "../../../utils/DialogBox"; type IProps = { + initiallyInCity?: boolean; engine: IEngine; p: IPlayer; } @@ -36,16 +37,17 @@ export class LocationRoot extends React.Component { this.state = { city: props.p.city, - inCity: true, + 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.location = to; + this.props.p.gotoLocation(to); this.setState({ inCity: false, location: to, @@ -133,6 +135,7 @@ export class LocationRoot extends React.Component { if (this.props.p.travel(to)) { this.setState({ + inCity: true, city: to }); } diff --git a/src/Locations/ui/SlumsLocation.tsx b/src/Locations/ui/SlumsLocation.tsx index ea9a5cc8f..7afa53bba 100644 --- a/src/Locations/ui/SlumsLocation.tsx +++ b/src/Locations/ui/SlumsLocation.tsx @@ -16,9 +16,16 @@ type IProps = { } export class SlumsLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.shoplift = this.shoplift.bind(this); this.robStore = this.robStore.bind(this); this.mug = this.mug.bind(this); @@ -40,12 +47,12 @@ export class SlumsLocation extends React.Component { robStore(e: React.MouseEvent): void { if (!e.isTrusted) { return; } - Crimes.RobSTore.commit(this.props.p); + Crimes.RobStore.commit(this.props.p); } mug(e: React.MouseEvent): void { if (!e.isTrusted) { return; } - Crimes.mug.commit(this.props.p); + Crimes.Mug.commit(this.props.p); } larceny(e: React.MouseEvent): void { @@ -112,72 +119,84 @@ export class SlumsLocation extends React.Component { diff --git a/src/Locations/ui/SpecialLocation.tsx b/src/Locations/ui/SpecialLocation.tsx index afa1b3955..ba51d8cfa 100644 --- a/src/Locations/ui/SpecialLocation.tsx +++ b/src/Locations/ui/SpecialLocation.tsx @@ -35,9 +35,16 @@ type IState = { } export class SpecialLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.createCorporationPopup = this.createCorporationPopup.bind(this); this.handleBladeburner = this.handleBladeburner.bind(this); this.handleResleeving = this.handleResleeving.bind(this); @@ -89,29 +96,35 @@ export class SpecialLocation extends React.Component { } renderBladeburner(): React.ReactNode { + if (!this.props.p.canAccessBladeburner()) { return null; } const text = this.state.inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division"; return ( ) } renderCreateCorporation(): React.ReactNode { + if (!this.props.p.canAccessCorporation()) { return null; } return ( ) } renderResleeving(): React.ReactNode { + if (!this.props.p.canAccessResleeving()) { return null; } return ( ) diff --git a/src/Locations/ui/TechVendorLocation.tsx b/src/Locations/ui/TechVendorLocation.tsx index 90aadfacd..584f87892 100644 --- a/src/Locations/ui/TechVendorLocation.tsx +++ b/src/Locations/ui/TechVendorLocation.tsx @@ -25,9 +25,16 @@ type IProps = { } export class TechVendorLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.state = { torPurchased: props.p.hasTorRouter(), } @@ -59,6 +66,7 @@ export class TechVendorLocation extends React.Component { createPurchaseServerPopup(i, this.props.p)} + style={this.btnStyle} text={`Purchase ${i}GB Server - ${numeralWrapper.formatMoney(cost)}`} /> ) @@ -70,11 +78,13 @@ export class TechVendorLocation extends React.Component { { this.state.torPurchased ? ( ) : ( ) @@ -82,10 +92,12 @@ export class TechVendorLocation extends React.Component { }
    diff --git a/src/Locations/ui/TravelAgencyLocation.tsx b/src/Locations/ui/TravelAgencyLocation.tsx index 4b5364b87..3f21b6183 100644 --- a/src/Locations/ui/TravelAgencyLocation.tsx +++ b/src/Locations/ui/TravelAgencyLocation.tsx @@ -20,8 +20,15 @@ type IProps = { } export class TravelAgencyLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + + this.btnStyle = { display: "block" }; } render() { @@ -36,6 +43,7 @@ export class TravelAgencyLocation extends React.Component { ) @@ -44,8 +52,8 @@ export class TravelAgencyLocation extends React.Component { return (

    - From here, you can travel to any other city! A ticket costs - {numeralWrapper.formatMoney(CONSTANTS.TravelCost)} + From here, you can travel to any other city! A ticket + costs {numeralWrapper.formatMoney(CONSTANTS.TravelCost)}

    {travelBtns}
    diff --git a/src/Locations/ui/UniversityLocation.tsx b/src/Locations/ui/UniversityLocation.tsx index 934b66856..a5b4d4b0c 100644 --- a/src/Locations/ui/UniversityLocation.tsx +++ b/src/Locations/ui/UniversityLocation.tsx @@ -19,10 +19,18 @@ type IProps = { } export class UniversityLocation extends React.Component { + /** + * Stores button styling that sets them all to block display + */ + btnStyle: object; + constructor(props: IProps) { super(props); + this.btnStyle = { display: "block" }; + this.take = this.take.bind(this); + this.study = this.study.bind(this); this.dataStructures = this.dataStructures.bind(this); this.networks = this.networks.bind(this); this.algorithms = this.algorithms.bind(this); @@ -72,26 +80,32 @@ export class UniversityLocation extends React.Component {
    diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts index ed89e6084..7f60e2409 100644 --- a/src/PersonObjects/IPlayer.ts +++ b/src/PersonObjects/IPlayer.ts @@ -33,6 +33,7 @@ export interface IPlayer { hacknetNodes: (HacknetNode | string)[]; // HacknetNode object or IP of Hacknet Server hashManager: HashManager; hasWseAccount: boolean; + homeComputer: string; hp: number; jobs: IMap; karma: number; @@ -111,6 +112,9 @@ export interface IPlayer { applyForSoftwareConsultantJob(sing?: boolean): boolean | void; applyForSoftwareJob(sing?: boolean): boolean | void; applyForWaiterJob(sing?: boolean): boolean | void; + canAccessBladeburner(): boolean; + canAccessCorporation(): boolean; + canAccessResleeving(): boolean; canAfford(cost: number): boolean; gainHackingExp(exp: number): void; gainStrengthExp(exp: number): void; @@ -122,6 +126,7 @@ export interface IPlayer { getHomeComputer(): Server; getNextCompanyPosition(company: Company, entryPosType: CompanyPosition): CompanyPosition; getUpgradeHomeRamCost(): number; + gotoLocation(to: LocationName): boolean; hasCorporation(): boolean; hasTorRouter(): boolean; inBladeburner(): boolean; @@ -145,5 +150,7 @@ export interface IPlayer { money: number, time: number, singParams: any): void; + startWork(companyName: string): void; + startWorkPartTime(companyName: string): void; travel(to: CityName): boolean; } diff --git a/src/PersonObjects/Player/PlayerObject.js b/src/PersonObjects/Player/PlayerObject.js new file mode 100644 index 000000000..7f9ec86bb --- /dev/null +++ b/src/PersonObjects/Player/PlayerObject.js @@ -0,0 +1,212 @@ +import * as generalMethods from "./PlayerObjectGeneralMethods"; +import * as serverMethods from "./PlayerObjectServerMethods"; +import * as bladeburnerMethods from "./PlayerObjectBladeburnerMethods"; +import * as corporationMethods from "./PlayerObjectCorporationMethods"; + +import { HashManager } from "../../Hacknet/HashManager"; +import { CityName } from "../../Locations/data/CityNames"; + +import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; +import { Reviver, + Generic_toJSON, + Generic_fromJSON } from "../../../utils/JSONReviver"; + +import Decimal from "decimal.js"; + +export function PlayerObject() { + //Skills and stats + this.hacking_skill = 1; + + //Combat stats + this.hp = 10; + this.max_hp = 10; + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + //Labor stats + this.charisma = 1; + + //Special stats + this.intelligence = 0; + + //Hacking multipliers + this.hacking_chance_mult = 1; + this.hacking_speed_mult = 1; + this.hacking_money_mult = 1; + this.hacking_grow_mult = 1; + + //Experience and multipliers + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + this.intelligence_exp= 0; + + this.hacking_mult = 1; + this.strength_mult = 1; + this.defense_mult = 1; + this.dexterity_mult = 1; + this.agility_mult = 1; + this.charisma_mult = 1; + + this.hacking_exp_mult = 1; + this.strength_exp_mult = 1; + this.defense_exp_mult = 1; + this.dexterity_exp_mult = 1; + this.agility_exp_mult = 1; + this.charisma_exp_mult = 1; + + this.company_rep_mult = 1; + this.faction_rep_mult = 1; + + //Money + this.money = new Decimal(1000); + + //IP Address of Starting (home) computer + this.homeComputer = ""; + + //Location information + this.city = CityName.Sector12; + this.location = ""; + + // Jobs that the player holds + // Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object) + // The CompanyPosition name must match a key value in CompanyPositions + this.jobs = {}; + + // Company at which player is CURRENTLY working (only valid when the player is actively working) + this.companyName = ""; // Name of Company. Must match a key value in Companies map + + // Servers + this.currentServer = ""; //IP address of Server currently being accessed through terminal + this.purchasedServers = []; //IP Addresses of purchased servers + + // Hacknet Nodes/Servers + this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers + this.hashManager = new HashManager(); + + //Factions + this.factions = []; //Names of all factions player has joined + this.factionInvitations = []; //Outstanding faction invitations + + //Augmentations + this.queuedAugmentations = []; + this.augmentations = []; + + this.sourceFiles = []; + + //Crime statistics + this.numPeopleKilled = 0; + this.karma = 0; + + this.crime_money_mult = 1; + this.crime_success_mult = 1; + + //Flags/variables for working (Company, Faction, Creating Program, Taking Class) + this.isWorking = false; + this.workType = ""; + + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + this.workMoneyLossRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.createProgramName = ""; + this.createProgramReqLvl = 0; + + this.className = ""; + + this.crimeType = ""; + + this.timeWorked = 0; //in ms + this.timeWorkedCreateProgram = 0; + this.timeNeededToCompleteWork = 0; + + this.work_money_mult = 1; + + //Hacknet Node multipliers + this.hacknet_node_money_mult = 1; + this.hacknet_node_purchase_cost_mult = 1; + this.hacknet_node_ram_cost_mult = 1; + this.hacknet_node_core_cost_mult = 1; + this.hacknet_node_level_cost_mult = 1; + + //Stock Market + this.hasWseAccount = false; + this.hasTixApiAccess = false; + this.has4SData = false; + this.has4SDataTixApi = false; + + //Gang + this.gang = 0; + + //Corporation + this.corporation = 0; + + //Bladeburner + this.bladeburner = 0; + this.bladeburner_max_stamina_mult = 1; + this.bladeburner_stamina_gain_mult = 1; + this.bladeburner_analysis_mult = 1; //Field Analysis Only + this.bladeburner_success_chance_mult = 1; + + // Sleeves & Re-sleeving + this.sleeves = []; + this.resleeves = []; + this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant + + //bitnode + this.bitNodeN = 1; + + //Flags for determining whether certain "thresholds" have been achieved + this.firstFacInvRecvd = false; + this.firstAugPurchased = false; + this.firstTimeTraveled = false; + this.firstProgramAvailable = false; + + //Used to store the last update time. + this.lastUpdate = 0; + this.totalPlaytime = 0; + this.playtimeSinceLastAug = 0; + this.playtimeSinceLastBitnode = 0; + + // Keep track of where money comes from + this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation + this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run + + // Production since last Augmentation installation + this.scriptProdSinceLastAug = 0; +}; + +Object.assign(PlayerObject.prototype, generalMethods, serverMethods, bladeburnerMethods, corporationMethods); + +PlayerObject.prototype.toJSON = function() { + return Generic_toJSON("PlayerObject", this); +} + +PlayerObject.fromJSON = function(value) { + return Generic_fromJSON(PlayerObject, value.data); +} + +Reviver.constructors.PlayerObject = PlayerObject; diff --git a/src/PersonObjects/Player/PlayerObjectBladeburnerMethods.js b/src/PersonObjects/Player/PlayerObjectBladeburnerMethods.js new file mode 100644 index 000000000..479021e33 --- /dev/null +++ b/src/PersonObjects/Player/PlayerObjectBladeburnerMethods.js @@ -0,0 +1,17 @@ +import { Bladeburner } from "../../Bladeburner"; +import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; + +export function canAccessBladeburner() { + if (this.bitNodeN === 8) { return false; } + + return (this.bitNodeN === 6) || (this.bitNodeN === 7) || (SourceFileFlags[6] > 0); +} + +export function inBladeburner() { + if (this.bladeburner == null) { return false; } + return (this.bladeburner instanceof Bladeburner); +} + +export function startBladeburner() { + this.bladeburner = new Bladeburner({ new: true }); +} diff --git a/src/PersonObjects/Player/PlayerObjectCorporationMethods.js b/src/PersonObjects/Player/PlayerObjectCorporationMethods.js new file mode 100644 index 000000000..a1d358232 --- /dev/null +++ b/src/PersonObjects/Player/PlayerObjectCorporationMethods.js @@ -0,0 +1,19 @@ +import { Corporation } from "../../Corporation/Corporation"; +import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; + +export function canAccessCorporation() { + return this.bitNodeN === 3 || (SourceFileFlags[3] > 0); +} + +export function hasCorporation() { + if (this.corporation == null) { return false; } + return (this.corporation instanceof Corporation); +} + +export function startCorporation(corpName, additionalShares=0) { + this.corporation = new Corporation({ + name: corpName + }); + + this.corporation.totalShares += additionalShares; +} diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.js b/src/PersonObjects/Player/PlayerObjectGeneralMethods.js new file mode 100644 index 000000000..cfaa4536d --- /dev/null +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.js @@ -0,0 +1,2301 @@ +import { Augmentations } from "../../Augmentation/Augmentations"; +import { applyAugmentation } from "../../Augmentation/AugmentationHelpers"; +import { PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation"; +import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; +import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; +import { Bladeburner } from "../../Bladeburner"; +import { CodingContractRewardType } from "../../CodingContracts"; +import { Company } from "../../Company/Company"; +import { Companies } from "../../Company/Companies"; +import { getNextCompanyPositionHelper } from "../../Company/GetNextCompanyPosition"; +import { getJobRequirementText } from "../../Company/GetJobRequirementText"; +import { CompanyPositions } from "../../Company/CompanyPositions"; +import * as posNames from "../../Company/data/companypositionnames"; +import {CONSTANTS} from "../../Constants"; +import { Corporation } from "../../Corporation/Corporation"; +import { Programs } from "../../Programs/Programs"; +import { determineCrimeSuccess } from "../../Crime/CrimeHelpers"; +import { Crimes } from "../../Crime/Crimes"; +import {Engine} from "../../engine"; +import { Faction } from "../../Faction/Faction"; +import { Factions } from "../../Faction/Factions"; +import { displayFactionContent } from "../../Faction/FactionHelpers"; +import {Gang, resetGangs} from "../../Gang"; +import { hasHacknetServers } from "../../Hacknet/HacknetHelpers"; +import { HashManager } from "../../Hacknet/HashManager"; +import { Cities } from "../../Locations/Cities"; +import { Locations } from "../../Locations/Locations"; +import { CityName } from "../../Locations/data/CityNames"; +import { LocationName } from "../../Locations/data/LocationNames"; +import {hasBn11SF, hasWallStreetSF,hasAISF} from "../../NetscriptFunctions"; +import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve"; +import { AllServers, + AddToAllServers } from "../../Server/AllServers"; +import { Server } from "../../Server/Server"; +import {Settings} from "../../Settings/Settings"; +import {SpecialServerIps, SpecialServerNames} from "../../Server/SpecialServerIps"; +import {SourceFiles, applySourceFile} from "../../SourceFile"; +import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; + +import Decimal from "decimal.js"; + +import {numeralWrapper} from "../../ui/numeralFormat"; +import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; +import {dialogBoxCreate} from "../../../utils/DialogBox"; +import {clearEventListeners} from "../../../utils/uiHelpers/clearEventListeners"; +import {createRandomIp} from "../../../utils/IPAddress"; +import {Reviver, Generic_toJSON, + Generic_fromJSON} from "../../../utils/JSONReviver"; +import {convertTimeMsToTimeElapsedString} from "../../../utils/StringHelperFunctions"; + +const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; + +export function init() { + /* Initialize Player's home computer */ + var t_homeComp = new Server({ + ip:createRandomIp(), hostname:"home", organizationName:"Home PC", + isConnectedTo:true, adminRights:true, purchasedByPlayer:true, maxRam:8 + }); + this.homeComputer = t_homeComp.ip; + this.currentServer = t_homeComp.ip; + AddToAllServers(t_homeComp); + + this.getHomeComputer().programs.push(Programs.NukeProgram.name); +} + +export function prestigeAugmentation() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new Decimal(1000); + + this.city = CityName.Sector12; + this.location = ""; + + this.companyName = ""; + this.jobs = {}; + + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + + this.resleeves = []; + + for (let i = 0; i < this.sleeves.length; ++i) { + if (this.sleeves[i] instanceof Sleeve) { + if (this.sleeves[i].shock >= 100) { + this.sleeves[i].synchronize(this); + } else { + this.sleeves[i].shockRecovery(this); + } + } + } + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + // Statistics Trackers + this.playtimeSinceLastAug = 0; + this.scriptProdSinceLastAug = 0; + this.moneySourceA.reset(); + + this.hacknetNodes.length = 0; + + //Re-calculate skills and reset HP + this.updateSkillLevels(); + this.hp = this.max_hp; +} + +export function prestigeSourceFile() { + var homeComp = this.getHomeComputer(); + this.currentServer = homeComp.ip; + this.homeComputer = homeComp.ip; + + this.numPeopleKilled = 0; + this.karma = 0; + + //Reset stats + this.hacking_skill = 1; + + this.strength = 1; + this.defense = 1; + this.dexterity = 1; + this.agility = 1; + + this.charisma = 1; + + this.hacking_exp = 0; + this.strength_exp = 0; + this.defense_exp = 0; + this.dexterity_exp = 0; + this.agility_exp = 0; + this.charisma_exp = 0; + + this.money = new Decimal(1000); + + this.city = CityName.Sector12; + this.location = ""; + + this.companyName = ""; + this.jobs = {}; + + this.purchasedServers = []; + + this.factions = []; + this.factionInvitations = []; + + this.queuedAugmentations = []; + this.augmentations = []; + + this.resleeves = []; + + // Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists) + this.sleeves.length = SourceFileFlags[10] + this.sleevesFromCovenant; + for (let i = 0; i < this.sleeves.length; ++i) { + if (this.sleeves[i] instanceof Sleeve) { + this.sleeves[i].prestige(this); + } else { + this.sleeves[i] = new Sleeve(this); + } + } + + this.isWorking = false; + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + this.crimeType = ""; + + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + + this.lastUpdate = new Date().getTime(); + + this.hacknetNodes.length = 0; + + //Gang + this.gang = null; + resetGangs(); + + //Reset Stock market + this.hasWseAccount = false; + this.hasTixApiAccess = false; + this.has4SData = false; + this.has4SDataTixApi = false; + + //BitNode 3: Corporatocracy + this.corporation = 0; + + // Statistics trackers + this.playtimeSinceLastAug = 0; + this.playtimeSinceLastBitnode = 0; + this.scriptProdSinceLastAug = 0; + this.moneySourceA.reset(); + this.moneySourceB.reset(); + + this.updateSkillLevels(); + this.hp = this.max_hp; +} + +export function receiveInvite(factionName) { + if(this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) { + return; + } + this.firstFacInvRecvd = true; + this.factionInvitations.push(factionName); +} + +//Calculates skill level based on experience. The same formula will be used for every skill +export function calculateSkill(exp, mult=1) { + return Math.max(Math.floor(mult*(32 * Math.log(exp + 534.5) - 200)), 1); +} + +export function updateSkillLevels() { + this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier))); + this.strength = Math.max(1, Math.floor(this.calculateSkill(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier))); + this.defense = Math.max(1, Math.floor(this.calculateSkill(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier))); + this.dexterity = Math.max(1, Math.floor(this.calculateSkill(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier))); + this.agility = Math.max(1, Math.floor(this.calculateSkill(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier))); + this.charisma = Math.max(1, Math.floor(this.calculateSkill(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier))); + + if (this.intelligence > 0) { + this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp)); + } else { + this.intelligence = 0; + } + + var ratio = this.hp / this.max_hp; + this.max_hp = Math.floor(10 + this.defense / 10); + this.hp = Math.round(this.max_hp * ratio); +} + +export function resetMultipliers() { + this.hacking_chance_mult = 1; + this.hacking_speed_mult = 1; + this.hacking_money_mult = 1; + this.hacking_grow_mult = 1; + + this.hacking_mult = 1; + this.strength_mult = 1; + this.defense_mult = 1; + this.dexterity_mult = 1; + this.agility_mult = 1; + this.charisma_mult = 1; + + this.hacking_exp_mult = 1; + this.strength_exp_mult = 1; + this.defense_exp_mult = 1; + this.dexterity_exp_mult = 1; + this.agility_exp_mult = 1; + this.charisma_exp_mult = 1; + + this.company_rep_mult = 1; + this.faction_rep_mult = 1; + + this.crime_money_mult = 1; + this.crime_success_mult = 1; + + this.hacknet_node_money_mult = 1; + this.hacknet_node_purchase_cost_mult = 1; + this.hacknet_node_ram_cost_mult = 1; + this.hacknet_node_core_cost_mult = 1; + this.hacknet_node_level_cost_mult = 1; + + this.work_money_mult = 1; + + this.bladeburner_max_stamina_mult = 1; + this.bladeburner_stamina_gain_mult = 1; + this.bladeburner_analysis_mult = 1; + this.bladeburner_success_chance_mult = 1; +} + +export function hasProgram(programName) { + const home = this.getHomeComputer(); + if (home == null) { return false; } + + for (var i = 0; i < home.programs.length; ++i) { + if (programName.toLowerCase() == home.programs[i].toLowerCase()) {return true;} + } + return false; +} + +export function setMoney(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.setMoney()"); return; + } + this.money = money; +} + +export function gainMoney(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.gainMoney()"); return; + } + this.money = this.money.plus(money); +} + +export function loseMoney(money) { + if (isNaN(money)) { + console.log("ERR: NaN passed into Player.loseMoney()"); return; + } + this.money = this.money.minus(money); +} + +export function canAfford(cost) { + if (isNaN(cost)) { + console.error(`NaN passed into Player.canAfford()`); + return false; + } + return this.money.gte(cost); +} + +export function recordMoneySource(amt, source) { + if (!(this.moneySourceA instanceof MoneySourceTracker)) { + console.warn(`Player.moneySourceA was not properly initialized. Resetting`); + this.moneySourceA = new MoneySourceTracker(); + } + if (!(this.moneySourceB instanceof MoneySourceTracker)) { + console.warn(`Player.moneySourceB was not properly initialized. Resetting`); + this.moneySourceB = new MoneySourceTracker(); + } + this.moneySourceA.record(amt, source); + this.moneySourceB.record(amt, source); +} + +export function gainHackingExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainHackingExp()"); return; + } + this.hacking_exp += exp; + if(this.hacking_exp < 0) { + this.hacking_exp = 0; + } +} + +export function gainStrengthExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainStrengthExp()"); return; + } + this.strength_exp += exp; + if(this.strength_exp < 0) { + this.strength_exp = 0; + } +} + +export function gainDefenseExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into player.gainDefenseExp()"); return; + } + this.defense_exp += exp; + if(this.defense_exp < 0) { + this.defense_exp = 0; + } +} + +export function gainDexterityExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainDexterityExp()"); return; + } + this.dexterity_exp += exp; + if(this.dexterity_exp < 0) { + this.dexterity_exp = 0; + } +} + +export function gainAgilityExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainAgilityExp()"); return; + } + this.agility_exp += exp; + if(this.agility_exp < 0) { + this.agility_exp = 0; + } +} + +export function gainCharismaExp(exp) { + if (isNaN(exp)) { + console.log("ERR: NaN passed into Player.gainCharismaExp()"); return; + } + this.charisma_exp += exp; + if(this.charisma_exp < 0) { + this.charisma_exp = 0; + } +} + +export function gainIntelligenceExp(exp) { + if (isNaN(exp)) { + console.log("ERROR: NaN passed into Player.gainIntelligenceExp()"); return; + } + if (hasAISF || this.intelligence > 0) { + this.intelligence_exp += exp; + } +} + +//Given a string expression like "str" or "strength", returns the given stat +export function queryStatFromString(str) { + const tempStr = str.toLowerCase(); + if (tempStr.includes("hack")) { return this.hacking_skill; } + if (tempStr.includes("str")) { return this.strength; } + if (tempStr.includes("def")) { return this.defense; } + if (tempStr.includes("dex")) { return this.dexterity; } + if (tempStr.includes("agi")) { return this.agility; } + if (tempStr.includes("cha")) { return this.charisma; } + if (tempStr.includes("int")) { return this.intelligence; } +} + +/******* Working functions *******/ +export function resetWorkStatus() { + this.workHackExpGainRate = 0; + this.workStrExpGainRate = 0; + this.workDefExpGainRate = 0; + this.workDexExpGainRate = 0; + this.workAgiExpGainRate = 0; + this.workChaExpGainRate = 0; + this.workRepGainRate = 0; + this.workMoneyGainRate = 0; + this.workMoneyLossRate = 0; + + this.workHackExpGained = 0; + this.workStrExpGained = 0; + this.workDefExpGained = 0; + this.workDexExpGained = 0; + this.workAgiExpGained = 0; + this.workChaExpGained = 0; + this.workRepGained = 0; + this.workMoneyGained = 0; + + this.timeWorked = 0; + this.timeWorkedCreateProgram = 0; + + this.currentWorkFactionName = ""; + this.currentWorkFactionDescription = ""; + this.createProgramName = ""; + this.className = ""; + + document.getElementById("work-in-progress-text").innerHTML = ""; +} + +export function processWorkEarnings(numCycles=1) { + const hackExpGain = this.workHackExpGainRate * numCycles; + const strExpGain = this.workStrExpGainRate * numCycles; + const defExpGain = this.workDefExpGainRate * numCycles; + const dexExpGain = this.workDexExpGainRate * numCycles; + const agiExpGain = this.workAgiExpGainRate * numCycles; + const chaExpGain = this.workChaExpGainRate * numCycles; + const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles; + + this.gainHackingExp(hackExpGain); + this.gainStrengthExp(strExpGain); + this.gainDefenseExp(defExpGain); + this.gainDexterityExp(dexExpGain); + this.gainAgilityExp(agiExpGain); + this.gainCharismaExp(chaExpGain); + this.gainMoney(moneyGain); + this.recordMoneySource(moneyGain, "work"); + this.workHackExpGained += hackExpGain; + this.workStrExpGained += strExpGain; + this.workDefExpGained += defExpGain; + this.workDexExpGained += dexExpGain; + this.workAgiExpGained += agiExpGain; + this.workChaExpGained += chaExpGain; + this.workRepGained += this.workRepGainRate * numCycles; + this.workMoneyGained += this.workMoneyGainRate * numCycles; + this.workMoneyGained -= this.workMoneyLossRate * numCycles; +} + +/* Working for Company */ +export function startWork(companyName) { + this.resetWorkStatus(); + this.isWorking = true; + this.companyName = companyName; + this.workType = CONSTANTS.WorkTypeCompany; + + this.workHackExpGainRate = this.getWorkHackExpGain(); + this.workStrExpGainRate = this.getWorkStrExpGain(); + this.workDefExpGainRate = this.getWorkDefExpGain(); + this.workDexExpGainRate = this.getWorkDexExpGain(); + this.workAgiExpGainRate = this.getWorkAgiExpGain(); + this.workChaExpGainRate = this.getWorkChaExpGain(); + this.workRepGainRate = this.getWorkRepGain(); + this.workMoneyGainRate = this.getWorkMoneyGain(); + + this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; + + //Remove all old event listeners from Cancel button + var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); + newCancelButton.innerHTML = "Cancel Work"; + newCancelButton.addEventListener("click", () => { + this.finishWork(true); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function work(numCycles) { + //Cap the number of cycles being processed to whatever would put you at + //the work time limit (8 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); + } + this.timeWorked += Engine._idleSpeed * numCycles; + + this.workRepGainRate = this.getWorkRepGain(); + this.processWorkEarnings(numCycles); + + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { + return this.finishWork(false); + } + + var comp = Companies[this.companyName], companyRep = "0"; + if (comp == null || !(comp instanceof Company)) { + console.error(`Could not find Company: ${this.companyName}`); + } else { + companyRep = comp.playerReputation; + } + + const position = this.jobs[this.companyName]; + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working as a " + position + + " at " + this.companyName + " (Current Company Reputation: " + + numeralWrapper.format(companyRep, '0,0') + ")

    " + + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "You have earned:

    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company

    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + + "but you will only gain half of the reputation you've earned so far." +} + +export function finishWork(cancelled, sing=false) { + //Since the work was cancelled early, player only gains half of what they've earned so far + if (cancelled) { + this.workRepGained /= 2; + } + + var company = Companies[this.companyName]; + company.playerReputation += (this.workRepGained); + + this.updateSkillLevels(); + + var txt = "You earned a total of:
    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; + + if (cancelled) { + txt = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "Since you cancelled your work early, you only gained half of the reputation you earned.

    " + txt; + } else { + txt = "You worked a full shift of 8 hours!

    " + txt; + } + if (!sing) {dialogBoxCreate(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + Engine.loadLocationContent(false); + + if (sing) { + var res = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + + "earned $" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp."; + this.resetWorkStatus(); + return res; + } + this.resetWorkStatus(); +} + +export function startWorkPartTime(companyName) { + this.resetWorkStatus(); + this.isWorking = true; + this.companyName = companyName; + this.workType = CONSTANTS.WorkTypeCompanyPartTime; + + this.workHackExpGainRate = this.getWorkHackExpGain(); + this.workStrExpGainRate = this.getWorkStrExpGain(); + this.workDefExpGainRate = this.getWorkDefExpGain(); + this.workDexExpGainRate = this.getWorkDexExpGain(); + this.workAgiExpGainRate = this.getWorkAgiExpGain(); + this.workChaExpGainRate = this.getWorkChaExpGain(); + this.workRepGainRate = this.getWorkRepGain(); + this.workMoneyGainRate = this.getWorkMoneyGain(); + + this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; + + var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); + newCancelButton.innerHTML = "Stop Working"; + newCancelButton.addEventListener("click", () => { + this.finishWorkPartTime(); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function workPartTime(numCycles) { + //Cap the number of cycles being processed to whatever would put you at the + //work time limit (8 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); + } + this.timeWorked += Engine._idleSpeed * numCycles; + + this.workRepGainRate = this.getWorkRepGain(); + this.processWorkEarnings(numCycles); + + //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { + return this.finishWorkPartTime(); + } + + var comp = Companies[this.companyName], companyRep = "0"; + if (comp == null || !(comp instanceof Company)) { + console.log("ERROR: Could not find Company: " + this.companyName); + } else { + companyRep = comp.playerReputation; + } + + const position = this.jobs[this.companyName]; + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working as a " + position + + " at " + this.companyName + " (Current Company Reputation: " + + numeralWrapper.format(companyRep, '0,0') + ")

    " + + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "You have earned:

    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company

    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + + "You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
    " + + "and there will be no penalty because this is a part-time job."; + +} + +export function finishWorkPartTime(sing=false) { + var company = Companies[this.companyName]; + company.playerReputation += (this.workRepGained); + + this.updateSkillLevels(); + + var txt = "You earned a total of:
    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; + txt = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + txt; + if (!sing) {dialogBoxCreate(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + Engine.loadLocationContent(false); + if (sing) { + var res = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + + "earned a total of " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp"; + this.resetWorkStatus(); + return res; + } + this.resetWorkStatus(); +} + +/* Working for Faction */ +export function startFactionWork(faction) { + //Update reputation gain rate to account for faction favor + var favorMult = 1 + (faction.favor / 100); + if (isNaN(favorMult)) {favorMult = 1;} + this.workRepGainRate *= favorMult; + this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; + + this.isWorking = true; + this.workType = CONSTANTS.WorkTypeFaction; + this.currentWorkFactionName = faction.name; + + this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours; + + var cancelButton = clearEventListeners("work-in-progress-cancel-button"); + cancelButton.innerHTML = "Stop Faction Work"; + cancelButton.addEventListener("click", () => { + this.finishFactionWork(true); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function startFactionHackWork(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workRepGainRate = this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; + + this.factionWorkType = CONSTANTS.FactionWorkHacking; + this.currentWorkFactionDescription = "carrying out hacking contracts"; + + this.startFactionWork(faction); +} + +export function startFactionFieldWork(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workStrExpGainRate = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDefExpGainRate = .1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workRepGainRate = this.getFactionFieldWorkRepGain(); + + this.factionWorkType = CONSTANTS.FactionWorkField; + this.currentWorkFactionDescription = "carrying out field missions" + + this.startFactionWork(faction); +} + +export function startFactionSecurityWork(faction) { + this.resetWorkStatus(); + + this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDefExpGainRate = 0.15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; + this.workRepGainRate = this.getFactionSecurityWorkRepGain(); + + this.factionWorkType = CONSTANTS.FactionWorkSecurity; + this.currentWorkFactionDescription = "performing security detail" + + this.startFactionWork(faction); +} + +export function workForFaction(numCycles) { + var faction = Factions[this.currentWorkFactionName]; + + //Constantly update the rep gain rate + switch (this.factionWorkType) { + case CONSTANTS.FactionWorkHacking: + this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; + break; + case CONSTANTS.FactionWorkField: + this.workRepGainRate = this.getFactionFieldWorkRepGain(); + break; + case CONSTANTS.FactionWorkSecurity: + this.workRepGainRate = this.getFactionSecurityWorkRepGain(); + break; + default: + break; + } + + //Update reputation gain rate to account for faction favor + var favorMult = 1 + (faction.favor / 100); + if (isNaN(favorMult)) {favorMult = 1;} + this.workRepGainRate *= favorMult; + this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; + + //Cap the number of cycles being processed to whatever would put you at limit (20 hours) + var overMax = false; + if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) { + overMax = true; + numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / Engine._idleSpeed); + } + this.timeWorked += Engine._idleSpeed * numCycles; + + this.processWorkEarnings(numCycles); + + //If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours + if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) { + return this.finishFactionWork(false); + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently " + this.currentWorkFactionDescription + " for your faction " + faction.name + + " (Current Faction Reputation: " + numeralWrapper.format(faction.playerReputation, '0,0') + ").
    " + + "You have been doing this for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "You have earned:

    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " (" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this faction

    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + + + "You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
    " + + "There is no penalty for cancelling earlier."; +} + +export function finishFactionWork(cancelled, sing=false) { + var faction = Factions[this.currentWorkFactionName]; + faction.playerReputation += (this.workRepGained); + + this.updateSkillLevels(); + + var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "You earned a total of:
    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the faction
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; + if (!sing) {dialogBoxCreate(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + Engine.loadFactionContent(); + displayFactionContent(faction.name); + if (sing) { + var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + + "You earned " + + numeralWrapper.format(this.workRepGained, '0,0.0000') + " rep, " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, and " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."; + this.resetWorkStatus(); + return res; + } + this.resetWorkStatus(); +} + +//Money gained per game cycle +export function getWorkMoneyGain() { + // If player has SF-11, calculate salary multiplier from favor + let bn11Mult = 1; + const company = Companies[this.companyName]; + if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); } + + // Get base salary + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (companyPosition == null) { + console.error(`Could not find CompanyPosition object for ${companyPositionName}. Work salary will be 0`); + return 0; + } + + return companyPosition.baseSalary * company.salaryMultiplier * this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney * bn11Mult; +} + +//Hack exp gained per game cycle +export function getWorkHackExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work hack exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.hackingExpGain * company.expMultiplier * this.hacking_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Str exp gained per game cycle +export function getWorkStrExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work str exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.strengthExpGain * company.expMultiplier * this.strength_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Def exp gained per game cycle +export function getWorkDefExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work def exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.defenseExpGain * company.expMultiplier * this.defense_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Dex exp gained per game cycle +export function getWorkDexExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work dex exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.dexterityExpGain * company.expMultiplier * this.dexterity_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Agi exp gained per game cycle +export function getWorkAgiExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work agi exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.agilityExpGain * company.expMultiplier * this.agility_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Charisma exp gained per game cycle +export function getWorkChaExpGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work cha exp gain will be 0`].join(" ")); + return 0; + } + + return companyPosition.charismaExpGain * company.expMultiplier * this.charisma_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; +} + +//Reputation gained per game cycle +export function getWorkRepGain() { + const company = Companies[this.companyName]; + const companyPositionName = this.jobs[this.companyName]; + const companyPosition = CompanyPositions[companyPositionName]; + if (company == null || companyPosition == null) { + console.error([`Could not find Company object for ${this.companyName}`, + `or CompanyPosition object for ${companyPositionName}.`, + `Work rep gain will be 0`].join(" ")); + return 0; + } + + var jobPerformance = companyPosition.calculateJobPerformance(this.hacking_skill, this.strength, + this.defense, this.dexterity, + this.agility, this.charisma); + + //Intelligence provides a flat bonus to job performance + jobPerformance += (this.intelligence / CONSTANTS.MaxSkillLevel); + + //Update reputation gain rate to account for company favor + var favorMult = 1 + (company.favor / 100); + if (isNaN(favorMult)) { favorMult = 1; } + return jobPerformance * this.company_rep_mult * favorMult; +} + +export function getFactionSecurityWorkRepGain() { + var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel + + this.strength / CONSTANTS.MaxSkillLevel + + this.defense / CONSTANTS.MaxSkillLevel + + this.dexterity / CONSTANTS.MaxSkillLevel + + this.agility / CONSTANTS.MaxSkillLevel) / 4.5; + return t * this.faction_rep_mult; +} + +export function getFactionFieldWorkRepGain() { + var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel + + this.strength / CONSTANTS.MaxSkillLevel + + this.defense / CONSTANTS.MaxSkillLevel + + this.dexterity / CONSTANTS.MaxSkillLevel + + this.agility / CONSTANTS.MaxSkillLevel + + this.charisma / CONSTANTS.MaxSkillLevel + + this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5; + return t * this.faction_rep_mult; +} + +/* Creating a Program */ +export function startCreateProgramWork(programName, time, reqLevel) { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = CONSTANTS.WorkTypeCreateProgram; + + //Time needed to complete work affected by hacking skill (linearly based on + //ratio of (your skill - required level) to MAX skill) + //var timeMultiplier = (CONSTANTS.MaxSkillLevel - (this.hacking_skill - reqLevel)) / CONSTANTS.MaxSkillLevel; + //if (timeMultiplier > 1) {timeMultiplier = 1;} + //if (timeMultiplier < 0.01) {timeMultiplier = 0.01;} + this.createProgramReqLvl = reqLevel; + + this.timeNeededToCompleteWork = time; + //Check for incomplete program + for (var i = 0; i < this.getHomeComputer().programs.length; ++i) { + var programFile = this.getHomeComputer().programs[i]; + if (programFile.startsWith(programName) && programFile.endsWith("%-INC")) { + var res = programFile.split("-"); + if (res.length != 3) {break;} + var percComplete = Number(res[1].slice(0, -1)); + if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {break;} + this.timeWorkedCreateProgram = percComplete / 100 * this.timeNeededToCompleteWork; + this.getHomeComputer().programs.splice(i, 1); + } + } + + this.createProgramName = programName; + + var cancelButton = clearEventListeners("work-in-progress-cancel-button"); + cancelButton.innerHTML = "Cancel work on creating program"; + cancelButton.addEventListener("click", () => { + this.finishCreateProgramWork(true); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function createProgramWork(numCycles) { + //Higher hacking skill will allow you to create programs faster + var reqLvl = this.createProgramReqLvl; + var skillMult = (this.hacking_skill / reqLvl); //This should always be greater than 1; + skillMult = 1 + ((skillMult - 1) / 5); //The divider constant can be adjusted as necessary + + //Skill multiplier directly applied to "time worked" + this.timeWorked += (Engine._idleSpeed * numCycles); + this.timeWorkedCreateProgram += (Engine._idleSpeed * numCycles * skillMult); + var programName = this.createProgramName; + + if (this.timeWorkedCreateProgram >= this.timeNeededToCompleteWork) { + this.finishCreateProgramWork(false); + } + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are currently working on coding " + programName + ".

    " + + "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "The program is " + (this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 100).toFixed(2) + "% complete.
    " + + "If you cancel, your work will be saved and you can come back to complete the program later."; +} + +export function finishCreateProgramWork(cancelled, sing=false) { + var programName = this.createProgramName; + if (cancelled === false) { + dialogBoxCreate("You've finished creating " + programName + "!
    " + + "The new program can be found on your home computer."); + + this.getHomeComputer().programs.push(programName); + } else { + var perc = (Math.floor(this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 10000)/100).toString(); + var incompleteName = programName + "-" + perc + "%-INC"; + this.getHomeComputer().programs.push(incompleteName); + } + + if (!cancelled) { + this.gainIntelligenceExp(this.createProgramReqLvl / CONSTANTS.IntelligenceProgramBaseExpGain); + } + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + Engine.loadTerminalContent(); + this.resetWorkStatus(); +} + +/* Studying/Taking Classes */ +export function startClass(costMult, expMult, className) { + this.resetWorkStatus(); + this.isWorking = true; + this.workType = CONSTANTS.WorkTypeStudyClass; + + this.className = className; + + var gameCPS = 1000 / Engine._idleSpeed; + + //Base exp gains per second + var baseStudyComputerScienceExp = 0.5; + var baseDataStructuresExp = 1; + var baseNetworksExp = 2; + var baseAlgorithmsExp = 4; + var baseManagementExp = 2; + var baseLeadershipExp = 4; + var baseGymExp = 1; + + //Find cost and exp gain per game cycle + var cost = 0; + var hackExp = 0, strExp = 0, defExp = 0, dexExp = 0, agiExp = 0, chaExp = 0; + const hashManager = this.hashManager; + switch (className) { + case CONSTANTS.ClassStudyComputerScience: + hackExp = baseStudyComputerScienceExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassDataStructures: + cost = CONSTANTS.ClassDataStructuresBaseCost * costMult / gameCPS; + hackExp = baseDataStructuresExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassNetworks: + cost = CONSTANTS.ClassNetworksBaseCost * costMult / gameCPS; + hackExp = baseNetworksExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassAlgorithms: + cost = CONSTANTS.ClassAlgorithmsBaseCost * costMult / gameCPS; + hackExp = baseAlgorithmsExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassManagement: + cost = CONSTANTS.ClassManagementBaseCost * costMult / gameCPS; + chaExp = baseManagementExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassLeadership: + cost = CONSTANTS.ClassLeadershipBaseCost * costMult / gameCPS; + chaExp = baseLeadershipExp * expMult / gameCPS * hashManager.getStudyMult(); + break; + case CONSTANTS.ClassGymStrength: + cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; + strExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); + break; + case CONSTANTS.ClassGymDefense: + cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; + defExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); + break; + case CONSTANTS.ClassGymDexterity: + cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; + dexExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); + break; + case CONSTANTS.ClassGymAgility: + cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; + agiExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); + break; + default: + throw new Error("ERR: Invalid/unrecognized class name"); + return; + } + + this.workMoneyLossRate = cost; + this.workHackExpGainRate = hackExp * this.hacking_exp_mult * BitNodeMultipliers.ClassGymExpGain; + this.workStrExpGainRate = strExp * this.strength_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workDefExpGainRate = defExp * this.defense_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workDexExpGainRate = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workAgiExpGainRate = agiExp * this.agility_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + this.workChaExpGainRate = chaExp * this.charisma_exp_mult * BitNodeMultipliers.ClassGymExpGain;; + + var cancelButton = clearEventListeners("work-in-progress-cancel-button"); + if (className == CONSTANTS.ClassGymStrength || + className == CONSTANTS.ClassGymDefense || + className == CONSTANTS.ClassGymDexterity || + className == CONSTANTS.ClassGymAgility) { + cancelButton.innerHTML = "Stop training at gym"; + } else { + cancelButton.innerHTML = "Stop taking course"; + } + cancelButton.addEventListener("click", () => { + this.finishClass(); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function takeClass(numCycles) { + this.timeWorked += Engine._idleSpeed * numCycles; + var className = this.className; + + this.processWorkEarnings(numCycles); + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You have been " + className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + + "This has cost you:
    " + + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyLossRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + + "You have gained:
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp
    " + + "You may cancel at any time"; +} + +//The 'sing' argument defines whether or not this function was called +//through a Singularity Netscript function +export function finishClass(sing=false) { + this.gainIntelligenceExp(CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.timeWorked / 1000)); + + if (this.workMoneyGained > 0) { + throw new Error("ERR: Somehow gained money while taking class"); + } + + this.updateSkillLevels(); + var txt = "After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ",
    " + + "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ".

    " + + "You earned a total of:
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; + if (!sing) {dialogBoxCreate(txt);} + + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + + this.isWorking = false; + + Engine.loadLocationContent(false); + if (sing) { + var res="After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", " + + "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ". " + + "You earned a total of: " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp"; + this.resetWorkStatus(); + return res; + } + this.resetWorkStatus(); +} + +//The EXP and $ gains are hardcoded. Time is in ms +export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) { + this.crimeType = crimeType; + + this.resetWorkStatus(); + this.isWorking = true; + this.workType = CONSTANTS.WorkTypeCrime; + + if (singParams && singParams.workerscript) { + this.committingCrimeThruSingFn = true; + this.singFnCrimeWorkerScript = singParams.workerscript; + } + + this.workHackExpGained = hackExp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workStrExpGained = strExp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workDefExpGained = defExp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workDexExpGained = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workAgiExpGained = agiExp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workChaExpGained = chaExp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain; + this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney; + + this.timeNeededToCompleteWork = time; + + //Remove all old event listeners from Cancel button + var newCancelButton = clearEventListeners("work-in-progress-cancel-button") + newCancelButton.innerHTML = "Cancel crime" + newCancelButton.addEventListener("click", () => { + this.finishCrime(true); + return false; + }); + + //Display Work In Progress Screen + Engine.loadWorkInProgressContent(); +} + +export function commitCrime(numCycles) { + this.timeWorked += Engine._idleSpeed * numCycles; + + if (this.timeWorked >= this.timeNeededToCompleteWork) {this.finishCrime(false); return;} + + var percent = Math.round(this.timeWorked / this.timeNeededToCompleteWork * 100); + var numBars = Math.round(percent / 5); + if (numBars < 0) {numBars = 0;} + if (numBars > 20) {numBars = 20;} + var progressBar = "[" + Array(numBars+1).join("|") + Array(20 - numBars + 1).join(" ") + "]"; + + var txt = document.getElementById("work-in-progress-text"); + txt.innerHTML = "You are attempting to " + this.crimeType + ".
    " + + "Time remaining: " + convertTimeMsToTimeElapsedString(this.timeNeededToCompleteWork - this.timeWorked) + "
    " + + progressBar.replace( / /g, " " ); +} + +export function finishCrime(cancelled) { + //Determine crime success/failure + if (!cancelled) { + var statusText = ""; // TODO, unique message for each crime when you succeed + if (determineCrimeSuccess(this, this.crimeType)) { + //Handle Karma and crime statistics + let crime = null; + for(const i in Crimes) { + if(Crimes[i].type == this.crimeType) { + crime = Crimes[i]; + break; + } + } + if(crime == null) { + console.log(this.crimeType); + dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer"); + } + this.gainMoney(this.workMoneyGained); + this.recordMoneySource(this.workMoneyGained, "crime"); + this.karma -= crime.karma; + this.numPeopleKilled += crime.kills; + if(crime.intelligence_exp > 0) { + this.gainIntelligenceExp(crime.intelligence_exp); + } + + //On a crime success, gain 2x exp + this.workHackExpGained *= 2; + this.workStrExpGained *= 2; + this.workDefExpGained *= 2; + this.workDexExpGained *= 2; + this.workAgiExpGained *= 2; + this.workChaExpGained *= 2; + if (this.committingCrimeThruSingFn) { + if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { + this.singFnCrimeWorkerScript.scriptRef.log("Crime successful! Gained " + + numeralWrapper.format(this.workMoneyGained, "$0.000a") + ", " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."); + } + } else { + dialogBoxCreate("Crime successful!

    " + + "You gained:
    "+ + "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience"); + } + + } else { + //Exp halved on failure + this.workHackExpGained /= 2; + this.workStrExpGained /= 2; + this.workDefExpGained /= 2; + this.workDexExpGained /= 2; + this.workAgiExpGained /= 2; + this.workChaExpGained /= 2; + if (this.committingCrimeThruSingFn) { + if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { + this.singFnCrimeWorkerScript.scriptRef.log("Crime failed! Gained " + + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."); + } + } else { + dialogBoxCreate("Crime failed!

    " + + "You gained:
    "+ + numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience
    " + + numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience
    " + + numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience
    " + + numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience
    " + + numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience
    " + + numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience"); + } + } + + this.gainHackingExp(this.workHackExpGained); + this.gainStrengthExp(this.workStrExpGained); + this.gainDefenseExp(this.workDefExpGained); + this.gainDexterityExp(this.workDexExpGained); + this.gainAgilityExp(this.workAgiExpGained); + this.gainCharismaExp(this.workChaExpGained); + } + this.committingCrimeThruSingFn = false; + this.singFnCrimeWorkerScript = null; + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + this.isWorking = false; + this.resetWorkStatus(); + Engine.loadLocationContent(false); +} + +//Cancels the player's current "work" assignment and gives the proper rewards +//Used only for Singularity functions, so no popups are created +export function singularityStopWork() { + if (!this.isWorking) {return "";} + var res; //Earnings text for work + switch (this.workType) { + case CONSTANTS.WorkTypeStudyClass: + res = this.finishClass(true); + break; + case CONSTANTS.WorkTypeCompany: + res = this.finishWork(true, true); + break; + case CONSTANTS.WorkTypeCompanyPartTime: + res = this.finishWorkPartTime(true); + break; + case CONSTANTS.WorkTypeFaction: + res = this.finishFactionWork(true, true); + break; + case CONSTANTS.WorkTypeCreateProgram: + res = this.finishCreateProgramWork(true, true); + break; + case CONSTANTS.WorkTypeCrime: + res = this.finishCrime(true); + break; + default: + console.log("ERROR: Unrecognized work type"); + return ""; + } + return res; +} + + +// Returns true if hospitalized, false otherwise +export function takeDamage(amt) { + if (typeof amt !== "number") { + console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`); + return; + } + + this.hp -= amt; + if (this.hp <= 0) { + this.hospitalize(); + return true; + } else { + return false; + } +} + +export function regenerateHp(amt) { + if (typeof amt !== "number") { + console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`); + return; + } + this.hp += amt; + if (this.hp > this.max_hp) { this.hp = this.max_hp; } +} + +export function hospitalize() { + if (Settings.SuppressHospitalizationPopup === false) { + dialogBoxCreate( + "You were in critical condition! You were taken to the hospital where " + + "luckily they were able to save your life. You were charged " + + numeralWrapper.format(this.max_hp * CONSTANTS.HospitalCostPerHp, '$0.000a') + ); + } + + this.loseMoney(this.max_hp * CONSTANTS.HospitalCostPerHp); + this.hp = this.max_hp; +} + +/********* Company job application **********/ +//Determines the job that the Player should get (if any) at the current company +//The 'sing' argument designates whether or not this is being called from +//the applyToCompany() Netscript Singularity function +export function applyForJob(entryPosType, sing=false) { + // Get current company and job + let currCompany = null; + if (this.companyName !== "") { + currCompany = Companies[this.companyName]; + } + const currPositionName = this.jobs[this.companyName]; + + // Get company that's being applied to + const company = Companies[this.location]; //Company being applied to + if (!(company instanceof Company)) { + if (sing) { + return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed"; + } else { + console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`); + return; + } + } + + let pos = entryPosType; + + if (!this.isQualified(company, pos)) { + var reqText = getJobRequirementText(company, pos); + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position
    " + reqText); + return; + } + + while (true) { + let newPos = getNextCompanyPositionHelper(pos); + if (newPos == null) {break;} + + //Check if this company has this position + if (company.hasPosition(newPos)) { + if (!this.isQualified(company, newPos)) { + //If player not qualified for next job, break loop so player will be given current job + break; + } + pos = newPos; + } else { + break; + } + } + + //Check if the determined job is the same as the player's current job + if (currCompany != null) { + if (currCompany.name == company.name && pos.name == currPositionName) { + var nextPos = getNextCompanyPositionHelper(pos); + if (nextPos == null) { + if (sing) {return false;} + dialogBoxCreate("You are already at the highest position for your field! No promotion available"); + } else if (company.hasPosition(nextPos)) { + if (sing) {return false;} + var reqText = getJobRequirementText(company, nextPos); + dialogBoxCreate("Unfortunately, you do not qualify for a promotion
    " + reqText); + } else { + if (sing) {return false;} + dialogBoxCreate("You are already at the highest position for your field! No promotion available"); + } + return; //Same job, do nothing + } + } + + this.companyName = company.name; + this.jobs[company.name] = pos.name; + + document.getElementById("world-menu-header").click(); + document.getElementById("world-menu-header").click(); + + if (sing) { return true; } + dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!"); + + Engine.loadLocationContent(false); +} + +//Returns your next position at a company given the field (software, business, etc.) +export function getNextCompanyPosition(company, entryPosType) { + var currCompany = null; + if (this.companyName !== "") { + currCompany = Companies[this.companyName]; + } + + //Not employed at this company, so return the entry position + if (currCompany == null || (currCompany.name != company.name)) { + return entryPosType; + } + + //If the entry pos type and the player's current position have the same type, + //return the player's "nextCompanyPosition". Otherwise return the entryposType + //Employed at this company, so just return the next position if it exists. + const currentPositionName = this.jobs[this.companyName]; + const currentPosition = CompanyPositions[currentPositionName]; + if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || + (currentPosition.isITJob() && entryPosType.isITJob()) || + (currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) || + (currentPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || + (currentPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || + (currentPosition.isSecurityJob() && entryPosType.isSecurityJob()) || + (currentPosition.isAgentJob() && entryPosType.isAgentJob()) || + (currentPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || + (currentPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || + (currentPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) { + return getNextCompanyPositionHelper(currentPosition); + } + + return entryPosType; +} + +export function applyForSoftwareJob(sing=false) { + return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing); +} + +export function applyForSoftwareConsultantJob(sing=false) { + return this.applyForJob(CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], sing); +} + +export function applyForItJob(sing=false) { + return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing); +} + +export function applyForSecurityEngineerJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) { + return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForNetworkEngineerJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) { + return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForBusinessJob(sing=false) { + return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing); +} + +export function applyForBusinessConsultantJob(sing=false) { + return this.applyForJob(CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], sing); +} + +export function applyForSecurityJob(sing=false) { + // TODO Police Jobs + // Indexing starts at 2 because 0 is for police officer + return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing); +} + +export function applyForAgentJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) { + return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForEmployeeJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) { + this.companyName = company.name; + this.jobs[company.name] = posNames.MiscCompanyPositions[1]; + document.getElementById("world-menu-header").click(); + document.getElementById("world-menu-header").click(); + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); + Engine.loadLocationContent(false); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForPartTimeEmployeeJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) { + this.companyName = company.name; + this.jobs[company.name] = posNames.PartTimeCompanyPositions[1]; + document.getElementById("world-menu-header").click(); + document.getElementById("world-menu-header").click(); + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); + Engine.loadLocationContent(false); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForWaiterJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) { + this.companyName = company.name; + this.jobs[company.name] = posNames.MiscCompanyPositions[0]; + document.getElementById("world-menu-header").click(); + document.getElementById("world-menu-header").click(); + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); + Engine.loadLocationContent(false); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +export function applyForPartTimeWaiterJob(sing=false) { + var company = Companies[this.location]; //Company being applied to + if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) { + this.companyName = company.name; + this.jobs[company.name] = posNames.PartTimeCompanyPositions[0]; + document.getElementById("world-menu-header").click(); + document.getElementById("world-menu-header").click(); + if (sing) {return true;} + dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); + Engine.loadLocationContent(false); + } else { + if (sing) {return false;} + dialogBoxCreate("Unforunately, you do not qualify for this position"); + } +} + +//Checks if the Player is qualified for a certain position +export function isQualified(company, position) { + var offset = company.jobStatReqOffset; + var reqHacking = position.requiredHacking > 0 ? position.requiredHacking+offset : 0; + var reqStrength = position.requiredStrength > 0 ? position.requiredStrength+offset : 0; + var reqDefense = position.requiredDefense > 0 ? position.requiredDefense+offset : 0; + var reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; + var reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma+offset : 0; + + if (this.hacking_skill >= reqHacking && + this.strength >= reqStrength && + this.defense >= reqDefense && + this.dexterity >= reqDexterity && + this.agility >= reqAgility && + this.charisma >= reqCharisma && + company.playerReputation >= position.requiredReputation) { + return true; + } + return false; +} + +/********** Reapplying Augmentations and Source File ***********/ +export function reapplyAllAugmentations(resetMultipliers=true) { + console.log("Re-applying augmentations"); + if (resetMultipliers) { + this.resetMultipliers(); + } + + for (let i = 0; i < this.augmentations.length; ++i) { + //Compatibility with new version + if (this.augmentations[i].name === "HacknetNode NIC Architecture Neural-Upload") { + this.augmentations[i].name = "Hacknet Node NIC Architecture Neural-Upload"; + } + + const augName = this.augmentations[i].name; + var aug = Augmentations[augName]; + if (aug == null) { + console.log(`WARNING: Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`); + continue; + } + aug.owned = true; + if (aug.name == AugmentationNames.NeuroFluxGovernor) { + for (let j = 0; j < aug.level; ++j) { + applyAugmentation(this.augmentations[i], true); + } + continue; + } + applyAugmentation(this.augmentations[i], true); + } +} + +export function reapplyAllSourceFiles() { + console.log("Re-applying source files"); + //Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset + //this.resetMultipliers(); + + for (let i = 0; i < this.sourceFiles.length; ++i) { + var srcFileKey = "SourceFile" + this.sourceFiles[i].n; + var sourceFileObject = SourceFiles[srcFileKey]; + if (sourceFileObject == null) { + console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); + continue; + } + applySourceFile(this.sourceFiles[i]); + } +} + +/*************** Check for Faction Invitations *************/ +//This function sets the requirements to join a Faction. It checks whether the Player meets +//those requirements and will return an array of all factions that the Player should +//receive an invitation to +export function checkForFactionInvitations() { + let invitedFactions = []; //Array which will hold all Factions the player should be invited to + + var numAugmentations = this.augmentations.length; + + const allCompanies = Object.keys(this.jobs); + const allPositions = Object.values(this.jobs); + + // Given a company name, safely returns the reputation (returns 0 if invalid company is specified) + function getCompanyRep(companyName) { + const company = Companies[companyName]; + if (company == null) { + return 0; + } else { + return company.playerReputation; + } + } + + // Helper function that returns a boolean indicating whether the Player meets + // the requirements for the specified company. There are two requirements: + // 1. High enough reputation + // 2. Player is employed at the company + function checkMegacorpRequirements(companyName, repNeeded=CONSTANTS.CorpFactionRepRequirement) { + return allCompanies.includes(companyName) && (getCompanyRep(companyName) > repNeeded); + } + + //Illuminati + var illuminatiFac = Factions["Illuminati"]; + if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited && + numAugmentations >= 30 && + this.money.gte(150000000000) && + this.hacking_skill >= 1500 && + this.strength >= 1200 && this.defense >= 1200 && + this.dexterity >= 1200 && this.agility >= 1200) { + invitedFactions.push(illuminatiFac); + } + + //Daedalus + var daedalusFac = Factions["Daedalus"]; + if (!daedalusFac.isBanned && !daedalusFac.isMember && !daedalusFac.alreadyInvited && + numAugmentations >= Math.round(30 * BitNodeMultipliers.DaedalusAugsRequirement) && + this.money.gte(100000000000) && + (this.hacking_skill >= 2500 || + (this.strength >= 1500 && this.defense >= 1500 && + this.dexterity >= 1500 && this.agility >= 1500))) { + invitedFactions.push(daedalusFac); + } + + //The Covenant + var covenantFac = Factions["The Covenant"]; + if (!covenantFac.isBanned && !covenantFac.isMember && !covenantFac.alreadyInvited && + numAugmentations >= 20 && + this.money.gte(75000000000) && + this.hacking_skill >= 850 && + this.strength >= 850 && + this.defense >= 850 && + this.dexterity >= 850 && + this.agility >= 850) { + invitedFactions.push(covenantFac); + } + + //ECorp + var ecorpFac = Factions["ECorp"]; + if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && + checkMegacorpRequirements(LocationName.AevumECorp)) { + invitedFactions.push(ecorpFac); + } + + //MegaCorp + var megacorpFac = Factions["MegaCorp"]; + if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && + checkMegacorpRequirements(LocationName.Sector12MegaCorp)) { + invitedFactions.push(megacorpFac); + } + + //Bachman & Associates + var bachmanandassociatesFac = Factions["Bachman & Associates"]; + if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && + !bachmanandassociatesFac.alreadyInvited && + checkMegacorpRequirements(LocationName.AevumBachmanAndAssociates)) { + invitedFactions.push(bachmanandassociatesFac); + } + + //Blade Industries + var bladeindustriesFac = Factions["Blade Industries"]; + if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && + checkMegacorpRequirements(LocationName.Sector12BladeIndustries)) { + invitedFactions.push(bladeindustriesFac); + } + + //NWO + var nwoFac = Factions["NWO"]; + if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && + checkMegacorpRequirements(LocationName.VolhavenNWO)) { + invitedFactions.push(nwoFac); + } + + //Clarke Incorporated + var clarkeincorporatedFac = Factions["Clarke Incorporated"]; + if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && + checkMegacorpRequirements(LocationName.AevumClarkeIncorporated)) { + invitedFactions.push(clarkeincorporatedFac); + } + + //OmniTek Incorporated + var omnitekincorporatedFac = Factions["OmniTek Incorporated"]; + if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && + checkMegacorpRequirements(LocationName.VolhavenOmniTekIncorporated)) { + invitedFactions.push(omnitekincorporatedFac); + } + + //Four Sigma + var foursigmaFac = Factions["Four Sigma"]; + if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && + checkMegacorpRequirements(LocationName.Sector12FourSigma)) { + invitedFactions.push(foursigmaFac); + } + + //KuaiGong International + var kuaigonginternationalFac = Factions["KuaiGong International"]; + if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && + !kuaigonginternationalFac.alreadyInvited && + checkMegacorpRequirements(LocationName.ChongqingKuaiGongInternational)) { + invitedFactions.push(kuaigonginternationalFac); + } + + //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company + var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; + var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]]; + if (fulcrumSecretServer == null) { + console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); + } else { + if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && + !fulcrumsecrettechonologiesFac.alreadyInvited && + fulcrumSecretServer.manuallyHacked && + checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)) { + invitedFactions.push(fulcrumsecrettechonologiesFac); + } + } + + //BitRunners + var bitrunnersFac = Factions["BitRunners"]; + var homeComp = this.getHomeComputer(); + var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]]; + if (bitrunnersServer == null) { + console.log("ERROR: Could not find BitRunners Server"); + } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && + !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { + invitedFactions.push(bitrunnersFac); + } + + //The Black Hand + var theblackhandFac = Factions["The Black Hand"]; + var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]]; + if (blackhandServer == null) { + console.log("ERROR: Could not find The Black Hand Server"); + } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && + !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { + invitedFactions.push(theblackhandFac); + } + + //NiteSec + var nitesecFac = Factions["NiteSec"]; + var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]]; + if (nitesecServer == null) { + console.log("ERROR: Could not find NiteSec Server"); + } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && + !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { + invitedFactions.push(nitesecFac); + } + + //Chongqing + var chongqingFac = Factions["Chongqing"]; + if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && + this.money.gte(20000000) && this.city == CityName.Chongqing) { + invitedFactions.push(chongqingFac); + } + + //Sector-12 + var sector12Fac = Factions["Sector-12"]; + if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && + this.money.gte(15000000) && this.city == CityName.Sector12) { + invitedFactions.push(sector12Fac); + } + + //New Tokyo + var newtokyoFac = Factions["New Tokyo"]; + if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && + this.money.gte(20000000) && this.city == CityName.NewTokyo) { + invitedFactions.push(newtokyoFac); + } + + //Aevum + var aevumFac = Factions["Aevum"]; + if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && + this.money.gte(40000000) && this.city == CityName.Aevum) { + invitedFactions.push(aevumFac); + } + + //Ishima + var ishimaFac = Factions["Ishima"]; + if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && + this.money.gte(30000000) && this.city == CityName.Ishima) { + invitedFactions.push(ishimaFac); + } + + //Volhaven + var volhavenFac = Factions["Volhaven"]; + if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && + this.money.gte(50000000) && this.city == CityName.Volhaven) { + invitedFactions.push(volhavenFac); + } + + //Speakers for the Dead + var speakersforthedeadFac = Factions["Speakers for the Dead"]; + if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && + this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && + this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && + !allCompanies.includes(LocationName.Sector12NSA)) { + invitedFactions.push(speakersforthedeadFac); + } + + //The Dark Army + var thedarkarmyFac = Factions["The Dark Army"]; + if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && + this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && + this.dexterity >= 300 && this.agility >= 300 && this.city == CityName.Chongqing && + this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && + !allCompanies.includes(LocationName.Sector12NSA)) { + invitedFactions.push(thedarkarmyFac); + } + + //The Syndicate + var thesyndicateFac = Factions["The Syndicate"]; + if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && + this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && + this.dexterity >= 200 && this.agility >= 200 && + (this.city == CityName.Aevum || this.city == CityName.Sector12) && + this.money.gte(10000000) && this.karma <= -90 && + !allCompanies.includes(LocationName.Sector12CIA) && !allCompanies.includes(LocationName.Sector12NSA)) { + invitedFactions.push(thesyndicateFac); + } + + //Silhouette + var silhouetteFac = Factions["Silhouette"]; + if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited && + (allPositions.includes("Chief Technology Officer") || + allPositions.includes("Chief Financial Officer") || + allPositions.includes("Chief Executive Officer")) && + this.money.gte(15000000) && this.karma <= -22) { + invitedFactions.push(silhouetteFac); + } + + //Tetrads + var tetradsFac = Factions["Tetrads"]; + if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && + (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || + this.city == CityName.Ishima) && this.strength >= 75 && this.defense >= 75 && + this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { + invitedFactions.push(tetradsFac); + } + + //SlumSnakes + var slumsnakesFac = Factions["Slum Snakes"]; + if (!slumsnakesFac.isBanned && !slumsnakesFac.isMember && !slumsnakesFac.alreadyInvited && + this.strength >= 30 && this.defense >= 30 && this.dexterity >= 30 && + this.agility >= 30 && this.karma <= -9 && this.money.gte(1000000)) { + invitedFactions.push(slumsnakesFac); + } + + //Netburners + var netburnersFac = Factions["Netburners"]; + var totalHacknetRam = 0; + var totalHacknetCores = 0; + var totalHacknetLevels = 0; + for (let i = 0; i < this.hacknetNodes.length; ++i) { + if (hasHacknetServers()) { + const hserver = AllServers[this.hacknetNodes[i]]; + if (hserver) { + totalHacknetLevels += hserver.level; + totalHacknetRam += hserver.maxRam; + totalHacknetCores += hserver.cores; + } + } else { + totalHacknetLevels += this.hacknetNodes[i].level; + totalHacknetRam += this.hacknetNodes[i].ram; + totalHacknetCores += this.hacknetNodes[i].cores; + } + } + if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited && + this.hacking_skill >= 80 && totalHacknetRam >= 8 && + totalHacknetCores >= 4 && totalHacknetLevels >= 100) { + invitedFactions.push(netburnersFac); + } + + //Tian Di Hui + var tiandihuiFac = Factions["Tian Di Hui"]; + if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && + this.money.gte(1000000) && this.hacking_skill >= 50 && + (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || + this.city == CityName.Ishima)) { + invitedFactions.push(tiandihuiFac); + } + + //CyberSec + var cybersecFac = Factions["CyberSec"]; + var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]]; + if (cybersecServer == null) { + console.log("ERROR: Could not find CyberSec Server"); + } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && + !cybersecFac.alreadyInvited && this.hacking_skill >= 50) { + invitedFactions.push(cybersecFac); + } + + return invitedFactions; +} + + +/*************** Gang ****************/ +//Returns true if Player is in a gang and false otherwise +export function inGang() { + if (this.gang == null || this.gang == undefined) {return false;} + return (this.gang instanceof Gang); +} + +export function startGang(factionName, hacking) { + this.gang = new Gang(factionName, hacking); +} + +/************* BitNodes **************/ +export function setBitNodeNumber(n) { + this.bitNodeN = n; +} + +export function queueAugmentation(name) { + for(const i in this.queuedAugmentations) { + if(this.queuedAugmentations[i].name == name) { + console.log('tried to queue '+name+' twice, this may be a bug'); + return; + } + } + + for(const i in this.augmentations) { + if(this.augmentations[i].name == name) { + console.log('tried to queue '+name+' but we already have that aug'); + return; + } + } + + this.firstAugPurchased = true; + this.queuedAugmentations.push(new PlayerOwnedAugmentation(name)); +} + +/************* Coding Contracts **************/ +export function gainCodingContractReward(reward, difficulty=1) { + if (reward == null || reward.type == null || reward == null) { + return `No reward for this contract`; + } + + /* eslint-disable no-case-declarations */ + switch (reward.type) { + case CodingContractRewardType.FactionReputation: + if (reward.name == null || !(Factions[reward.name] instanceof Faction)) { + // If no/invalid faction was designated, just give rewards to all factions + reward.type = CodingContractRewardType.FactionReputationAll; + return this.gainCodingContractReward(reward); + } + var repGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty; + Factions[reward.name].playerReputation += repGain; + return `Gained ${repGain} faction reputation for ${reward.name}`; + case CodingContractRewardType.FactionReputationAll: + const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty; + + // Ignore Bladeburners and other special factions for this calculation + const specialFactions = ["Bladeburners"]; + var factions = this.factions.slice(); + factions = factions.filter((f) => { + return !specialFactions.includes(f); + }); + + // If the player was only part of the special factions, we'll just give money + if (factions.length == 0) { + reward.type = CodingContractRewardType.Money; + return this.gainCodingContractReward(reward, difficulty); + } + + const gainPerFaction = Math.floor(totalGain / factions.length); + for (const facName of factions) { + if (!(Factions[facName] instanceof Faction)) { continue; } + Factions[facName].playerReputation += gainPerFaction; + } + return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`; + break; + case CodingContractRewardType.CompanyReputation: + if (reward.name == null || !(Companies[reward.name] instanceof Company)) { + //If no/invalid company was designated, just give rewards to all factions + reward.type = CodingContractRewardType.FactionReputationAll; + return this.gainCodingContractReward(reward); + } + var repGain = CONSTANTS.CodingContractBaseCompanyRepGain * difficulty; + Companies[reward.name].playerReputation += repGain; + return `Gained ${repGain} company reputation for ${reward.name}`; + break; + case CodingContractRewardType.Money: + default: + var moneyGain = CONSTANTS.CodingContractBaseMoneyGain * difficulty * BitNodeMultipliers.CodingContractMoney; + this.gainMoney(moneyGain); + this.recordMoneySource(moneyGain, "codingcontract"); + return `Gained ${numeralWrapper.format(moneyGain, '$0.000a')}`; + break; + } + /* eslint-enable no-case-declarations */ +} + +export function travel(to) { + if (Cities[to] == null) { + console.warn(`Player.travel() called with invalid city: ${to}`); + return false; + } + this.city = to; + + return true; +} + +export function gotoLocation(to) { + if (Locations[to] == null) { + console.warn(`Player.gotoLocation() called with invalid location: ${to}`); + return false; + } + this.location = to; + + return true; +} + +export function canAccessResleeving() { + return this.bitNodeN === 10 || (SourceFileFlags[10] > 0); +} diff --git a/src/PersonObjects/Player/PlayerObjectServerMethods.ts b/src/PersonObjects/Player/PlayerObjectServerMethods.ts new file mode 100644 index 000000000..aced9460b --- /dev/null +++ b/src/PersonObjects/Player/PlayerObjectServerMethods.ts @@ -0,0 +1,30 @@ +import { IPlayer } from "../IPlayer"; + +import { CONSTANTS } from "../../Constants"; +import { AllServers } from "../../Server/AllServers"; +import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; +import { SpecialServerIps } from "../../Server/SpecialServerIps"; + +export function hasTorRouter(this: IPlayer) { + return SpecialServerIps.hasOwnProperty("Darkweb Server"); +} + +export function getCurrentServer(this: IPlayer) { + return AllServers[this.currentServer]; +} + +export function getHomeComputer(this: IPlayer) { + return AllServers[this.homeComputer]; +} + +export function getUpgradeHomeRamCost(this: IPlayer) { + //Calculate how many times ram has been upgraded (doubled) + const currentRam = this.getHomeComputer().maxRam; + const numUpgrades = Math.log2(currentRam); + + //Calculate cost + //Have cost increase by some percentage each time RAM has been upgraded + const mult = Math.pow(1.58, numUpgrades); + var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost; + return cost; +} diff --git a/src/Player.js b/src/Player.js index 65ab700ee..fe8140fdf 100644 --- a/src/Player.js +++ b/src/Player.js @@ -1,2542 +1,9 @@ -import { Augmentations } from "./Augmentation/Augmentations"; -import { applyAugmentation } from "./Augmentation/AugmentationHelpers"; -import { PlayerOwnedAugmentation } from "./Augmentation/PlayerOwnedAugmentation"; -import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; -import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers"; -import { Bladeburner } from "./Bladeburner"; -import { CodingContractRewardType } from "./CodingContracts"; -import { Company } from "./Company/Company"; -import { Companies } from "./Company/Companies"; -import { getNextCompanyPosition } from "./Company/GetNextCompanyPosition"; -import { getJobRequirementText } from "./Company/GetJobRequirementText"; -import { CompanyPositions } from "./Company/CompanyPositions"; -import * as posNames from "./Company/data/companypositionnames"; -import {CONSTANTS} from "./Constants"; -import { Corporation } from "./Corporation/Corporation"; -import { Programs } from "./Programs/Programs"; -import { determineCrimeSuccess } from "./Crime/CrimeHelpers"; -import { Crimes } from "./Crime/Crimes"; -import {Engine} from "./engine"; -import { Faction } from "./Faction/Faction"; -import { Factions } from "./Faction/Factions"; -import { displayFactionContent } from "./Faction/FactionHelpers"; -import {Gang, resetGangs} from "./Gang"; -import { hasHacknetServers } from "./Hacknet/HacknetHelpers"; -import { HashManager } from "./Hacknet/HashManager"; -import { Cities } from "./Locations/Cities"; -import { Locations } from "./Locations/Locations"; -import { CityName } from "./Locations/data/CityNames"; -import { LocationName } from "./Locations/data/LocationNames"; -import {hasBn11SF, hasWallStreetSF,hasAISF} from "./NetscriptFunctions"; -import { Sleeve } from "./PersonObjects/Sleeve/Sleeve"; -import { AllServers, - AddToAllServers } from "./Server/AllServers"; -import { Server } from "./Server/Server"; -import {Settings} from "./Settings/Settings"; -import {SpecialServerIps, SpecialServerNames} from "./Server/SpecialServerIps"; -import {SourceFiles, applySourceFile} from "./SourceFile"; -import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; +import { Corporation } from "./Corporation/Corporation"; +import { PlayerObject } from "./PersonObjects/Player/PlayerObject"; -import Decimal from "decimal.js"; +import { Reviver } from "../utils/JSONReviver"; -import {numeralWrapper} from "./ui/numeralFormat"; -import { MoneySourceTracker } from "./utils/MoneySourceTracker"; -import {dialogBoxCreate} from "./../utils/DialogBox"; -import {clearEventListeners} from "./../utils/uiHelpers/clearEventListeners"; -import {createRandomIp} from "./../utils/IPAddress"; -import {Reviver, Generic_toJSON, - Generic_fromJSON} from "../utils/JSONReviver"; -import {convertTimeMsToTimeElapsedString} from "../utils/StringHelperFunctions"; - -const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; - -function PlayerObject() { - //Skills and stats - this.hacking_skill = 1; - - //Combat stats - this.hp = 10; - this.max_hp = 10; - this.strength = 1; - this.defense = 1; - this.dexterity = 1; - this.agility = 1; - - //Labor stats - this.charisma = 1; - - //Special stats - this.intelligence = 0; - - //Hacking multipliers - this.hacking_chance_mult = 1; - this.hacking_speed_mult = 1; - this.hacking_money_mult = 1; - this.hacking_grow_mult = 1; - - //Experience and multipliers - this.hacking_exp = 0; - this.strength_exp = 0; - this.defense_exp = 0; - this.dexterity_exp = 0; - this.agility_exp = 0; - this.charisma_exp = 0; - this.intelligence_exp= 0; - - this.hacking_mult = 1; - this.strength_mult = 1; - this.defense_mult = 1; - this.dexterity_mult = 1; - this.agility_mult = 1; - this.charisma_mult = 1; - - this.hacking_exp_mult = 1; - this.strength_exp_mult = 1; - this.defense_exp_mult = 1; - this.dexterity_exp_mult = 1; - this.agility_exp_mult = 1; - this.charisma_exp_mult = 1; - - this.company_rep_mult = 1; - this.faction_rep_mult = 1; - - //Money - this.money = new Decimal(1000); - - //IP Address of Starting (home) computer - this.homeComputer = ""; - - //Location information - this.city = CityName.Sector12; - this.location = ""; - - // Jobs that the player holds - // Map of company name (key) -> name of company position (value. Just the name, not the CompanyPosition object) - // The CompanyPosition name must match a key value in CompanyPositions - this.jobs = {}; - - // Company at which player is CURRENTLY working (only valid when the player is actively working) - this.companyName = ""; // Name of Company. Must match a key value in Companies map - - // Servers - this.currentServer = ""; //IP address of Server currently being accessed through terminal - this.purchasedServers = []; //IP Addresses of purchased servers - - // Hacknet Nodes/Servers - this.hacknetNodes = []; // Note: For Hacknet Servers, this array holds the IP addresses of the servers - this.hashManager = new HashManager(); - - //Factions - this.factions = []; //Names of all factions player has joined - this.factionInvitations = []; //Outstanding faction invitations - - //Augmentations - this.queuedAugmentations = []; - this.augmentations = []; - - this.sourceFiles = []; - - //Crime statistics - this.numPeopleKilled = 0; - this.karma = 0; - - this.crime_money_mult = 1; - this.crime_success_mult = 1; - - //Flags/variables for working (Company, Faction, Creating Program, Taking Class) - this.isWorking = false; - this.workType = ""; - - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; - - this.workHackExpGainRate = 0; - this.workStrExpGainRate = 0; - this.workDefExpGainRate = 0; - this.workDexExpGainRate = 0; - this.workAgiExpGainRate = 0; - this.workChaExpGainRate = 0; - this.workRepGainRate = 0; - this.workMoneyGainRate = 0; - this.workMoneyLossRate = 0; - - this.workHackExpGained = 0; - this.workStrExpGained = 0; - this.workDefExpGained = 0; - this.workDexExpGained = 0; - this.workAgiExpGained = 0; - this.workChaExpGained = 0; - this.workRepGained = 0; - this.workMoneyGained = 0; - - this.createProgramName = ""; - this.createProgramReqLvl = 0; - - this.className = ""; - - this.crimeType = ""; - - this.timeWorked = 0; //in ms - this.timeWorkedCreateProgram = 0; - this.timeNeededToCompleteWork = 0; - - this.work_money_mult = 1; - - //Hacknet Node multipliers - this.hacknet_node_money_mult = 1; - this.hacknet_node_purchase_cost_mult = 1; - this.hacknet_node_ram_cost_mult = 1; - this.hacknet_node_core_cost_mult = 1; - this.hacknet_node_level_cost_mult = 1; - - //Stock Market - this.hasWseAccount = false; - this.hasTixApiAccess = false; - this.has4SData = false; - this.has4SDataTixApi = false; - - //Gang - this.gang = 0; - - //Corporation - this.corporation = 0; - - //Bladeburner - this.bladeburner = 0; - this.bladeburner_max_stamina_mult = 1; - this.bladeburner_stamina_gain_mult = 1; - this.bladeburner_analysis_mult = 1; //Field Analysis Only - this.bladeburner_success_chance_mult = 1; - - // Sleeves & Re-sleeving - this.sleeves = []; - this.resleeves = []; - this.sleevesFromCovenant = 0; // # of Duplicate sleeves purchased from the covenant - - //bitnode - this.bitNodeN = 1; - - //Flags for determining whether certain "thresholds" have been achieved - this.firstFacInvRecvd = false; - this.firstAugPurchased = false; - this.firstTimeTraveled = false; - this.firstProgramAvailable = false; - - //Used to store the last update time. - this.lastUpdate = 0; - this.totalPlaytime = 0; - this.playtimeSinceLastAug = 0; - this.playtimeSinceLastBitnode = 0; - - // Keep track of where money comes from - this.moneySourceA = new MoneySourceTracker(); // Where money comes from since last-installed Augmentation - this.moneySourceB = new MoneySourceTracker(); // Where money comes from for this entire BitNode run - - // Production since last Augmentation installation - this.scriptProdSinceLastAug = 0; -}; - -PlayerObject.prototype.init = function() { - /* Initialize Player's home computer */ - var t_homeComp = new Server({ - ip:createRandomIp(), hostname:"home", organizationName:"Home PC", - isConnectedTo:true, adminRights:true, purchasedByPlayer:true, maxRam:8 - }); - this.homeComputer = t_homeComp.ip; - this.currentServer = t_homeComp.ip; - AddToAllServers(t_homeComp); - - this.getHomeComputer().programs.push(Programs.NukeProgram.name); -} - -PlayerObject.prototype.prestigeAugmentation = function() { - var homeComp = this.getHomeComputer(); - this.currentServer = homeComp.ip; - this.homeComputer = homeComp.ip; - - this.numPeopleKilled = 0; - this.karma = 0; - - //Reset stats - this.hacking_skill = 1; - - this.strength = 1; - this.defense = 1; - this.dexterity = 1; - this.agility = 1; - - this.charisma = 1; - - this.hacking_exp = 0; - this.strength_exp = 0; - this.defense_exp = 0; - this.dexterity_exp = 0; - this.agility_exp = 0; - this.charisma_exp = 0; - - this.money = new Decimal(1000); - - this.city = CityName.Sector12; - this.location = ""; - - this.companyName = ""; - this.jobs = {}; - - this.purchasedServers = []; - - this.factions = []; - this.factionInvitations = []; - - this.queuedAugmentations = []; - - this.resleeves = []; - - for (let i = 0; i < this.sleeves.length; ++i) { - if (this.sleeves[i] instanceof Sleeve) { - if (this.sleeves[i].shock >= 100) { - this.sleeves[i].synchronize(this); - } else { - this.sleeves[i].shockRecovery(this); - } - } - } - - this.isWorking = false; - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; - this.createProgramName = ""; - this.className = ""; - this.crimeType = ""; - - this.workHackExpGainRate = 0; - this.workStrExpGainRate = 0; - this.workDefExpGainRate = 0; - this.workDexExpGainRate = 0; - this.workAgiExpGainRate = 0; - this.workChaExpGainRate = 0; - this.workRepGainRate = 0; - this.workMoneyGainRate = 0; - - this.workHackExpGained = 0; - this.workStrExpGained = 0; - this.workDefExpGained = 0; - this.workDexExpGained = 0; - this.workAgiExpGained = 0; - this.workChaExpGained = 0; - this.workRepGained = 0; - this.workMoneyGained = 0; - - this.timeWorked = 0; - - this.lastUpdate = new Date().getTime(); - - // Statistics Trackers - this.playtimeSinceLastAug = 0; - this.scriptProdSinceLastAug = 0; - this.moneySourceA.reset(); - - this.hacknetNodes.length = 0; - - //Re-calculate skills and reset HP - this.updateSkillLevels(); - this.hp = this.max_hp; -} - -PlayerObject.prototype.prestigeSourceFile = function() { - var homeComp = this.getHomeComputer(); - this.currentServer = homeComp.ip; - this.homeComputer = homeComp.ip; - - this.numPeopleKilled = 0; - this.karma = 0; - - //Reset stats - this.hacking_skill = 1; - - this.strength = 1; - this.defense = 1; - this.dexterity = 1; - this.agility = 1; - - this.charisma = 1; - - this.hacking_exp = 0; - this.strength_exp = 0; - this.defense_exp = 0; - this.dexterity_exp = 0; - this.agility_exp = 0; - this.charisma_exp = 0; - - this.money = new Decimal(1000); - - this.city = CityName.Sector12; - this.location = ""; - - this.companyName = ""; - this.jobs = {}; - - this.purchasedServers = []; - - this.factions = []; - this.factionInvitations = []; - - this.queuedAugmentations = []; - this.augmentations = []; - - this.resleeves = []; - - // Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists) - this.sleeves.length = SourceFileFlags[10] + this.sleevesFromCovenant; - for (let i = 0; i < this.sleeves.length; ++i) { - if (this.sleeves[i] instanceof Sleeve) { - this.sleeves[i].prestige(this); - } else { - this.sleeves[i] = new Sleeve(this); - } - } - - this.isWorking = false; - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; - this.createProgramName = ""; - this.className = ""; - this.crimeType = ""; - - this.workHackExpGainRate = 0; - this.workStrExpGainRate = 0; - this.workDefExpGainRate = 0; - this.workDexExpGainRate = 0; - this.workAgiExpGainRate = 0; - this.workChaExpGainRate = 0; - this.workRepGainRate = 0; - this.workMoneyGainRate = 0; - - this.workHackExpGained = 0; - this.workStrExpGained = 0; - this.workDefExpGained = 0; - this.workDexExpGained = 0; - this.workAgiExpGained = 0; - this.workChaExpGained = 0; - this.workRepGained = 0; - this.workMoneyGained = 0; - - this.timeWorked = 0; - - this.lastUpdate = new Date().getTime(); - - this.hacknetNodes.length = 0; - - //Gang - this.gang = null; - resetGangs(); - - //Reset Stock market - this.hasWseAccount = false; - this.hasTixApiAccess = false; - this.has4SData = false; - this.has4SDataTixApi = false; - - //BitNode 3: Corporatocracy - this.corporation = 0; - - // Statistics trackers - this.playtimeSinceLastAug = 0; - this.playtimeSinceLastBitnode = 0; - this.scriptProdSinceLastAug = 0; - this.moneySourceA.reset(); - this.moneySourceB.reset(); - - this.updateSkillLevels(); - this.hp = this.max_hp; -} - -PlayerObject.prototype.receiveInvite = function(factionName) { - if(this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) { - return; - } - this.firstFacInvRecvd = true; - this.factionInvitations.push(factionName); -} - -//Calculates skill level based on experience. The same formula will be used for every skill -PlayerObject.prototype.calculateSkill = function(exp, mult=1) { - return Math.max(Math.floor(mult*(32 * Math.log(exp + 534.5) - 200)), 1); -} - -PlayerObject.prototype.updateSkillLevels = function() { - this.hacking_skill = Math.max(1, Math.floor(this.calculateSkill(this.hacking_exp, this.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier))); - this.strength = Math.max(1, Math.floor(this.calculateSkill(this.strength_exp, this.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier))); - this.defense = Math.max(1, Math.floor(this.calculateSkill(this.defense_exp, this.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier))); - this.dexterity = Math.max(1, Math.floor(this.calculateSkill(this.dexterity_exp, this.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier))); - this.agility = Math.max(1, Math.floor(this.calculateSkill(this.agility_exp, this.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier))); - this.charisma = Math.max(1, Math.floor(this.calculateSkill(this.charisma_exp, this.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier))); - - if (this.intelligence > 0) { - this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp)); - } else { - this.intelligence = 0; - } - - var ratio = this.hp / this.max_hp; - this.max_hp = Math.floor(10 + this.defense / 10); - this.hp = Math.round(this.max_hp * ratio); -} - -PlayerObject.prototype.resetMultipliers = function() { - this.hacking_chance_mult = 1; - this.hacking_speed_mult = 1; - this.hacking_money_mult = 1; - this.hacking_grow_mult = 1; - - this.hacking_mult = 1; - this.strength_mult = 1; - this.defense_mult = 1; - this.dexterity_mult = 1; - this.agility_mult = 1; - this.charisma_mult = 1; - - this.hacking_exp_mult = 1; - this.strength_exp_mult = 1; - this.defense_exp_mult = 1; - this.dexterity_exp_mult = 1; - this.agility_exp_mult = 1; - this.charisma_exp_mult = 1; - - this.company_rep_mult = 1; - this.faction_rep_mult = 1; - - this.crime_money_mult = 1; - this.crime_success_mult = 1; - - this.hacknet_node_money_mult = 1; - this.hacknet_node_purchase_cost_mult = 1; - this.hacknet_node_ram_cost_mult = 1; - this.hacknet_node_core_cost_mult = 1; - this.hacknet_node_level_cost_mult = 1; - - this.work_money_mult = 1; - - this.bladeburner_max_stamina_mult = 1; - this.bladeburner_stamina_gain_mult = 1; - this.bladeburner_analysis_mult = 1; - this.bladeburner_success_chance_mult = 1; -} - -PlayerObject.prototype.hasProgram = function(programName) { - const home = this.getHomeComputer(); - if (home == null) { return false; } - - for (var i = 0; i < home.programs.length; ++i) { - if (programName.toLowerCase() == home.programs[i].toLowerCase()) {return true;} - } - return false; -} - -PlayerObject.prototype.setMoney = function(money) { - if (isNaN(money)) { - console.log("ERR: NaN passed into Player.setMoney()"); return; - } - this.money = money; -} - -PlayerObject.prototype.gainMoney = function(money) { - if (isNaN(money)) { - console.log("ERR: NaN passed into Player.gainMoney()"); return; - } - this.money = this.money.plus(money); -} - -PlayerObject.prototype.loseMoney = function(money) { - if (isNaN(money)) { - console.log("ERR: NaN passed into Player.loseMoney()"); return; - } - this.money = this.money.minus(money); -} - -PlayerObject.prototype.canAfford = function(cost) { - if (isNaN(cost)) { - console.error(`NaN passed into Player.canAfford()`); - return false; - } - return this.money.gte(cost); -} - -PlayerObject.prototype.recordMoneySource = function(amt, source) { - if (!(this.moneySourceA instanceof MoneySourceTracker)) { - console.warn(`Player.moneySourceA was not properly initialized. Resetting`); - this.moneySourceA = new MoneySourceTracker(); - } - if (!(this.moneySourceB instanceof MoneySourceTracker)) { - console.warn(`Player.moneySourceB was not properly initialized. Resetting`); - this.moneySourceB = new MoneySourceTracker(); - } - this.moneySourceA.record(amt, source); - this.moneySourceB.record(amt, source); -} - -PlayerObject.prototype.gainHackingExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into Player.gainHackingExp()"); return; - } - this.hacking_exp += exp; - if(this.hacking_exp < 0) { - this.hacking_exp = 0; - } -} - -PlayerObject.prototype.gainStrengthExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into Player.gainStrengthExp()"); return; - } - this.strength_exp += exp; - if(this.strength_exp < 0) { - this.strength_exp = 0; - } -} - -PlayerObject.prototype.gainDefenseExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into player.gainDefenseExp()"); return; - } - this.defense_exp += exp; - if(this.defense_exp < 0) { - this.defense_exp = 0; - } -} - -PlayerObject.prototype.gainDexterityExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into Player.gainDexterityExp()"); return; - } - this.dexterity_exp += exp; - if(this.dexterity_exp < 0) { - this.dexterity_exp = 0; - } -} - -PlayerObject.prototype.gainAgilityExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into Player.gainAgilityExp()"); return; - } - this.agility_exp += exp; - if(this.agility_exp < 0) { - this.agility_exp = 0; - } -} - -PlayerObject.prototype.gainCharismaExp = function(exp) { - if (isNaN(exp)) { - console.log("ERR: NaN passed into Player.gainCharismaExp()"); return; - } - this.charisma_exp += exp; - if(this.charisma_exp < 0) { - this.charisma_exp = 0; - } -} - -PlayerObject.prototype.gainIntelligenceExp = function(exp) { - if (isNaN(exp)) { - console.log("ERROR: NaN passed into Player.gainIntelligenceExp()"); return; - } - if (hasAISF || this.intelligence > 0) { - this.intelligence_exp += exp; - } -} - -//Given a string expression like "str" or "strength", returns the given stat -PlayerObject.prototype.queryStatFromString = function(str) { - const tempStr = str.toLowerCase(); - if (tempStr.includes("hack")) { return this.hacking_skill; } - if (tempStr.includes("str")) { return this.strength; } - if (tempStr.includes("def")) { return this.defense; } - if (tempStr.includes("dex")) { return this.dexterity; } - if (tempStr.includes("agi")) { return this.agility; } - if (tempStr.includes("cha")) { return this.charisma; } - if (tempStr.includes("int")) { return this.intelligence; } -} - -/******* Working functions *******/ -PlayerObject.prototype.resetWorkStatus = function() { - this.workHackExpGainRate = 0; - this.workStrExpGainRate = 0; - this.workDefExpGainRate = 0; - this.workDexExpGainRate = 0; - this.workAgiExpGainRate = 0; - this.workChaExpGainRate = 0; - this.workRepGainRate = 0; - this.workMoneyGainRate = 0; - this.workMoneyLossRate = 0; - - this.workHackExpGained = 0; - this.workStrExpGained = 0; - this.workDefExpGained = 0; - this.workDexExpGained = 0; - this.workAgiExpGained = 0; - this.workChaExpGained = 0; - this.workRepGained = 0; - this.workMoneyGained = 0; - - this.timeWorked = 0; - this.timeWorkedCreateProgram = 0; - - this.currentWorkFactionName = ""; - this.currentWorkFactionDescription = ""; - this.createProgramName = ""; - this.className = ""; - - document.getElementById("work-in-progress-text").innerHTML = ""; -} - -PlayerObject.prototype.processWorkEarnings = function(numCycles=1) { - const hackExpGain = this.workHackExpGainRate * numCycles; - const strExpGain = this.workStrExpGainRate * numCycles; - const defExpGain = this.workDefExpGainRate * numCycles; - const dexExpGain = this.workDexExpGainRate * numCycles; - const agiExpGain = this.workAgiExpGainRate * numCycles; - const chaExpGain = this.workChaExpGainRate * numCycles; - const moneyGain = (this.workMoneyGainRate - this.workMoneyLossRate) * numCycles; - - this.gainHackingExp(hackExpGain); - this.gainStrengthExp(strExpGain); - this.gainDefenseExp(defExpGain); - this.gainDexterityExp(dexExpGain); - this.gainAgilityExp(agiExpGain); - this.gainCharismaExp(chaExpGain); - this.gainMoney(moneyGain); - this.recordMoneySource(moneyGain, "work"); - this.workHackExpGained += hackExpGain; - this.workStrExpGained += strExpGain; - this.workDefExpGained += defExpGain; - this.workDexExpGained += dexExpGain; - this.workAgiExpGained += agiExpGain; - this.workChaExpGained += chaExpGain; - this.workRepGained += this.workRepGainRate * numCycles; - this.workMoneyGained += this.workMoneyGainRate * numCycles; - this.workMoneyGained -= this.workMoneyLossRate * numCycles; -} - -/* Working for Company */ -PlayerObject.prototype.startWork = function(companyName) { - this.resetWorkStatus(); - this.isWorking = true; - this.companyName = companyName; - this.workType = CONSTANTS.WorkTypeCompany; - - this.workHackExpGainRate = this.getWorkHackExpGain(); - this.workStrExpGainRate = this.getWorkStrExpGain(); - this.workDefExpGainRate = this.getWorkDefExpGain(); - this.workDexExpGainRate = this.getWorkDexExpGain(); - this.workAgiExpGainRate = this.getWorkAgiExpGain(); - this.workChaExpGainRate = this.getWorkChaExpGain(); - this.workRepGainRate = this.getWorkRepGain(); - this.workMoneyGainRate = this.getWorkMoneyGain(); - - this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; - - //Remove all old event listeners from Cancel button - var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); - newCancelButton.innerHTML = "Cancel Work"; - newCancelButton.addEventListener("click", function() { - this.finishWork(true); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.work = function(numCycles) { - //Cap the number of cycles being processed to whatever would put you at - //the work time limit (8 hours) - var overMax = false; - if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { - overMax = true; - numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); - } - this.timeWorked += Engine._idleSpeed * numCycles; - - this.workRepGainRate = this.getWorkRepGain(); - this.processWorkEarnings(numCycles); - - //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money - if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { - return this.finishWork(false); - } - - var comp = Companies[this.companyName], companyRep = "0"; - if (comp == null || !(comp instanceof Company)) { - console.error(`Could not find Company: ${this.companyName}`); - } else { - companyRep = comp.playerReputation; - } - - const position = this.jobs[this.companyName]; - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are currently working as a " + position + - " at " + this.companyName + " (Current Company Reputation: " + - numeralWrapper.format(companyRep, '0,0') + ")

    " + - "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "You have earned:

    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company

    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + - "You will automatically finish after working for 8 hours. You can cancel earlier if you wish, " + - "but you will only gain half of the reputation you've earned so far." -} - -PlayerObject.prototype.finishWork = function(cancelled, sing=false) { - //Since the work was cancelled early, player only gains half of what they've earned so far - if (cancelled) { - this.workRepGained /= 2; - } - - var company = Companies[this.companyName]; - company.playerReputation += (this.workRepGained); - - this.updateSkillLevels(); - - var txt = "You earned a total of:
    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; - - if (cancelled) { - txt = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "Since you cancelled your work early, you only gained half of the reputation you earned.

    " + txt; - } else { - txt = "You worked a full shift of 8 hours!

    " + txt; - } - if (!sing) {dialogBoxCreate(txt);} - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - this.isWorking = false; - Engine.loadLocationContent(); - - if (sing) { - var res = "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + - "earned $" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp."; - this.resetWorkStatus(); - return res; - } - this.resetWorkStatus(); -} - -PlayerObject.prototype.startWorkPartTime = function(companyName) { - this.resetWorkStatus(); - this.isWorking = true; - this.companyName = companyName; - this.workType = CONSTANTS.WorkTypeCompanyPartTime; - - this.workHackExpGainRate = this.getWorkHackExpGain(); - this.workStrExpGainRate = this.getWorkStrExpGain(); - this.workDefExpGainRate = this.getWorkDefExpGain(); - this.workDexExpGainRate = this.getWorkDexExpGain(); - this.workAgiExpGainRate = this.getWorkAgiExpGain(); - this.workChaExpGainRate = this.getWorkChaExpGain(); - this.workRepGainRate = this.getWorkRepGain(); - this.workMoneyGainRate = this.getWorkMoneyGain(); - - this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer8Hours; - - var newCancelButton = clearEventListeners("work-in-progress-cancel-button"); - newCancelButton.innerHTML = "Stop Working"; - newCancelButton.addEventListener("click", function() { - this.finishWorkPartTime(); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.workPartTime = function(numCycles) { - //Cap the number of cycles being processed to whatever would put you at the - //work time limit (8 hours) - var overMax = false; - if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer8Hours) { - overMax = true; - numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed); - } - this.timeWorked += Engine._idleSpeed * numCycles; - - this.workRepGainRate = this.getWorkRepGain(); - this.processWorkEarnings(numCycles); - - //If timeWorked == 8 hours, then finish. You can only gain 8 hours worth of exp and money - if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) { - return this.finishWorkPartTime(); - } - - var comp = Companies[this.companyName], companyRep = "0"; - if (comp == null || !(comp instanceof Company)) { - console.log("ERROR: Could not find Company: " + this.companyName); - } else { - companyRep = comp.playerReputation; - } - - const position = this.jobs[this.companyName]; - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are currently working as a " + position + - " at " + this.companyName + " (Current Company Reputation: " + - numeralWrapper.format(companyRep, '0,0') + ")

    " + - "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "You have earned:

    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this company

    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + - "You will automatically finish after working for 8 hours. You can cancel earlier if you wish,
    " + - "and there will be no penalty because this is a part-time job."; - -} - -PlayerObject.prototype.finishWorkPartTime = function(sing=false) { - var company = Companies[this.companyName]; - company.playerReputation += (this.workRepGained); - - this.updateSkillLevels(); - - var txt = "You earned a total of:
    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the company
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; - txt = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + txt; - if (!sing) {dialogBoxCreate(txt);} - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - this.isWorking = false; - Engine.loadLocationContent(); - if (sing) { - var res = "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " + - "earned a total of " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + ", " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation, " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp"; - this.resetWorkStatus(); - return res; - } - this.resetWorkStatus(); -} - -/* Working for Faction */ -PlayerObject.prototype.startFactionWork = function(faction) { - //Update reputation gain rate to account for faction favor - var favorMult = 1 + (faction.favor / 100); - if (isNaN(favorMult)) {favorMult = 1;} - this.workRepGainRate *= favorMult; - this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; - - this.isWorking = true; - this.workType = CONSTANTS.WorkTypeFaction; - this.currentWorkFactionName = faction.name; - - this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours; - - var cancelButton = clearEventListeners("work-in-progress-cancel-button"); - cancelButton.innerHTML = "Stop Faction Work"; - cancelButton.addEventListener("click", function() { - this.finishFactionWork(true); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.startFactionHackWork = function(faction) { - this.resetWorkStatus(); - - this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workRepGainRate = this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; - - this.factionWorkType = CONSTANTS.FactionWorkHacking; - this.currentWorkFactionDescription = "carrying out hacking contracts"; - - this.startFactionWork(faction); -} - -PlayerObject.prototype.startFactionFieldWork = function(faction) { - this.resetWorkStatus(); - - this.workHackExpGainRate = .1 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workStrExpGainRate = .1 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDefExpGainRate = .1 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDexExpGainRate = .1 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workAgiExpGainRate = .1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workChaExpGainRate = .1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workRepGainRate = this.getFactionFieldWorkRepGain(); - - this.factionWorkType = CONSTANTS.FactionWorkField; - this.currentWorkFactionDescription = "carrying out field missions" - - this.startFactionWork(faction); -} - -PlayerObject.prototype.startFactionSecurityWork = function(faction) { - this.resetWorkStatus(); - - this.workHackExpGainRate = 0.05 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workStrExpGainRate = 0.15 * this.strength_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDefExpGainRate = 0.15 * this.defense_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workDexExpGainRate = 0.15 * this.dexterity_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workAgiExpGainRate = 0.15 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workChaExpGainRate = 0.00 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; - this.workRepGainRate = this.getFactionSecurityWorkRepGain(); - - this.factionWorkType = CONSTANTS.FactionWorkSecurity; - this.currentWorkFactionDescription = "performing security detail" - - this.startFactionWork(faction); -} - -PlayerObject.prototype.workForFaction = function(numCycles) { - var faction = Factions[this.currentWorkFactionName]; - - //Constantly update the rep gain rate - switch (this.factionWorkType) { - case CONSTANTS.FactionWorkHacking: - this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult; - break; - case CONSTANTS.FactionWorkField: - this.workRepGainRate = this.getFactionFieldWorkRepGain(); - break; - case CONSTANTS.FactionWorkSecurity: - this.workRepGainRate = this.getFactionSecurityWorkRepGain(); - break; - default: - break; - } - - //Update reputation gain rate to account for faction favor - var favorMult = 1 + (faction.favor / 100); - if (isNaN(favorMult)) {favorMult = 1;} - this.workRepGainRate *= favorMult; - this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain; - - //Cap the number of cycles being processed to whatever would put you at limit (20 hours) - var overMax = false; - if (this.timeWorked + (Engine._idleSpeed * numCycles) >= CONSTANTS.MillisecondsPer20Hours) { - overMax = true; - numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / Engine._idleSpeed); - } - this.timeWorked += Engine._idleSpeed * numCycles; - - this.processWorkEarnings(numCycles); - - //If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours - if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) { - return this.finishFactionWork(false); - } - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are currently " + this.currentWorkFactionDescription + " for your faction " + faction.name + - " (Current Faction Reputation: " + numeralWrapper.format(faction.playerReputation, '0,0') + ").
    " + - "You have been doing this for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "You have earned:

    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " (" + numeralWrapper.format(this.workMoneyGainRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " (" + numeralWrapper.format(this.workRepGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) reputation for this faction

    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp

    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp

    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp

    " + - - "You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
    " + - "There is no penalty for cancelling earlier."; -} - -PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) { - var faction = Factions[this.currentWorkFactionName]; - faction.playerReputation += (this.workRepGained); - - this.updateSkillLevels(); - - var txt = "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "You earned a total of:
    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " reputation for the faction
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; - if (!sing) {dialogBoxCreate(txt);} - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - - this.isWorking = false; - - Engine.loadFactionContent(); - displayFactionContent(faction.name); - if (sing) { - var res="You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " + - "You earned " + - numeralWrapper.format(this.workRepGained, '0,0.0000') + " rep, " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, and " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."; - this.resetWorkStatus(); - return res; - } - this.resetWorkStatus(); -} - -//Money gained per game cycle -PlayerObject.prototype.getWorkMoneyGain = function() { - // If player has SF-11, calculate salary multiplier from favor - let bn11Mult = 1; - const company = Companies[this.companyName]; - if (hasBn11SF) { bn11Mult = 1 + (company.favor / 100); } - - // Get base salary - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (companyPosition == null) { - console.error(`Could not find CompanyPosition object for ${companyPositionName}. Work salary will be 0`); - return 0; - } - - return companyPosition.baseSalary * company.salaryMultiplier * this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney * bn11Mult; -} - -//Hack exp gained per game cycle -PlayerObject.prototype.getWorkHackExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work hack exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.hackingExpGain * company.expMultiplier * this.hacking_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Str exp gained per game cycle -PlayerObject.prototype.getWorkStrExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work str exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.strengthExpGain * company.expMultiplier * this.strength_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Def exp gained per game cycle -PlayerObject.prototype.getWorkDefExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work def exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.defenseExpGain * company.expMultiplier * this.defense_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Dex exp gained per game cycle -PlayerObject.prototype.getWorkDexExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work dex exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.dexterityExpGain * company.expMultiplier * this.dexterity_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Agi exp gained per game cycle -PlayerObject.prototype.getWorkAgiExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work agi exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.agilityExpGain * company.expMultiplier * this.agility_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Charisma exp gained per game cycle -PlayerObject.prototype.getWorkChaExpGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work cha exp gain will be 0`].join(" ")); - return 0; - } - - return companyPosition.charismaExpGain * company.expMultiplier * this.charisma_exp_mult * BitNodeMultipliers.CompanyWorkExpGain; -} - -//Reputation gained per game cycle -PlayerObject.prototype.getWorkRepGain = function() { - const company = Companies[this.companyName]; - const companyPositionName = this.jobs[this.companyName]; - const companyPosition = CompanyPositions[companyPositionName]; - if (company == null || companyPosition == null) { - console.error([`Could not find Company object for ${this.companyName}`, - `or CompanyPosition object for ${companyPositionName}.`, - `Work rep gain will be 0`].join(" ")); - return 0; - } - - var jobPerformance = companyPosition.calculateJobPerformance(this.hacking_skill, this.strength, - this.defense, this.dexterity, - this.agility, this.charisma); - - //Intelligence provides a flat bonus to job performance - jobPerformance += (this.intelligence / CONSTANTS.MaxSkillLevel); - - //Update reputation gain rate to account for company favor - var favorMult = 1 + (company.favor / 100); - if (isNaN(favorMult)) { favorMult = 1; } - return jobPerformance * this.company_rep_mult * favorMult; -} - -PlayerObject.prototype.getFactionSecurityWorkRepGain = function() { - var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel + - this.strength / CONSTANTS.MaxSkillLevel + - this.defense / CONSTANTS.MaxSkillLevel + - this.dexterity / CONSTANTS.MaxSkillLevel + - this.agility / CONSTANTS.MaxSkillLevel) / 4.5; - return t * this.faction_rep_mult; -} - -PlayerObject.prototype.getFactionFieldWorkRepGain = function() { - var t = 0.9 * (this.hacking_skill / CONSTANTS.MaxSkillLevel + - this.strength / CONSTANTS.MaxSkillLevel + - this.defense / CONSTANTS.MaxSkillLevel + - this.dexterity / CONSTANTS.MaxSkillLevel + - this.agility / CONSTANTS.MaxSkillLevel + - this.charisma / CONSTANTS.MaxSkillLevel + - this.intelligence / CONSTANTS.MaxSkillLevel) / 5.5; - return t * this.faction_rep_mult; -} - -/* Creating a Program */ -PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqLevel) { - this.resetWorkStatus(); - this.isWorking = true; - this.workType = CONSTANTS.WorkTypeCreateProgram; - - //Time needed to complete work affected by hacking skill (linearly based on - //ratio of (your skill - required level) to MAX skill) - //var timeMultiplier = (CONSTANTS.MaxSkillLevel - (this.hacking_skill - reqLevel)) / CONSTANTS.MaxSkillLevel; - //if (timeMultiplier > 1) {timeMultiplier = 1;} - //if (timeMultiplier < 0.01) {timeMultiplier = 0.01;} - this.createProgramReqLvl = reqLevel; - - this.timeNeededToCompleteWork = time; - //Check for incomplete program - for (var i = 0; i < this.getHomeComputer().programs.length; ++i) { - var programFile = this.getHomeComputer().programs[i]; - if (programFile.startsWith(programName) && programFile.endsWith("%-INC")) { - var res = programFile.split("-"); - if (res.length != 3) {break;} - var percComplete = Number(res[1].slice(0, -1)); - if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {break;} - this.timeWorkedCreateProgram = percComplete / 100 * this.timeNeededToCompleteWork; - this.getHomeComputer().programs.splice(i, 1); - } - } - - this.createProgramName = programName; - - var cancelButton = clearEventListeners("work-in-progress-cancel-button"); - cancelButton.innerHTML = "Cancel work on creating program"; - cancelButton.addEventListener("click", function() { - this.finishCreateProgramWork(true); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.createProgramWork = function(numCycles) { - //Higher hacking skill will allow you to create programs faster - var reqLvl = this.createProgramReqLvl; - var skillMult = (this.hacking_skill / reqLvl); //This should always be greater than 1; - skillMult = 1 + ((skillMult - 1) / 5); //The divider constant can be adjusted as necessary - - //Skill multiplier directly applied to "time worked" - this.timeWorked += (Engine._idleSpeed * numCycles); - this.timeWorkedCreateProgram += (Engine._idleSpeed * numCycles * skillMult); - var programName = this.createProgramName; - - if (this.timeWorkedCreateProgram >= this.timeNeededToCompleteWork) { - this.finishCreateProgramWork(false); - } - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are currently working on coding " + programName + ".

    " + - "You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "The program is " + (this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 100).toFixed(2) + "% complete.
    " + - "If you cancel, your work will be saved and you can come back to complete the program later."; -} - -PlayerObject.prototype.finishCreateProgramWork = function(cancelled, sing=false) { - var programName = this.createProgramName; - if (cancelled === false) { - dialogBoxCreate("You've finished creating " + programName + "!
    " + - "The new program can be found on your home computer."); - - this.getHomeComputer().programs.push(programName); - } else { - var perc = (Math.floor(this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 10000)/100).toString(); - var incompleteName = programName + "-" + perc + "%-INC"; - this.getHomeComputer().programs.push(incompleteName); - } - - if (!cancelled) { - this.gainIntelligenceExp(this.createProgramReqLvl / CONSTANTS.IntelligenceProgramBaseExpGain); - } - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - - this.isWorking = false; - - Engine.loadTerminalContent(); - this.resetWorkStatus(); -} - -/* Studying/Taking Classes */ -PlayerObject.prototype.startClass = function(costMult, expMult, className) { - this.resetWorkStatus(); - this.isWorking = true; - this.workType = CONSTANTS.WorkTypeStudyClass; - - this.className = className; - - var gameCPS = 1000 / Engine._idleSpeed; - - //Base exp gains per second - var baseStudyComputerScienceExp = 0.5; - var baseDataStructuresExp = 1; - var baseNetworksExp = 2; - var baseAlgorithmsExp = 4; - var baseManagementExp = 2; - var baseLeadershipExp = 4; - var baseGymExp = 1; - - //Find cost and exp gain per game cycle - var cost = 0; - var hackExp = 0, strExp = 0, defExp = 0, dexExp = 0, agiExp = 0, chaExp = 0; - const hashManager = this.hashManager; - switch (className) { - case CONSTANTS.ClassStudyComputerScience: - hackExp = baseStudyComputerScienceExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassDataStructures: - cost = CONSTANTS.ClassDataStructuresBaseCost * costMult / gameCPS; - hackExp = baseDataStructuresExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassNetworks: - cost = CONSTANTS.ClassNetworksBaseCost * costMult / gameCPS; - hackExp = baseNetworksExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassAlgorithms: - cost = CONSTANTS.ClassAlgorithmsBaseCost * costMult / gameCPS; - hackExp = baseAlgorithmsExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassManagement: - cost = CONSTANTS.ClassManagementBaseCost * costMult / gameCPS; - chaExp = baseManagementExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassLeadership: - cost = CONSTANTS.ClassLeadershipBaseCost * costMult / gameCPS; - chaExp = baseLeadershipExp * expMult / gameCPS * hashManager.getStudyMult(); - break; - case CONSTANTS.ClassGymStrength: - cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; - strExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); - break; - case CONSTANTS.ClassGymDefense: - cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; - defExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); - break; - case CONSTANTS.ClassGymDexterity: - cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; - dexExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); - break; - case CONSTANTS.ClassGymAgility: - cost = CONSTANTS.ClassGymBaseCost * costMult / gameCPS; - agiExp = baseGymExp * expMult / gameCPS * hashManager.getTrainingMult(); - break; - default: - throw new Error("ERR: Invalid/unrecognized class name"); - return; - } - - this.workMoneyLossRate = cost; - this.workHackExpGainRate = hackExp * this.hacking_exp_mult * BitNodeMultipliers.ClassGymExpGain; - this.workStrExpGainRate = strExp * this.strength_exp_mult * BitNodeMultipliers.ClassGymExpGain;; - this.workDefExpGainRate = defExp * this.defense_exp_mult * BitNodeMultipliers.ClassGymExpGain;; - this.workDexExpGainRate = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.ClassGymExpGain;; - this.workAgiExpGainRate = agiExp * this.agility_exp_mult * BitNodeMultipliers.ClassGymExpGain;; - this.workChaExpGainRate = chaExp * this.charisma_exp_mult * BitNodeMultipliers.ClassGymExpGain;; - - var cancelButton = clearEventListeners("work-in-progress-cancel-button"); - if (className == CONSTANTS.ClassGymStrength || - className == CONSTANTS.ClassGymDefense || - className == CONSTANTS.ClassGymDexterity || - className == CONSTANTS.ClassGymAgility) { - cancelButton.innerHTML = "Stop training at gym"; - } else { - cancelButton.innerHTML = "Stop taking course"; - } - cancelButton.addEventListener("click", function() { - this.finishClass(); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.takeClass = function(numCycles) { - this.timeWorked += Engine._idleSpeed * numCycles; - var className = this.className; - - this.processWorkEarnings(numCycles); - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You have been " + className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "

    " + - "This has cost you:
    " + - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + " ($" + numeralWrapper.format(this.workMoneyLossRate * CYCLES_PER_SEC, '0,0.00') + " / sec)

    " + - "You have gained:
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workHackExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) hacking exp
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workStrExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDefExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workDexExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workAgiExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) agility exp
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " (" + numeralWrapper.format(this.workChaExpGainRate * CYCLES_PER_SEC, '0,0.0000') + " / sec) charisma exp
    " + - "You may cancel at any time"; -} - -//The 'sing' argument defines whether or not this function was called -//through a Singularity Netscript function -PlayerObject.prototype.finishClass = function(sing=false) { - this.gainIntelligenceExp(CONSTANTS.IntelligenceClassBaseExpGain * Math.round(this.timeWorked / 1000)); - - if (this.workMoneyGained > 0) { - throw new Error("ERR: Somehow gained money while taking class"); - } - - this.updateSkillLevels(); - var txt = "After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ",
    " + - "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ".

    " + - "You earned a total of:
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp
    "; - if (!sing) {dialogBoxCreate(txt);} - - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - - this.isWorking = false; - - Engine.loadLocationContent(); - if (sing) { - var res="After " + this.className + " for " + convertTimeMsToTimeElapsedString(this.timeWorked) + ", " + - "you spent a total of $" + numeralWrapper.format(this.workMoneyGained * -1, '0,0.00') + ". " + - "You earned a total of: " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility exp, and " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma exp"; - this.resetWorkStatus(); - return res; - } - this.resetWorkStatus(); -} - -//The EXP and $ gains are hardcoded. Time is in ms -PlayerObject.prototype.startCrime = function(crimeType, hackExp, strExp, defExp, dexExp, agiExp, chaExp, money, time, singParams=null) { - this.crimeType = crimeType; - - this.resetWorkStatus(); - this.isWorking = true; - this.workType = CONSTANTS.WorkTypeCrime; - - if (singParams && singParams.workerscript) { - this.committingCrimeThruSingFn = true; - this.singFnCrimeWorkerScript = singParams.workerscript; - } - - this.workHackExpGained = hackExp * this.hacking_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workStrExpGained = strExp * this.strength_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workDefExpGained = defExp * this.defense_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workDexExpGained = dexExp * this.dexterity_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workAgiExpGained = agiExp * this.agility_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workChaExpGained = chaExp * this.charisma_exp_mult * BitNodeMultipliers.CrimeExpGain; - this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney; - - this.timeNeededToCompleteWork = time; - - //Remove all old event listeners from Cancel button - var newCancelButton = clearEventListeners("work-in-progress-cancel-button") - newCancelButton.innerHTML = "Cancel crime" - newCancelButton.addEventListener("click", function() { - this.finishCrime(true); - return false; - }); - - //Display Work In Progress Screen - Engine.loadWorkInProgressContent(); -} - -PlayerObject.prototype.commitCrime = function (numCycles) { - this.timeWorked += Engine._idleSpeed * numCycles; - - if (this.timeWorked >= this.timeNeededToCompleteWork) {this.finishCrime(false); return;} - - var percent = Math.round(this.timeWorked / this.timeNeededToCompleteWork * 100); - var numBars = Math.round(percent / 5); - if (numBars < 0) {numBars = 0;} - if (numBars > 20) {numBars = 20;} - var progressBar = "[" + Array(numBars+1).join("|") + Array(20 - numBars + 1).join(" ") + "]"; - - var txt = document.getElementById("work-in-progress-text"); - txt.innerHTML = "You are attempting to " + this.crimeType + ".
    " + - "Time remaining: " + convertTimeMsToTimeElapsedString(this.timeNeededToCompleteWork - this.timeWorked) + "
    " + - progressBar.replace( / /g, " " ); -} - -PlayerObject.prototype.finishCrime = function(cancelled) { - //Determine crime success/failure - if (!cancelled) { - var statusText = ""; //TODO, unique message for each crime when you succeed - if (determineCrimeSuccess(Player, this.crimeType)) { - //Handle Karma and crime statistics - let crime = null; - for(const i in Crimes) { - if(Crimes[i].type == this.crimeType) { - crime = Crimes[i]; - break; - } - } - if(crime == null) { - console.log(this.crimeType); - dialogBoxCreate("ERR: Unrecognized crime type. This is probably a bug please contact the developer"); - } - this.gainMoney(this.workMoneyGained); - this.recordMoneySource(this.workMoneyGained, "crime"); - this.karma -= crime.karma; - this.numPeopleKilled += crime.kills; - if(crime.intelligence_exp > 0) { - this.gainIntelligenceExp(crime.intelligence_exp); - } - - //On a crime success, gain 2x exp - this.workHackExpGained *= 2; - this.workStrExpGained *= 2; - this.workDefExpGained *= 2; - this.workDexExpGained *= 2; - this.workAgiExpGained *= 2; - this.workChaExpGained *= 2; - if (this.committingCrimeThruSingFn) { - if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { - this.singFnCrimeWorkerScript.scriptRef.log("Crime successful! Gained " + - numeralWrapper.format(this.workMoneyGained, "$0.000a") + ", " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."); - } - } else { - dialogBoxCreate("Crime successful!

    " + - "You gained:
    "+ - "$" + numeralWrapper.format(this.workMoneyGained, '0,0.00') + "
    " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience"); - } - - } else { - //Exp halved on failure - this.workHackExpGained /= 2; - this.workStrExpGained /= 2; - this.workDefExpGained /= 2; - this.workDexExpGained /= 2; - this.workAgiExpGained /= 2; - this.workChaExpGained /= 2; - if (this.committingCrimeThruSingFn) { - if(this.singFnCrimeWorkerScript.disableLogs.ALL == null && this.singFnCrimeWorkerScript.disableLogs.commitCrime == null) { - this.singFnCrimeWorkerScript.scriptRef.log("Crime failed! Gained " + - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hack exp, " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " str exp, " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " def exp, " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dex exp, " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agi exp, " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " cha exp."); - } - } else { - dialogBoxCreate("Crime failed!

    " + - "You gained:
    "+ - numeralWrapper.format(this.workHackExpGained, '0,0.0000') + " hacking experience
    " + - numeralWrapper.format(this.workStrExpGained, '0,0.0000') + " strength experience
    " + - numeralWrapper.format(this.workDefExpGained, '0,0.0000') + " defense experience
    " + - numeralWrapper.format(this.workDexExpGained, '0,0.0000') + " dexterity experience
    " + - numeralWrapper.format(this.workAgiExpGained, '0,0.0000') + " agility experience
    " + - numeralWrapper.format(this.workChaExpGained, '0,0.0000') + " charisma experience"); - } - } - - this.gainHackingExp(this.workHackExpGained); - this.gainStrengthExp(this.workStrExpGained); - this.gainDefenseExp(this.workDefExpGained); - this.gainDexterityExp(this.workDexExpGained); - this.gainAgilityExp(this.workAgiExpGained); - this.gainCharismaExp(this.workChaExpGained); - } - this.committingCrimeThruSingFn = false; - this.singFnCrimeWorkerScript = null; - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - this.isWorking = false; - this.resetWorkStatus(); - Engine.loadLocationContent(); -} - -//Cancels the player's current "work" assignment and gives the proper rewards -//Used only for Singularity functions, so no popups are created -PlayerObject.prototype.singularityStopWork = function() { - if (!this.isWorking) {return "";} - var res; //Earnings text for work - switch (this.workType) { - case CONSTANTS.WorkTypeStudyClass: - res = this.finishClass(true); - break; - case CONSTANTS.WorkTypeCompany: - res = this.finishWork(true, true); - break; - case CONSTANTS.WorkTypeCompanyPartTime: - res = this.finishWorkPartTime(true); - break; - case CONSTANTS.WorkTypeFaction: - res = this.finishFactionWork(true, true); - break; - case CONSTANTS.WorkTypeCreateProgram: - res = this.finishCreateProgramWork(true, true); - break; - case CONSTANTS.WorkTypeCrime: - res = this.finishCrime(true); - break; - default: - console.log("ERROR: Unrecognized work type"); - return ""; - } - return res; -} - - -// Returns true if hospitalized, false otherwise -PlayerObject.prototype.takeDamage = function(amt) { - if (typeof amt !== "number") { - console.warn(`Player.takeDamage() called without a numeric argument: ${amt}`); - return; - } - - this.hp -= amt; - if (this.hp <= 0) { - this.hospitalize(); - return true; - } else { - return false; - } -} - -PlayerObject.prototype.regenerateHp = function(amt) { - if (typeof amt !== "number") { - console.warn(`Player.regenerateHp() called without a numeric argument: ${amt}`); - return; - } - this.hp += amt; - if (this.hp > this.max_hp) { this.hp = this.max_hp; } -} - -PlayerObject.prototype.hospitalize = function() { - if (Settings.SuppressHospitalizationPopup === false) { - dialogBoxCreate( - "You were in critical condition! You were taken to the hospital where " + - "luckily they were able to save your life. You were charged " + - numeralWrapper.format(this.max_hp * CONSTANTS.HospitalCostPerHp, '$0.000a') - ); - } - - this.loseMoney(this.max_hp * CONSTANTS.HospitalCostPerHp); - this.hp = this.max_hp; -} - -/********* Company job application **********/ -//Determines the job that the Player should get (if any) at the current company -//The 'sing' argument designates whether or not this is being called from -//the applyToCompany() Netscript Singularity function -PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) { - // Get current company and job - let currCompany = null; - if (this.companyName !== "") { - currCompany = Companies[this.companyName]; - } - const currPositionName = this.jobs[this.companyName]; - - // Get company that's being applied to - const company = Companies[this.location]; //Company being applied to - if (!(company instanceof Company)) { - if (sing) { - return "ERROR: Invalid company name: " + this.location + ". applyToCompany() failed"; - } else { - console.error(`Could not find company that matches the location: ${this.location}. Player.applyToCompany() failed`); - return; - } - } - - let pos = entryPosType; - - if (!this.isQualified(company, pos)) { - var reqText = getJobRequirementText(company, pos); - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position
    " + reqText); - return; - } - - while (true) { - let newPos = getNextCompanyPosition(pos); - if (newPos == null) {break;} - - //Check if this company has this position - if (company.hasPosition(newPos)) { - if (!this.isQualified(company, newPos)) { - //If player not qualified for next job, break loop so player will be given current job - break; - } - pos = newPos; - } else { - break; - } - } - - //Check if the determined job is the same as the player's current job - if (currCompany != null) { - if (currCompany.name == company.name && pos.name == currPositionName) { - var nextPos = getNextCompanyPosition(pos); - if (nextPos == null) { - if (sing) {return false;} - dialogBoxCreate("You are already at the highest position for your field! No promotion available"); - } else if (company.hasPosition(nextPos)) { - if (sing) {return false;} - var reqText = getJobRequirementText(company, nextPos); - dialogBoxCreate("Unfortunately, you do not qualify for a promotion
    " + reqText); - } else { - if (sing) {return false;} - dialogBoxCreate("You are already at the highest position for your field! No promotion available"); - } - return; //Same job, do nothing - } - } - - this.companyName = company.name; - this.jobs[company.name] = pos.name; - - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - - if (sing) { return true; } - dialogBoxCreate("Congratulations! You were offered a new job at " + this.companyName + " as a " + pos.name + "!"); - - Engine.loadLocationContent(); -} - -//Returns your next position at a company given the field (software, business, etc.) -PlayerObject.prototype.getNextCompanyPosition = function(company, entryPosType) { - var currCompany = null; - if (this.companyName !== "") { - currCompany = Companies[this.companyName]; - } - - //Not employed at this company, so return the entry position - if (currCompany == null || (currCompany.name != company.name)) { - return entryPosType; - } - - //If the entry pos type and the player's current position have the same type, - //return the player's "nextCompanyPosition". Otherwise return the entryposType - //Employed at this company, so just return the next position if it exists. - const currentPositionName = this.jobs[this.companyName]; - const currentPosition = CompanyPositions[currentPositionName]; - if ((currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || - (currentPosition.isITJob() && entryPosType.isITJob()) || - (currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) || - (currentPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || - (currentPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || - (currentPosition.isSecurityJob() && entryPosType.isSecurityJob()) || - (currentPosition.isAgentJob() && entryPosType.isAgentJob()) || - (currentPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || - (currentPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || - (currentPosition.isPartTimeJob() && entryPosType.isPartTimeJob())) { - return getNextCompanyPosition(currentPosition); - } - - return entryPosType; -} - -PlayerObject.prototype.applyForSoftwareJob = function(sing=false) { - return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing); -} - -PlayerObject.prototype.applyForSoftwareConsultantJob = function(sing=false) { - return this.applyForJob(CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]], sing); -} - -PlayerObject.prototype.applyForItJob = function(sing=false) { - return this.applyForJob(CompanyPositions[posNames.ITCompanyPositions[0]], sing); -} - -PlayerObject.prototype.applyForSecurityEngineerJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]])) { - return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForNetworkEngineerJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]])) { - return this.applyForJob(CompanyPositions[posNames.NetworkEngineerCompanyPositions[0]], sing); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForBusinessJob = function(sing=false) { - return this.applyForJob(CompanyPositions[posNames.BusinessCompanyPositions[0]], sing); -} - -PlayerObject.prototype.applyForBusinessConsultantJob = function(sing=false) { - return this.applyForJob(CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]], sing); -} - -PlayerObject.prototype.applyForSecurityJob = function(sing=false) { - // TODO Police Jobs - // Indexing starts at 2 because 0 is for police officer - return this.applyForJob(CompanyPositions[posNames.SecurityCompanyPositions[2]], sing); -} - -PlayerObject.prototype.applyForAgentJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.AgentCompanyPositions[0]])) { - return this.applyForJob(CompanyPositions[posNames.AgentCompanyPositions[0]], sing); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForEmployeeJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) { - this.companyName = company.name; - this.jobs[company.name] = posNames.MiscCompanyPositions[1]; - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - if (sing) {return true;} - dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); - Engine.loadLocationContent(); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) { - this.companyName = company.name; - this.jobs[company.name] = posNames.PartTimeCompanyPositions[1]; - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - if (sing) {return true;} - dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); - Engine.loadLocationContent(); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForWaiterJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) { - this.companyName = company.name; - this.jobs[company.name] = posNames.MiscCompanyPositions[0]; - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - if (sing) {return true;} - dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); - Engine.loadLocationContent(); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) { - var company = Companies[this.location]; //Company being applied to - if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) { - this.companyName = company.name; - this.jobs[company.name] = posNames.PartTimeCompanyPositions[0]; - document.getElementById("world-menu-header").click(); - document.getElementById("world-menu-header").click(); - if (sing) {return true;} - dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); - Engine.loadLocationContent(); - } else { - if (sing) {return false;} - dialogBoxCreate("Unforunately, you do not qualify for this position"); - } -} - -//Checks if the Player is qualified for a certain position -PlayerObject.prototype.isQualified = function(company, position) { - var offset = company.jobStatReqOffset; - var reqHacking = position.requiredHacking > 0 ? position.requiredHacking+offset : 0; - var reqStrength = position.requiredStrength > 0 ? position.requiredStrength+offset : 0; - var reqDefense = position.requiredDefense > 0 ? position.requiredDefense+offset : 0; - var reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; - var reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity+offset : 0; - var reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma+offset : 0; - - if (this.hacking_skill >= reqHacking && - this.strength >= reqStrength && - this.defense >= reqDefense && - this.dexterity >= reqDexterity && - this.agility >= reqAgility && - this.charisma >= reqCharisma && - company.playerReputation >= position.requiredReputation) { - return true; - } - return false; -} - -/********** Reapplying Augmentations and Source File ***********/ -PlayerObject.prototype.reapplyAllAugmentations = function(resetMultipliers=true) { - console.log("Re-applying augmentations"); - if (resetMultipliers) { - this.resetMultipliers(); - } - - for (let i = 0; i < this.augmentations.length; ++i) { - //Compatibility with new version - if (this.augmentations[i].name === "HacknetNode NIC Architecture Neural-Upload") { - this.augmentations[i].name = "Hacknet Node NIC Architecture Neural-Upload"; - } - - const augName = this.augmentations[i].name; - var aug = Augmentations[augName]; - if (aug == null) { - console.log(`WARNING: Invalid augmentation name in Player.reapplyAllAugmentations(). Aug ${augName} will be skipped`); - continue; - } - aug.owned = true; - if (aug.name == AugmentationNames.NeuroFluxGovernor) { - for (let j = 0; j < aug.level; ++j) { - applyAugmentation(this.augmentations[i], true); - } - continue; - } - applyAugmentation(this.augmentations[i], true); - } -} - -PlayerObject.prototype.reapplyAllSourceFiles = function() { - console.log("Re-applying source files"); - //Will always be called after reapplyAllAugmentations() so multipliers do not have to be reset - //this.resetMultipliers(); - - for (let i = 0; i < this.sourceFiles.length; ++i) { - var srcFileKey = "SourceFile" + this.sourceFiles[i].n; - var sourceFileObject = SourceFiles[srcFileKey]; - if (sourceFileObject == null) { - console.log("ERROR: Invalid source file number: " + this.sourceFiles[i].n); - continue; - } - applySourceFile(this.sourceFiles[i]); - } -} - -/*************** Check for Faction Invitations *************/ -//This function sets the requirements to join a Faction. It checks whether the Player meets -//those requirements and will return an array of all factions that the Player should -//receive an invitation to -PlayerObject.prototype.checkForFactionInvitations = function() { - let invitedFactions = []; //Array which will hold all Factions the player should be invited to - - var numAugmentations = this.augmentations.length; - - const allCompanies = Object.keys(this.jobs); - const allPositions = Object.values(this.jobs); - - // Given a company name, safely returns the reputation (returns 0 if invalid company is specified) - function getCompanyRep(companyName) { - const company = Companies[companyName]; - if (company == null) { - return 0; - } else { - return company.playerReputation; - } - } - - // Helper function that returns a boolean indicating whether the Player meets - // the requirements for the specified company. There are two requirements: - // 1. High enough reputation - // 2. Player is employed at the company - function checkMegacorpRequirements(companyName, repNeeded=CONSTANTS.CorpFactionRepRequirement) { - return allCompanies.includes(companyName) && (getCompanyRep(companyName) > repNeeded); - } - - //Illuminati - var illuminatiFac = Factions["Illuminati"]; - if (!illuminatiFac.isBanned && !illuminatiFac.isMember && !illuminatiFac.alreadyInvited && - numAugmentations >= 30 && - this.money.gte(150000000000) && - this.hacking_skill >= 1500 && - this.strength >= 1200 && this.defense >= 1200 && - this.dexterity >= 1200 && this.agility >= 1200) { - invitedFactions.push(illuminatiFac); - } - - //Daedalus - var daedalusFac = Factions["Daedalus"]; - if (!daedalusFac.isBanned && !daedalusFac.isMember && !daedalusFac.alreadyInvited && - numAugmentations >= Math.round(30 * BitNodeMultipliers.DaedalusAugsRequirement) && - this.money.gte(100000000000) && - (this.hacking_skill >= 2500 || - (this.strength >= 1500 && this.defense >= 1500 && - this.dexterity >= 1500 && this.agility >= 1500))) { - invitedFactions.push(daedalusFac); - } - - //The Covenant - var covenantFac = Factions["The Covenant"]; - if (!covenantFac.isBanned && !covenantFac.isMember && !covenantFac.alreadyInvited && - numAugmentations >= 20 && - this.money.gte(75000000000) && - this.hacking_skill >= 850 && - this.strength >= 850 && - this.defense >= 850 && - this.dexterity >= 850 && - this.agility >= 850) { - invitedFactions.push(covenantFac); - } - - //ECorp - var ecorpFac = Factions["ECorp"]; - if (!ecorpFac.isBanned && !ecorpFac.isMember && !ecorpFac.alreadyInvited && - checkMegacorpRequirements(LocationName.AevumECorp)) { - invitedFactions.push(ecorpFac); - } - - //MegaCorp - var megacorpFac = Factions["MegaCorp"]; - if (!megacorpFac.isBanned && !megacorpFac.isMember && !megacorpFac.alreadyInvited && - checkMegacorpRequirements(LocationName.Sector12MegaCorp)) { - invitedFactions.push(megacorpFac); - } - - //Bachman & Associates - var bachmanandassociatesFac = Factions["Bachman & Associates"]; - if (!bachmanandassociatesFac.isBanned && !bachmanandassociatesFac.isMember && - !bachmanandassociatesFac.alreadyInvited && - checkMegacorpRequirements(LocationName.AevumBachmanAndAssociates)) { - invitedFactions.push(bachmanandassociatesFac); - } - - //Blade Industries - var bladeindustriesFac = Factions["Blade Industries"]; - if (!bladeindustriesFac.isBanned && !bladeindustriesFac.isMember && !bladeindustriesFac.alreadyInvited && - checkMegacorpRequirements(LocationName.Sector12BladeIndustries)) { - invitedFactions.push(bladeindustriesFac); - } - - //NWO - var nwoFac = Factions["NWO"]; - if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && - checkMegacorpRequirements(LocationName.VolhavenNWO)) { - invitedFactions.push(nwoFac); - } - - //Clarke Incorporated - var clarkeincorporatedFac = Factions["Clarke Incorporated"]; - if (!clarkeincorporatedFac.isBanned && !clarkeincorporatedFac.isMember && !clarkeincorporatedFac.alreadyInvited && - checkMegacorpRequirements(LocationName.AevumClarkeIncorporated)) { - invitedFactions.push(clarkeincorporatedFac); - } - - //OmniTek Incorporated - var omnitekincorporatedFac = Factions["OmniTek Incorporated"]; - if (!omnitekincorporatedFac.isBanned && !omnitekincorporatedFac.isMember && !omnitekincorporatedFac.alreadyInvited && - checkMegacorpRequirements(LocationName.VolhavenOmniTekIncorporated)) { - invitedFactions.push(omnitekincorporatedFac); - } - - //Four Sigma - var foursigmaFac = Factions["Four Sigma"]; - if (!foursigmaFac.isBanned && !foursigmaFac.isMember && !foursigmaFac.alreadyInvited && - checkMegacorpRequirements(LocationName.Sector12FourSigma)) { - invitedFactions.push(foursigmaFac); - } - - //KuaiGong International - var kuaigonginternationalFac = Factions["KuaiGong International"]; - if (!kuaigonginternationalFac.isBanned && !kuaigonginternationalFac.isMember && - !kuaigonginternationalFac.alreadyInvited && - checkMegacorpRequirements(LocationName.ChongqingKuaiGongInternational)) { - invitedFactions.push(kuaigonginternationalFac); - } - - //Fulcrum Secret Technologies - If u've unlocked fulcrum secret technolgoies server and have a high rep with the company - var fulcrumsecrettechonologiesFac = Factions["Fulcrum Secret Technologies"]; - var fulcrumSecretServer = AllServers[SpecialServerIps[SpecialServerNames.FulcrumSecretTechnologies]]; - if (fulcrumSecretServer == null) { - console.log("ERROR: Could not find Fulcrum Secret Technologies Server"); - } else { - if (!fulcrumsecrettechonologiesFac.isBanned && !fulcrumsecrettechonologiesFac.isMember && - !fulcrumsecrettechonologiesFac.alreadyInvited && - fulcrumSecretServer.manuallyHacked && - checkMegacorpRequirements(LocationName.AevumFulcrumTechnologies, 250e3)) { - invitedFactions.push(fulcrumsecrettechonologiesFac); - } - } - - //BitRunners - var bitrunnersFac = Factions["BitRunners"]; - var homeComp = this.getHomeComputer(); - var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]]; - if (bitrunnersServer == null) { - console.log("ERROR: Could not find BitRunners Server"); - } else if (!bitrunnersFac.isBanned && !bitrunnersFac.isMember && bitrunnersServer.manuallyHacked && - !bitrunnersFac.alreadyInvited && this.hacking_skill >= 500 && homeComp.maxRam >= 128) { - invitedFactions.push(bitrunnersFac); - } - - //The Black Hand - var theblackhandFac = Factions["The Black Hand"]; - var blackhandServer = AllServers[SpecialServerIps[SpecialServerNames.TheBlackHandServer]]; - if (blackhandServer == null) { - console.log("ERROR: Could not find The Black Hand Server"); - } else if (!theblackhandFac.isBanned && !theblackhandFac.isMember && blackhandServer.manuallyHacked && - !theblackhandFac.alreadyInvited && this.hacking_skill >= 350 && homeComp.maxRam >= 64) { - invitedFactions.push(theblackhandFac); - } - - //NiteSec - var nitesecFac = Factions["NiteSec"]; - var nitesecServer = AllServers[SpecialServerIps[SpecialServerNames.NiteSecServer]]; - if (nitesecServer == null) { - console.log("ERROR: Could not find NiteSec Server"); - } else if (!nitesecFac.isBanned && !nitesecFac.isMember && nitesecServer.manuallyHacked && - !nitesecFac.alreadyInvited && this.hacking_skill >= 200 && homeComp.maxRam >= 32) { - invitedFactions.push(nitesecFac); - } - - //Chongqing - var chongqingFac = Factions["Chongqing"]; - if (!chongqingFac.isBanned && !chongqingFac.isMember && !chongqingFac.alreadyInvited && - this.money.gte(20000000) && this.city == CityName.Chongqing) { - invitedFactions.push(chongqingFac); - } - - //Sector-12 - var sector12Fac = Factions["Sector-12"]; - if (!sector12Fac.isBanned && !sector12Fac.isMember && !sector12Fac.alreadyInvited && - this.money.gte(15000000) && this.city == CityName.Sector12) { - invitedFactions.push(sector12Fac); - } - - //New Tokyo - var newtokyoFac = Factions["New Tokyo"]; - if (!newtokyoFac.isBanned && !newtokyoFac.isMember && !newtokyoFac.alreadyInvited && - this.money.gte(20000000) && this.city == CityName.NewTokyo) { - invitedFactions.push(newtokyoFac); - } - - //Aevum - var aevumFac = Factions["Aevum"]; - if (!aevumFac.isBanned && !aevumFac.isMember && !aevumFac.alreadyInvited && - this.money.gte(40000000) && this.city == CityName.Aevum) { - invitedFactions.push(aevumFac); - } - - //Ishima - var ishimaFac = Factions["Ishima"]; - if (!ishimaFac.isBanned && !ishimaFac.isMember && !ishimaFac.alreadyInvited && - this.money.gte(30000000) && this.city == CityName.Ishima) { - invitedFactions.push(ishimaFac); - } - - //Volhaven - var volhavenFac = Factions["Volhaven"]; - if (!volhavenFac.isBanned && !volhavenFac.isMember && !volhavenFac.alreadyInvited && - this.money.gte(50000000) && this.city == CityName.Volhaven) { - invitedFactions.push(volhavenFac); - } - - //Speakers for the Dead - var speakersforthedeadFac = Factions["Speakers for the Dead"]; - if (!speakersforthedeadFac.isBanned && !speakersforthedeadFac.isMember && !speakersforthedeadFac.alreadyInvited && - this.hacking_skill >= 100 && this.strength >= 300 && this.defense >= 300 && - this.dexterity >= 300 && this.agility >= 300 && this.numPeopleKilled >= 30 && - this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && - !allCompanies.includes(LocationName.Sector12NSA)) { - invitedFactions.push(speakersforthedeadFac); - } - - //The Dark Army - var thedarkarmyFac = Factions["The Dark Army"]; - if (!thedarkarmyFac.isBanned && !thedarkarmyFac.isMember && !thedarkarmyFac.alreadyInvited && - this.hacking_skill >= 300 && this.strength >= 300 && this.defense >= 300 && - this.dexterity >= 300 && this.agility >= 300 && this.city == CityName.Chongqing && - this.numPeopleKilled >= 5 && this.karma <= -45 && !allCompanies.includes(LocationName.Sector12CIA) && - !allCompanies.includes(LocationName.Sector12NSA)) { - invitedFactions.push(thedarkarmyFac); - } - - //The Syndicate - var thesyndicateFac = Factions["The Syndicate"]; - if (!thesyndicateFac.isBanned && !thesyndicateFac.isMember && !thesyndicateFac.alreadyInvited && - this.hacking_skill >= 200 && this.strength >= 200 && this.defense >= 200 && - this.dexterity >= 200 && this.agility >= 200 && - (this.city == CityName.Aevum || this.city == CityName.Sector12) && - this.money.gte(10000000) && this.karma <= -90 && - !allCompanies.includes(LocationName.Sector12CIA) && !allCompanies.includes(LocationName.Sector12NSA)) { - invitedFactions.push(thesyndicateFac); - } - - //Silhouette - var silhouetteFac = Factions["Silhouette"]; - if (!silhouetteFac.isBanned && !silhouetteFac.isMember && !silhouetteFac.alreadyInvited && - (allPositions.includes("Chief Technology Officer") || - allPositions.includes("Chief Financial Officer") || - allPositions.includes("Chief Executive Officer")) && - this.money.gte(15000000) && this.karma <= -22) { - invitedFactions.push(silhouetteFac); - } - - //Tetrads - var tetradsFac = Factions["Tetrads"]; - if (!tetradsFac.isBanned && !tetradsFac.isMember && !tetradsFac.alreadyInvited && - (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || - this.city == CityName.Ishima) && this.strength >= 75 && this.defense >= 75 && - this.dexterity >= 75 && this.agility >= 75 && this.karma <= -18) { - invitedFactions.push(tetradsFac); - } - - //SlumSnakes - var slumsnakesFac = Factions["Slum Snakes"]; - if (!slumsnakesFac.isBanned && !slumsnakesFac.isMember && !slumsnakesFac.alreadyInvited && - this.strength >= 30 && this.defense >= 30 && this.dexterity >= 30 && - this.agility >= 30 && this.karma <= -9 && this.money.gte(1000000)) { - invitedFactions.push(slumsnakesFac); - } - - //Netburners - var netburnersFac = Factions["Netburners"]; - var totalHacknetRam = 0; - var totalHacknetCores = 0; - var totalHacknetLevels = 0; - for (let i = 0; i < this.hacknetNodes.length; ++i) { - if (hasHacknetServers()) { - const hserver = AllServers[this.hacknetNodes[i]]; - if (hserver) { - totalHacknetLevels += hserver.level; - totalHacknetRam += hserver.maxRam; - totalHacknetCores += hserver.cores; - } - } else { - totalHacknetLevels += this.hacknetNodes[i].level; - totalHacknetRam += this.hacknetNodes[i].ram; - totalHacknetCores += this.hacknetNodes[i].cores; - } - } - if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited && - this.hacking_skill >= 80 && totalHacknetRam >= 8 && - totalHacknetCores >= 4 && totalHacknetLevels >= 100) { - invitedFactions.push(netburnersFac); - } - - //Tian Di Hui - var tiandihuiFac = Factions["Tian Di Hui"]; - if (!tiandihuiFac.isBanned && !tiandihuiFac.isMember && !tiandihuiFac.alreadyInvited && - this.money.gte(1000000) && this.hacking_skill >= 50 && - (this.city == CityName.Chongqing || this.city == CityName.NewTokyo || - this.city == CityName.Ishima)) { - invitedFactions.push(tiandihuiFac); - } - - //CyberSec - var cybersecFac = Factions["CyberSec"]; - var cybersecServer = AllServers[SpecialServerIps[SpecialServerNames.CyberSecServer]]; - if (cybersecServer == null) { - console.log("ERROR: Could not find CyberSec Server"); - } else if (!cybersecFac.isBanned && !cybersecFac.isMember && cybersecServer.manuallyHacked && - !cybersecFac.alreadyInvited && this.hacking_skill >= 50) { - invitedFactions.push(cybersecFac); - } - - return invitedFactions; -} - - -/*************** Gang ****************/ -//Returns true if Player is in a gang and false otherwise -PlayerObject.prototype.inGang = function() { - if (this.gang == null || this.gang == undefined) {return false;} - return (this.gang instanceof Gang); -} - -PlayerObject.prototype.startGang = function(factionName, hacking) { - this.gang = new Gang(factionName, hacking); -} - -/************* BitNodes **************/ -PlayerObject.prototype.setBitNodeNumber = function(n) { - this.bitNodeN = n; -} - -PlayerObject.prototype.queueAugmentation = function(name) { - for(const i in this.queuedAugmentations) { - if(this.queuedAugmentations[i].name == name) { - console.log('tried to queue '+name+' twice, this may be a bug'); - return; - } - } - - for(const i in this.augmentations) { - if(this.augmentations[i].name == name) { - console.log('tried to queue '+name+' but we already have that aug'); - return; - } - } - - this.firstAugPurchased = true; - this.queuedAugmentations.push(new PlayerOwnedAugmentation(name)); -} - -/************* Coding Contracts **************/ -PlayerObject.prototype.gainCodingContractReward = function(reward, difficulty=1) { - if (reward == null || reward.type == null || reward == null) { - return `No reward for this contract`; - } - - /* eslint-disable no-case-declarations */ - switch (reward.type) { - case CodingContractRewardType.FactionReputation: - if (reward.name == null || !(Factions[reward.name] instanceof Faction)) { - // If no/invalid faction was designated, just give rewards to all factions - reward.type = CodingContractRewardType.FactionReputationAll; - return this.gainCodingContractReward(reward); - } - var repGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty; - Factions[reward.name].playerReputation += repGain; - return `Gained ${repGain} faction reputation for ${reward.name}`; - case CodingContractRewardType.FactionReputationAll: - const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty; - - // Ignore Bladeburners and other special factions for this calculation - const specialFactions = ["Bladeburners"]; - var factions = this.factions.slice(); - factions = factions.filter((f) => { - return !specialFactions.includes(f); - }); - - // If the player was only part of the special factions, we'll just give money - if (factions.length == 0) { - reward.type = CodingContractRewardType.Money; - return this.gainCodingContractReward(reward, difficulty); - } - - const gainPerFaction = Math.floor(totalGain / factions.length); - for (const facName of factions) { - if (!(Factions[facName] instanceof Faction)) { continue; } - Factions[facName].playerReputation += gainPerFaction; - } - return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.toString()}`; - break; - case CodingContractRewardType.CompanyReputation: - if (reward.name == null || !(Companies[reward.name] instanceof Company)) { - //If no/invalid company was designated, just give rewards to all factions - reward.type = CodingContractRewardType.FactionReputationAll; - return this.gainCodingContractReward(reward); - } - var repGain = CONSTANTS.CodingContractBaseCompanyRepGain * difficulty; - Companies[reward.name].playerReputation += repGain; - return `Gained ${repGain} company reputation for ${reward.name}`; - break; - case CodingContractRewardType.Money: - default: - var moneyGain = CONSTANTS.CodingContractBaseMoneyGain * difficulty * BitNodeMultipliers.CodingContractMoney; - this.gainMoney(moneyGain); - this.recordMoneySource(moneyGain, "codingcontract"); - return `Gained ${numeralWrapper.format(moneyGain, '$0.000a')}`; - break; - } - /* eslint-enable no-case-declarations */ -} - -PlayerObject.prototype.travel = function(to) { - if (Cities[to] == null) { - console.warn(`Player.travel() called with invalid city: ${to}`); - return false; - } - this.city = to; - - return true; -} - -PlayerObject.prototype.gotoLocation = function(to) { - if (Locations[to] == null) { - console.warn(`Player.gotoLocation() called with invalid location: ${to}`); - return false; - } - this.location = to; - - return true; -} - -PlayerObject.prototype.hasTorRouter = function() { - return SpecialServerIps.hasOwnProperty("Darkweb Server"); -} - -PlayerObject.prototype.getCurrentServer = function() { - return AllServers[this.currentServer]; -} - -PlayerObject.prototype.getHomeComputer = function() { - return AllServers[this.homeComputer]; -} - -PlayerObject.prototype.getUpgradeHomeRamCost = function() { - //Calculate how many times ram has been upgraded (doubled) - const currentRam = this.getHomeComputer().maxRam; - const numUpgrades = Math.log2(currentRam); - - //Calculate cost - //Have cost increase by some percentage each time RAM has been upgraded - const mult = Math.pow(1.58, numUpgrades); - var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost; - return cost; -} - -PlayerObject.prototype.inBladeburner = function() { - if (this.bladeburner == null) { return false; } - return (this.bladeburner instanceof Bladeburner); -} - -PlayerObject.prototype.startBladeburner = function() { - this.bladeburner = new Bladeburner({ new: true }); -} - -PlayerObject.prototype.hasCorporation = function() { - if (this.corporation == null) { return false; } - return (this.corporation instanceof Corporation); -} - -PlayerObject.prototype.startCorporation = function(corpName, additionalShares=0) { - this.corporation = new Corporation({ - name: corpName - }); - - this.corporation.totalShares += additionalShares; -} - -PlayerObject.prototype.toJSON = function() { - return Generic_toJSON("PlayerObject", this); -} - -PlayerObject.fromJSON = function(value) { - return Generic_fromJSON(PlayerObject, value.data); -} - -Reviver.constructors.PlayerObject = PlayerObject; +import Decimal from "decimal.js"; export let Player = new PlayerObject(); diff --git a/src/engine.jsx b/src/engine.jsx index 165375964..d7cd68d36 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -33,6 +33,7 @@ import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers"; import {iTutorialStart} from "./InteractiveTutorial"; import {initLiterature} from "./Literature"; +import { LocationName } from "./Locations/data/LocationNames"; import { LocationRoot } from "./Locations/ui/Root"; import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers"; import {inMission, currMission} from "./Missions"; @@ -343,12 +344,14 @@ const Engine = { MainMenuLinks.DevMenu.classList.add("active"); }, - loadLocationContent: function() { + loadLocationContent: function(initiallyInCity=true) { Engine.hideAllContent(); Engine.Display.locationContent.style.display = "block"; + MainMenuLinks.City.classList.add("active"); routing.navigateTo(Page.Location); const rootComponent = @@ -356,18 +359,42 @@ const Engine = { }, loadTravelContent: function() { + // Same as loadLocationContent() except first set the location to the travel agency, + // and make sure that the 'City' main menu link doesnt become 'active' + Engine.hideAllContent(); Player.gotoLocation(LocationName.TravelAgency); - Engine.loadLocationContent(); + Engine.Display.locationContent.style.display = "block"; + MainMenuLinks.Travel.classList.add("active"); + + routing.navigateTo(Page.Location); + const rootComponent = + ReactDOM.render(rootComponent, Engine.Display.locationContent); }, loadJobContent: function() { + // Same as loadLocationContent(), except first set the location to the job. + // Make sure that the 'City' main menu link doesnt become 'active' if (Player.companyName == "") { dialogBoxCreate("You do not currently have a job! You can visit various companies " + "in the city and try to find a job."); return; } - Player.location = Player.companyName; - Engine.loadLocationContent(); + Engine.hideAllContent(); + Player.gotoLocation(Player.companyName); + Engine.Display.locationContent.style.display = "block"; + MainMenuLinks.Job.classList.add("active"); + + routing.navigateTo(Page.Location); + const rootComponent = + ReactDOM.render(rootComponent, Engine.Display.locationContent); }, loadWorkInProgressContent: function() { @@ -469,7 +496,7 @@ const Engine = { } }, - //Helper function that hides all content + // Helper function that hides all content hideAllContent: function() { Engine.Display.terminalContent.style.display = "none"; Engine.Display.characterContent.style.display = "none"; @@ -483,6 +510,7 @@ const Engine = { Engine.Display.augmentationsContent.style.display = "none"; Engine.Display.tutorialContent.style.display = "none"; Engine.Display.locationContent.style.display = "none"; + ReactDOM.unmountComponentAtNode(Engine.Display.locationContent); Engine.Display.workInProgressContent.style.display = "none"; Engine.Display.redPillContent.style.display = "none"; Engine.Display.cinematicTextContent.style.display = "none"; @@ -507,7 +535,15 @@ const Engine = { clearResleevesPage(); clearSleevesPage(); - //Make nav menu tabs inactive + // Make nav menu tabs inactive + Engine.inactivateMainMenuLinks(); + + // Close dev menu + closeDevMenu(); + }, + + // Remove 'active' css class from all main menu links + inactivateMainMenuLinks: function() { MainMenuLinks.Terminal.classList.remove("active"); MainMenuLinks.ScriptEditor.classList.remove("active"); MainMenuLinks.ActiveScripts.classList.remove("active"); @@ -527,9 +563,6 @@ const Engine = { MainMenuLinks.Tutorial.classList.remove("active"); MainMenuLinks.Options.classList.remove("active"); MainMenuLinks.DevMenu.classList.remove("active"); - - // Close dev menu - closeDevMenu(); }, displayCharacterOverviewInfo: function() { @@ -1334,13 +1367,11 @@ const Engine = { MainMenuLinks.Travel.addEventListener("click", function() { Engine.loadTravelContent(); - MainMenuLinks.Travel.classList.add("active"); return false; }); MainMenuLinks.Job.addEventListener("click", function() { Engine.loadJobContent(); - MainMenuLinks.Job.classList.add("active"); return false; }); diff --git a/src/ui/React/AutoupdatingStdButton.tsx b/src/ui/React/AutoupdatingStdButton.tsx index a2f9d5a6a..4ef6542d4 100644 --- a/src/ui/React/AutoupdatingStdButton.tsx +++ b/src/ui/React/AutoupdatingStdButton.tsx @@ -19,6 +19,10 @@ interface IState { i: number; } +type IInnerHTMLMarkup = { + __html: string; +} + export class AutoupdatingStdButton extends React.Component { /** * Timer ID for auto-updating implementation (returned value from setInterval()) @@ -48,21 +52,27 @@ export class AutoupdatingStdButton extends React.Component { } render() { - const hasTooltip = this.props.tooltip !== ""; + const hasTooltip = this.props.tooltip != null && this.props.tooltip !== ""; let className = this.props.disabled ? "std-button-disabled" : "std-button"; if (hasTooltip) { className += " tooltip" } + // Tooltip will eb set using inner HTML + let tooltipMarkup: IInnerHTMLMarkup | null; + if (hasTooltip) { + tooltipMarkup = { + __html: this.props.tooltip! + } + } + return ( ) diff --git a/src/ui/React/StdButton.tsx b/src/ui/React/StdButton.tsx index ec3dfd5ee..d8bd957f4 100644 --- a/src/ui/React/StdButton.tsx +++ b/src/ui/React/StdButton.tsx @@ -6,28 +6,39 @@ import * as React from "react"; interface IStdButtonProps { disabled?: boolean; + id?: string; onClick?: (e: React.MouseEvent) => any; style?: object; text: string; tooltip?: string; } +type IInnerHTMLMarkup = { + __html: string; +} + export class StdButton extends React.Component { render() { - const hasTooltip = this.props.tooltip !== ""; + const hasTooltip = this.props.tooltip != null && this.props.tooltip !== ""; let className = this.props.disabled ? "std-button-disabled" : "std-button"; if (hasTooltip) { className += " tooltip"; } + // Tooltip will be set using inner HTML + let tooltipMarkup: IInnerHTMLMarkup | null; + if (hasTooltip) { + tooltipMarkup = { + __html: this.props.tooltip! + } + } + return ( - )