Fixed bugs with Location code refactor

This commit is contained in:
danielyxie 2019-04-03 17:08:11 -07:00
parent 4b95ba9ed1
commit bf9b837e31
24 changed files with 2897 additions and 2571 deletions

@ -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;

@ -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", {

@ -15,6 +15,7 @@ type IProps = {
entryPosType: CompanyPosition;
onClick: (e: React.MouseEvent<HTMLElement>) => void;
p: IPlayer;
style?: object;
text: string;
}
@ -38,6 +39,7 @@ export class ApplyToJobButton extends React.Component<IProps, any> {
return (
<StdButton
onClick={this.props.onClick}
style={this.props.style}
text={this.props.text}
tooltip={this.getJobRequirementTooltip()}
/>

@ -19,8 +19,8 @@ export class LocationCity extends React.Component<IProps, any> {
render() {
const locationButtons = this.props.city.locations.map((locName) => {
return (
<li>
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} key={locName} />
<li key={locName}>
<StdButton onClick={this.props.enterLocation.bind(this, locName)} text={locName} />
</li>
)
});

@ -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<IProps, any> {
type IState = {
employedHere: boolean;
}
export class CompanyLocation extends React.Component<IProps, IState> {
/**
* 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<IProps, any> {
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<IProps, any> {
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<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForAgentJob();
this.checkIfEmployedHere();
}
applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessConsultantJob();
this.checkIfEmployedHere();
}
applyForBusinessJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForBusinessJob();
this.checkIfEmployedHere();
}
applyForEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForEmployeeJob();
this.checkIfEmployedHere();
}
applyForItJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForItJob();
this.checkIfEmployedHere();
}
applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeEmployeeJob();
this.checkIfEmployedHere();
}
applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForPartTimeWaiterJob();
this.checkIfEmployedHere();
}
applyForSecurityJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSecurityJob();
this.checkIfEmployedHere();
}
applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareConsultantJob();
this.checkIfEmployedHere();
}
applyForSoftwareJob(e: React.MouseEvent<HTMLElement>) {
if (!e.isTrusted) { return false; }
this.props.p.applyForSoftwareJob();
this.checkIfEmployedHere();
}
applyForWaiterJob(e: React.MouseEvent<HTMLElement>) {
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<HTMLElement>) {
@ -133,9 +189,54 @@ export class CompanyLocation extends React.Component<IProps, any> {
beginInfiltration(this.props.locName, data.startingSecurityLevel, data.baseRewardValue, data.maxClearanceLevel, data.difficulty);
}
work(e: React.MouseEvent<HTMLElement>) {
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 (
<div>
{
isEmployedHere &&
<div>
<p>Job Title: {this.jobTitle}</p>
<p>--------------------</p>
<p className={"tooltip"}>
Company reputation: {numeralWrapper.format(this.company.playerReputation, "0,0.000")}
<span className={"tooltiptext"}>
You will earn ${numeralWrapper.format(favorGain[0], "0,0")} company
favor upon resetting after installing Augmentations
</span>
</p>
<p>--------------------</p>
<p className={"tooltip"}>
Company Favor: {numeralWrapper.format(this.company.favor, "0,0")}
<span className={"tooltiptext"}>
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.
</span>
</p>
<StdButton
id={"foo-work-button-id"}
onClick={this.work}
style={this.btnStyle}
text={"Work"}
/>
</div>
}
{
this.company.hasAgentPositions() &&
<ApplyToJobButton
@ -143,6 +244,7 @@ export class CompanyLocation extends React.Component<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
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<IProps, any> {
(this.location.infiltrationData != null) &&
<StdButton
onClick={this.startInfiltration}
style={this.btnStyle}
text={"Infiltration Company"}
/>
}

@ -33,6 +33,17 @@ type IProps = {
}
export class GenericLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
content.push(
<CompanyLocation
engine={this.props.engine}
key={"companylocation"}
locName={this.props.loc.name}
p={this.props.p}
/>
@ -53,6 +65,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.Gym)) {
content.push(
<GymLocation
key={"gymlocation"}
loc={this.props.loc}
p={this.props.p}
/>
@ -62,6 +75,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.Hospital)) {
content.push(
<HospitalLocation
key={"hospitallocation"}
p={this.props.p}
/>
)
@ -70,6 +84,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.Slums)) {
content.push(
<SlumsLocation
key={"slumslocation"}
p={this.props.p}
/>
)
@ -79,6 +94,7 @@ export class GenericLocation extends React.Component<IProps, any> {
content.push(
<SpecialLocation
engine={this.props.engine}
key={"speciallocation"}
loc={this.props.loc}
p={this.props.p}
/>
@ -88,6 +104,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.TechVendor)) {
content.push(
<TechVendorLocation
key={"techvendorlocation"}
loc={this.props.loc}
p={this.props.p}
/>
@ -97,6 +114,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.TravelAgency)) {
content.push(
<TravelAgencyLocation
key={"travelagencylocation"}
p={this.props.p}
travel={this.props.travel}
/>
@ -106,6 +124,7 @@ export class GenericLocation extends React.Component<IProps, any> {
if (this.props.loc.types.includes(LocationType.University)) {
content.push(
<UniversityLocation
key={"universitylocation"}
loc={this.props.loc}
p={this.props.p}
/>
@ -120,8 +139,7 @@ export class GenericLocation extends React.Component<IProps, any> {
return (
<div>
<StdButton onClick={this.props.returnToCity} text={"Return to world"} />
<br />
<StdButton onClick={this.props.returnToCity} style={this.btnStyle} text={"Return to World"} />
<h1>{this.props.loc.name}</h1>
{locContent}
</div>

@ -19,9 +19,16 @@ type IProps = {
}
export class GymLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
<div>
<StdButton
onClick={this.trainStrength}
style={this.btnStyle}
text={`Train Strength (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainDefense}
style={this.btnStyle}
text={`Train Defense (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainDexterity}
style={this.btnStyle}
text={`Train Dexterity (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
<StdButton
onClick={this.trainAgility}
style={this.btnStyle}
text={`Train Agility (${numeralWrapper.formatMoney(cost)} / sec)`}
/>
</div>

@ -18,9 +18,16 @@ type IProps = {
}
export class HospitalLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
return (
<AutoupdatingStdButton
onClick={this.getHealed}
style={this.btnStyle}
text={`Get treatment for wounds - ${numeralWrapper.formatMoney(cost)}`}
/>
)

@ -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<IProps, IState> {
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<IProps, IState> {
if (this.props.p.travel(to)) {
this.setState({
inCity: true,
city: to
});
}

@ -16,9 +16,16 @@ type IProps = {
}
export class SlumsLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
robStore(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.RobSTore.commit(this.props.p);
Crimes.RobStore.commit(this.props.p);
}
mug(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { return; }
Crimes.mug.commit(this.props.p);
Crimes.Mug.commit(this.props.p);
}
larceny(e: React.MouseEvent<HTMLElement>): void {
@ -112,72 +119,84 @@ export class SlumsLocation extends React.Component<IProps, any> {
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.shoplift}
style={this.btnStyle}
text={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
tooltip={"Attempt to shoplift from a low-end retailer"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.robStore}
style={this.btnStyle}
text={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
tooltip={"Attempt to commit armed robbery on a high-end store"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.mug}
style={this.btnStyle}
text={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
tooltip={"Attempt to mug a random person on the street"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.larceny}
style={this.btnStyle}
text={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
tooltip={"Attempt to rob property from someone's house"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.dealDrugs}
style={this.btnStyle}
text={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
tooltip={"Attempt to deal drugs"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.bondForgery}
style={this.btnStyle}
text={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
tooltip={"Attempt to forge corporate bonds"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.traffickArms}
style={this.btnStyle}
text={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
tooltip={"Attempt to smuggle illegal arms into the city"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.homicide}
style={this.btnStyle}
text={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
tooltip={"Attempt to murder a random person on the street"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.grandTheftAuto}
style={this.btnStyle}
text={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
tooltip={"Attempt to commit grand theft auto"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.kidnap}
style={this.btnStyle}
text={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
tooltip={"Attempt to kidnap and ransom a high-profile-target"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.assassinate}
style={this.btnStyle}
text={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
tooltip={"Attempt to assassinate a high-profile target"}
/>
<AutoupdatingStdButton
intervalTime={5e3}
onClick={this.heist}
style={this.btnStyle}
text={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
tooltip={"Attempt to pull off the ultimate heist"}
/>

@ -35,9 +35,16 @@ type IState = {
}
export class SpecialLocation extends React.Component<IProps, IState> {
/**
* 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<IProps, IState> {
}
renderBladeburner(): React.ReactNode {
if (!this.props.p.canAccessBladeburner()) { return null; }
const text = this.state.inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
return (
<StdButton
onClick={this.handleBladeburner}
style={this.btnStyle}
text={text}
/>
)
}
renderCreateCorporation(): React.ReactNode {
if (!this.props.p.canAccessCorporation()) { return null; }
return (
<AutoupdatingStdButton
disabled={this.props.p.hasCorporation()}
disabled={!this.props.p.canAccessCorporation() || this.props.p.hasCorporation()}
onClick={this.createCorporationPopup}
style={this.btnStyle}
text={"Create a Corporation"}
/>
)
}
renderResleeving(): React.ReactNode {
if (!this.props.p.canAccessResleeving()) { return null; }
return (
<StdButton
onClick={this.handleResleeving}
style={this.btnStyle}
text={"Re-Sleeve"}
/>
)

@ -25,9 +25,16 @@ type IProps = {
}
export class TechVendorLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
<StdButton
key={i}
onClick={() => 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<IProps, any> {
{
this.state.torPurchased ? (
<StdButtonPurchased
style={this.btnStyle}
text={"TOR Router - Purchased"}
/>
) : (
<StdButton
onClick={this.purchaseTorRouter}
style={this.btnStyle}
text={`Purchase TOR Router - ${numeralWrapper.formatMoney(CONSTANTS.TorRouterCost)}`}
/>
)
@ -82,10 +92,12 @@ export class TechVendorLocation extends React.Component<IProps, any> {
}
<StdButton
onClick={this.createUpgradeHomeRamPopup}
style={this.btnStyle}
text={`Purchase additional RAM for Home computer`}
/>
<StdButton
onClick={this.createUpgradeHomeCoresPopup}
style={this.btnStyle}
text={`Purchase additional Core for Home computer`}
/>
</div>

@ -20,8 +20,15 @@ type IProps = {
}
export class TravelAgencyLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
<StdButton
key={city}
onClick={createTravelPopup.bind(null, city, this.props.travel)}
style={this.btnStyle}
text={`Travel to ${city}`}
/>
)
@ -44,8 +52,8 @@ export class TravelAgencyLocation extends React.Component<IProps, any> {
return (
<div>
<p>
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)}
</p>
{travelBtns}
</div>

@ -19,10 +19,18 @@ type IProps = {
}
export class UniversityLocation extends React.Component<IProps, any> {
/**
* 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<IProps, any> {
<div>
<StdButton
onClick={this.study}
style={this.btnStyle}
text={`Study Computer Science (free)`}
/>
<StdButton
onClick={this.dataStructures}
style={this.btnStyle}
text={`Take Data Structures course (${numeralWrapper.formatMoney(dataStructuresCost)} / sec)`}
/>
<StdButton
onClick={this.networks}
style={this.btnStyle}
text={`Take Networks course (${numeralWrapper.formatMoney(networksCost)} / sec)`}
/>
<StdButton
onClick={this.algorithms}
style={this.btnStyle}
text={`Take Algorithms course (${numeralWrapper.formatMoney(algorithmsCost)} / sec)`}
/>
<StdButton
onClick={this.management}
style={this.btnStyle}
text={`Take Management course (${numeralWrapper.formatMoney(managementCost)} / sec)`}
/>
<StdButton
onClick={this.leadership}
style={this.btnStyle}
text={`Take Leadership course (${numeralWrapper.formatMoney(leadershipCost)} / sec)`}
/>
</div>

@ -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<string>;
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;
}

@ -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;

@ -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 });
}

@ -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;
}

File diff suppressed because it is too large Load Diff

@ -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;
}

File diff suppressed because it is too large Load Diff

@ -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 = <LocationRoot
initiallyInCity={initiallyInCity}
engine={Engine}
p={Player}
/>
@ -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 = <LocationRoot
initiallyInCity={false}
engine={Engine}
p={Player}
/>
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 = <LocationRoot
initiallyInCity={false}
engine={Engine}
p={Player}
/>
ReactDOM.render(rootComponent, Engine.Display.locationContent);
},
loadWorkInProgressContent: function() {
@ -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";
@ -508,6 +536,14 @@ const Engine = {
clearSleevesPage();
// 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;
});

@ -19,6 +19,10 @@ interface IState {
i: number;
}
type IInnerHTMLMarkup = {
__html: string;
}
export class AutoupdatingStdButton extends React.Component<IProps, IState> {
/**
* Timer ID for auto-updating implementation (returned value from setInterval())
@ -48,21 +52,27 @@ export class AutoupdatingStdButton extends React.Component<IProps, IState> {
}
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 (
<button className={className} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
{
hasTooltip &&
<span className={"tooltiptext"}>
{this.props.tooltip}
</span>
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
}
</button>
)

@ -6,28 +6,39 @@ import * as React from "react";
interface IStdButtonProps {
disabled?: boolean;
id?: string;
onClick?: (e: React.MouseEvent<HTMLElement>) => any;
style?: object;
text: string;
tooltip?: string;
}
type IInnerHTMLMarkup = {
__html: string;
}
export class StdButton extends React.Component<IStdButtonProps, any> {
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 (
<button className={className} onClick={this.props.onClick} style={this.props.style}>
<button className={className} id={this.props.id} onClick={this.props.onClick} style={this.props.style}>
{this.props.text}
{
hasTooltip &&
<span className={"tooltiptext"}>
{this.props.tooltip}
</span>
<span className={"tooltiptext"} dangerouslySetInnerHTML={tooltipMarkup!}></span>
}
</button>
)