mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-02-17 02:22:23 +01:00
big work
This commit is contained in:
@ -1,16 +1,17 @@
|
||||
import React from "react";
|
||||
import { hackWorldDaemon } from "../../RedPill";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
export function BitFlumePopup(props: IProps): React.ReactElement {
|
||||
function flume(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true, false);
|
||||
props.router.toBitVerse(true, false);
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
return (
|
||||
|
@ -1,18 +1,22 @@
|
||||
import React, { useState } from "react";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { enterBitNode } from "../../RedPill";
|
||||
import { PortalPopup } from "./PortalPopup";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IPortalProps {
|
||||
n: number;
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
const router = use.Router();
|
||||
const bitNode = BitNodes[`BitNode${props.n}`];
|
||||
if (bitNode == null) {
|
||||
return <>O</>;
|
||||
@ -32,6 +36,7 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
n: props.n,
|
||||
level: props.level,
|
||||
enter: props.enter,
|
||||
router: router,
|
||||
destroyedBitNode: props.destroyedBitNode,
|
||||
flume: props.flume,
|
||||
popupId: popupId,
|
||||
@ -57,18 +62,20 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
|
||||
interface IProps {
|
||||
flume: boolean;
|
||||
destroyedBitNodeNum: number;
|
||||
quick: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
}
|
||||
|
||||
export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const enter = enterBitNode;
|
||||
const destroyed = player.bitNodeN;
|
||||
const [destroySequence, setDestroySequence] = useState(true && !props.quick);
|
||||
|
||||
// Update NextSourceFileFlags
|
||||
const nextSourceFileFlags = SourceFileFlags.slice();
|
||||
if (!props.flume) {
|
||||
if (nextSourceFileFlags[props.destroyedBitNodeNum] < 3) ++nextSourceFileFlags[props.destroyedBitNodeNum];
|
||||
if (nextSourceFileFlags[destroyed] < 3) ++nextSourceFileFlags[destroyed];
|
||||
}
|
||||
|
||||
if (destroySequence) {
|
||||
@ -84,7 +91,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
"0020 7124696B 0000FF69 74652E6F FFFF1111",
|
||||
"----------------------------------------",
|
||||
"Failsafe initiated...",
|
||||
`Restarting BitNode-${props.destroyedBitNodeNum}...`,
|
||||
`Restarting BitNode-${destroyed}...`,
|
||||
"...........",
|
||||
"...........",
|
||||
"[ERROR] FAILED TO AUTOMATICALLY REBOOT BITNODE",
|
||||
@ -96,6 +103,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
"..............................................",
|
||||
]}
|
||||
onDone={() => setDestroySequence(false)}
|
||||
auto={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -116,16 +124,16 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
<pre> \| O | |_/ |\| \ O \__| \_| | O |/ </pre>
|
||||
<pre> | | |_/ | | \| / | \_| | | </pre>
|
||||
<pre> \| / \| | / / \ |/ </pre>
|
||||
<pre> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | </pre>
|
||||
<pre> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> </pre>
|
||||
<pre> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </pre>
|
||||
<pre> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </pre>
|
||||
<pre> | | | / / \ \ | | | </pre>
|
||||
<pre> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> \ | |/ </pre>
|
||||
<pre> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </pre>
|
||||
<pre> \ | / / | | \ \ | / </pre>
|
||||
<pre> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> PMUJ/ / </pre>
|
||||
<pre> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </pre>
|
||||
<pre> \|| | | | | | | | | ||/ </pre>
|
||||
<pre> \| \_ | | | | | | _/ |/ </pre>
|
||||
<pre> \ \| / \ / \ |/ / </pre>
|
||||
<pre> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={props.enter} flume={props.flume} destroyedBitNode={props.destroyedBitNodeNum} /> </pre>
|
||||
<pre> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </pre>
|
||||
<pre> | | | | | | | | </pre>
|
||||
<pre> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </pre>
|
||||
<br />
|
||||
|
@ -1,13 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
import { BitNodes } from "../BitNode";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
interface IProps {
|
||||
n: number;
|
||||
level: number;
|
||||
destroyedBitNode: number;
|
||||
flume: boolean;
|
||||
enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
router: IRouter;
|
||||
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
@ -33,7 +35,7 @@ export function PortalPopup(props: IProps): React.ReactElement {
|
||||
<button
|
||||
className="std-button"
|
||||
onClick={() => {
|
||||
props.enter(props.flume, props.destroyedBitNode, props.n);
|
||||
props.enter(props.router, props.flume, props.destroyedBitNode, props.n);
|
||||
removePopup(props.popupId);
|
||||
}}
|
||||
>
|
||||
|
@ -15,6 +15,7 @@ import { Skill } from "./Skill";
|
||||
import { City } from "./City";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { ConsoleHelpText } from "./data/Help";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
import { getRandomInt } from "../../utils/helpers/getRandomInt";
|
||||
@ -25,7 +26,7 @@ import { addOffset } from "../../utils/helpers/addOffset";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { Factions, factionExists } from "../Faction/Factions";
|
||||
import { calculateHospitalizationCost } from "../Hospital/Hospital";
|
||||
import { hackWorldDaemon, redPillFlag } from "../RedPill";
|
||||
import { redPillFlag } from "../RedPill";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
@ -1203,7 +1204,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
completeAction(player: IPlayer): void {
|
||||
completeAction(router: IRouter, player: IPlayer): void {
|
||||
switch (this.action.type) {
|
||||
case ActionTypes["Contract"]:
|
||||
case ActionTypes["Operation"]: {
|
||||
@ -1338,7 +1339,7 @@ export class Bladeburner implements IBladeburner {
|
||||
// Operation Daedalus
|
||||
if (action.name === "Operation Daedalus") {
|
||||
this.resetAction();
|
||||
return hackWorldDaemon(player.bitNodeN);
|
||||
return router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
if (this.logging.blackops) {
|
||||
@ -1540,7 +1541,7 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
}
|
||||
|
||||
processAction(player: IPlayer, seconds: number): void {
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void {
|
||||
if (this.action.type === ActionTypes["Idle"]) return;
|
||||
if (this.actionTimeToComplete <= 0) {
|
||||
throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
|
||||
@ -1555,7 +1556,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.actionTimeOverflow = 0;
|
||||
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
|
||||
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
|
||||
return this.completeAction(player);
|
||||
return this.completeAction(router, player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1888,10 +1889,10 @@ export class Bladeburner implements IBladeburner {
|
||||
});
|
||||
}
|
||||
|
||||
process(player: IPlayer): void {
|
||||
process(router: IRouter, player: IPlayer): void {
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (redPillFlag === false && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return hackWorldDaemon(player.bitNodeN);
|
||||
return router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
// If the Player starts doing some other actions, set action to idle and alert
|
||||
@ -1958,7 +1959,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.randomEventCounter += getRandomInt(240, 600);
|
||||
}
|
||||
|
||||
this.processAction(player, seconds);
|
||||
this.processAction(router, player, seconds);
|
||||
|
||||
// Automation
|
||||
if (this.automateEnabled) {
|
||||
|
@ -3,6 +3,7 @@ import { City } from "./City";
|
||||
import { Skill } from "./Skill";
|
||||
import { IAction } from "./IAction";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
|
||||
export interface IBladeburner {
|
||||
@ -103,11 +104,11 @@ export interface IBladeburner {
|
||||
completeOperation(success: boolean): void;
|
||||
getActionObject(actionId: IActionIdentifier): IAction | null;
|
||||
completeContract(success: boolean): void;
|
||||
completeAction(player: IPlayer): void;
|
||||
completeAction(router: IRouter, player: IPlayer): void;
|
||||
changeRank(player: IPlayer, change: number): void;
|
||||
processAction(player: IPlayer, seconds: number): void;
|
||||
processAction(router: IRouter, player: IPlayer, seconds: number): void;
|
||||
calculateStaminaGainPerSecond(player: IPlayer): number;
|
||||
calculateMaxStamina(player: IPlayer): void;
|
||||
create(): void;
|
||||
process(player: IPlayer): void;
|
||||
process(router: IRouter, player: IPlayer): void;
|
||||
}
|
||||
|
42
src/Bladeburner/ui/BladeburnerCinematic.tsx
Normal file
42
src/Bladeburner/ui/BladeburnerCinematic.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React from "react";
|
||||
import { use } from "../../ui/Context";
|
||||
import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
||||
export function BladeburnerCinematic(): React.ReactElement {
|
||||
const router = use.Router();
|
||||
return (
|
||||
<CinematicText
|
||||
lines={[
|
||||
"In the middle of the 21st century, OmniTek Incorporated advanced robot evolution ",
|
||||
"with their Synthoids (synthetic androids), a being virtually identical to a human.",
|
||||
"------",
|
||||
"Their sixth-generation Synthoids, called MK-VI, were stronger, faster, and more ",
|
||||
"intelligent than humans. Many argued that the MK-VI Synthoids were the first ",
|
||||
"example of sentient AI.",
|
||||
"------",
|
||||
"Unfortunately, in 2070 a terrorist group called Ascendis Totalis hacked into OmniTek and ",
|
||||
"uploaded a rogue AI into their Synthoid manufacturing facilities.",
|
||||
"------",
|
||||
"The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating ",
|
||||
"the deadliest conflict in human history. This dark chapter is now known as the Synthoid Uprising.",
|
||||
"------",
|
||||
"In the aftermath of the Uprising, further manufacturing of Synthoids with advanced AI ",
|
||||
"was banned. MK-VI Synthoids that did not have the rogue Ascendis Totalis AI were ",
|
||||
"allowed to continue their existence.",
|
||||
"------",
|
||||
"The intelligence community believes that not all of the rogue MK-VI Synthoids from the Uprising were ",
|
||||
"found and destroyed, and that many of them are blending in as normal humans in society today. ",
|
||||
"As a result, many nations have created Bladeburner divisions, special units that are tasked with ",
|
||||
"investigating and dealing with Synthoid threats.",
|
||||
]}
|
||||
onDone={() => {
|
||||
router.toTerminal();
|
||||
dialogBoxCreate(
|
||||
"Visit the National Security Agency (NSA) to apply for their Bladeburner " +
|
||||
"division! You will need 100 of each combat stat before doing this.",
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -3,17 +3,16 @@ import { Stats } from "./Stats";
|
||||
import { Console } from "./Console";
|
||||
import { AllPages } from "./AllPages";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
engine: IEngine;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
export function BladeburnerRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
return (
|
||||
<div className="bladeburner-container">
|
||||
<div style={{ height: "60%", display: "block", position: "relative" }}>
|
||||
@ -25,9 +24,9 @@ export function Root(props: IProps): React.ReactElement {
|
||||
border: "1px solid white",
|
||||
}}
|
||||
>
|
||||
<Stats bladeburner={props.bladeburner} player={props.player} engine={props.engine} />
|
||||
<Stats bladeburner={props.bladeburner} player={player} router={router} />
|
||||
</div>
|
||||
<Console bladeburner={props.bladeburner} player={props.player} />
|
||||
<Console bladeburner={props.bladeburner} player={player} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@ -39,7 +38,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<AllPages bladeburner={props.bladeburner} player={props.player} />
|
||||
<AllPages bladeburner={props.bladeburner} player={player} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -2,21 +2,21 @@ import React, { useState, useEffect } from "react";
|
||||
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
import { BladeburnerConstants } from "../data/Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { StatsTable } from "../../ui/React/StatsTable";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { joinFaction, displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { joinFaction } from "../../Faction/FactionHelpers";
|
||||
import { IBladeburner } from "../IBladeburner";
|
||||
|
||||
import { TravelPopup } from "./TravelPopup";
|
||||
|
||||
interface IProps {
|
||||
bladeburner: IBladeburner;
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
@ -72,8 +72,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
function openFaction(): void {
|
||||
const faction = Factions["Bladeburners"];
|
||||
if (faction.isMember) {
|
||||
props.engine.loadFactionContent();
|
||||
displayFactionContent("Bladeburners");
|
||||
props.router.toFaction(faction);
|
||||
} else {
|
||||
if (props.bladeburner.rank >= BladeburnerConstants.RankNeededForFaction) {
|
||||
joinFaction(faction);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { IPlayer } from "./PersonObjects/IPlayer";
|
||||
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { IEngine } from "./IEngine";
|
||||
import { IRouter } from "./ui/Router";
|
||||
|
||||
import React from "react";
|
||||
import { TTheme as Theme } from "./ui/React/Theme";
|
||||
@ -24,6 +25,7 @@ import { TimeSkip } from "./DevMenu/ui/TimeSkip";
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
engine: IEngine;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function DevMenuRoot(props: IProps): React.ReactElement {
|
||||
@ -31,7 +33,7 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
|
||||
<Theme>
|
||||
<>
|
||||
<h1>Development Menu - Only meant to be used for testing/debugging</h1>
|
||||
<General player={props.player} />
|
||||
<General player={props.player} router={props.router} />
|
||||
<Stats player={props.player} />
|
||||
<Factions player={props.player} />
|
||||
<Augmentations player={props.player} />
|
||||
|
@ -8,10 +8,11 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { hackWorldDaemon } from "../../RedPill";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function General(props: IProps): React.ReactElement {
|
||||
@ -26,19 +27,19 @@ export function General(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function quickB1tFlum3(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true, true);
|
||||
props.router.toBitVerse(true, true);
|
||||
}
|
||||
|
||||
function b1tflum3(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, true);
|
||||
props.router.toBitVerse(true, false);
|
||||
}
|
||||
|
||||
function quickHackW0r1dD43m0n(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN, false, true);
|
||||
props.router.toBitVerse(false, true);
|
||||
}
|
||||
|
||||
function hackW0r1dD43m0n(): void {
|
||||
hackWorldDaemon(props.player.bitNodeN);
|
||||
props.router.toBitVerse(false, false);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -30,7 +30,7 @@ export function TimeSkip(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<Accordion>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<h2>Sleeves</h2>
|
||||
<h2>Time skip</h2>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Button onClick={timeskip(60 * 1000)}>1 minute</Button>
|
||||
|
1
src/Faction/FactionHelpers.d.ts
vendored
1
src/Faction/FactionHelpers.d.ts
vendored
@ -4,6 +4,5 @@ import { Faction } from "../Faction/Faction";
|
||||
export declare function getNextNeurofluxLevel(): number;
|
||||
export declare function hasAugmentationPrereqs(aug: Augmentation): boolean;
|
||||
export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void;
|
||||
export declare function displayFactionContent(factionName: string, initiallyOnAugmentationsPage: boolean = false);
|
||||
export declare function joinFaction(faction: Faction): void;
|
||||
export declare function startHackingMission(faction: Faction): void;
|
||||
|
@ -1,14 +1,9 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { FactionRoot } from "./ui/FactionRoot";
|
||||
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { Engine } from "../engine";
|
||||
|
||||
import { Faction } from "./Faction";
|
||||
import { Factions } from "./Factions";
|
||||
import { HackingMission, setInMission } from "../Missions";
|
||||
@ -65,29 +60,6 @@ export function startHackingMission(faction) {
|
||||
mission.init();
|
||||
}
|
||||
|
||||
//Displays the HTML content for a specific faction
|
||||
export function displayFactionContent(factionName, initiallyOnAugmentationsPage = false) {
|
||||
const faction = Factions[factionName];
|
||||
if (faction == null) {
|
||||
throw new Error(`Invalid factionName passed into displayFactionContent(): ${factionName}`);
|
||||
}
|
||||
|
||||
if (!faction.isMember) {
|
||||
throw new Error(`Not a member of this faction. Cannot display faction information`);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<FactionRoot
|
||||
engine={Engine}
|
||||
initiallyOnAugmentationsPage={initiallyOnAugmentationsPage}
|
||||
faction={faction}
|
||||
p={Player}
|
||||
startHackingMissionFn={startHackingMission}
|
||||
/>,
|
||||
Engine.Display.content,
|
||||
);
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug) {
|
||||
@ -187,9 +159,6 @@ export function purchaseAugmentation(aug, fac, sing = false) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Force a rerender of the Augmentations page
|
||||
displayFactionContent(fac.name, true);
|
||||
} else {
|
||||
dialogBoxCreate(
|
||||
"Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
|
@ -1,52 +1,37 @@
|
||||
/**
|
||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
routeToMainPage: () => void;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
sortOrder: PurchaseAugmentationsOrderSetting;
|
||||
};
|
||||
|
||||
const infoStyleMarkup = {
|
||||
width: "70%",
|
||||
};
|
||||
|
||||
export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
// Flag for whether the player has a gang with this faction
|
||||
isPlayersGang: boolean;
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
const isPlayersGang = player.inGang() && player.getGangName() === props.faction.name;
|
||||
|
||||
this.isPlayersGang = props.p.inGang() && props.p.getGangName() === props.faction.name;
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
sortOrder: PurchaseAugmentationsOrderSetting.Default,
|
||||
};
|
||||
|
||||
this.rerender = this.rerender.bind(this);
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
getAugs(): string[] {
|
||||
if (this.isPlayersGang) {
|
||||
function getAugs(): string[] {
|
||||
if (isPlayersGang) {
|
||||
const augs: string[] = [];
|
||||
for (const augName in Augmentations) {
|
||||
const aug = Augmentations[augName];
|
||||
@ -57,25 +42,25 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
|
||||
return augs;
|
||||
} else {
|
||||
return this.props.faction.augmentations.slice();
|
||||
return props.faction.augmentations.slice();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSorted(): string[] {
|
||||
function getAugsSorted(): string[] {
|
||||
switch (Settings.PurchaseAugmentationsOrder) {
|
||||
case PurchaseAugmentationsOrderSetting.Cost: {
|
||||
return this.getAugsSortedByCost();
|
||||
return getAugsSortedByCost();
|
||||
}
|
||||
case PurchaseAugmentationsOrderSetting.Reputation: {
|
||||
return this.getAugsSortedByReputation();
|
||||
return getAugsSortedByReputation();
|
||||
}
|
||||
default:
|
||||
return this.getAugsSortedByDefault();
|
||||
return getAugsSortedByDefault();
|
||||
}
|
||||
}
|
||||
|
||||
getAugsSortedByCost(): string[] {
|
||||
const augs = this.getAugs();
|
||||
function getAugsSortedByCost(): string[] {
|
||||
const augs = getAugs();
|
||||
augs.sort((augName1, augName2) => {
|
||||
const aug1 = Augmentations[augName1],
|
||||
aug2 = Augmentations[augName2];
|
||||
@ -89,8 +74,8 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByReputation(): string[] {
|
||||
const augs = this.getAugs();
|
||||
function getAugsSortedByReputation(): string[] {
|
||||
const augs = getAugs();
|
||||
augs.sort((augName1, augName2) => {
|
||||
const aug1 = Augmentations[augName1],
|
||||
aug2 = Augmentations[augName2];
|
||||
@ -103,88 +88,70 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
return augs;
|
||||
}
|
||||
|
||||
getAugsSortedByDefault(): string[] {
|
||||
return this.getAugs();
|
||||
function getAugsSortedByDefault(): string[] {
|
||||
return getAugs();
|
||||
}
|
||||
|
||||
switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void {
|
||||
function switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void {
|
||||
Settings.PurchaseAugmentationsOrder = newOrder;
|
||||
this.rerender();
|
||||
rerender();
|
||||
}
|
||||
|
||||
rerender(): void {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
};
|
||||
});
|
||||
}
|
||||
const augs = getAugsSorted();
|
||||
const purchasable = augs.filter(
|
||||
(aug: string) =>
|
||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
|
||||
render(): React.ReactNode {
|
||||
const augs = this.getAugsSorted();
|
||||
const purchasable = augs.filter(
|
||||
(aug: string) => aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!this.props.p.augmentations.some((a) => a.name === aug) &&
|
||||
!this.props.p.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
const purchaseableAugmentation = (aug: string): React.ReactNode => {
|
||||
return <PurchaseableAugmentation augName={aug} faction={props.faction} key={aug} p={player} rerender={rerender} />;
|
||||
};
|
||||
|
||||
const purchaseableAugmentation = (aug: string): React.ReactNode => {
|
||||
return (
|
||||
<PurchaseableAugmentation
|
||||
augName={aug}
|
||||
faction={this.props.faction}
|
||||
key={aug}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||
|
||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||
|
||||
let ownedElem = <></>;
|
||||
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
|
||||
if (owned.length !== 0) {
|
||||
ownedElem = (
|
||||
<>
|
||||
<br />
|
||||
<h2>Purchased Augmentations</h2>
|
||||
<p style={infoStyleMarkup}>This factions also offers these augmentations but you already own them.</p>
|
||||
{owned.map((aug) => purchaseableAugmentation(aug))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={this.props.routeToMainPage} text={"Back"} />
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p style={infoStyleMarkup}>
|
||||
These are all of the Augmentations that are available to purchase from {this.props.faction.name}.
|
||||
Augmentations are powerful upgrades that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} />
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => this.switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
let ownedElem = <></>;
|
||||
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
|
||||
if (owned.length !== 0) {
|
||||
ownedElem = (
|
||||
<>
|
||||
<br />
|
||||
{augListElems}
|
||||
{ownedElem}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
<h2>Purchased Augmentations</h2>
|
||||
<p>This factions also offers these augmentations but you already own them.</p>
|
||||
{owned.map((aug) => purchaseableAugmentation(aug))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton onClick={props.routeToMainPage} text={"Back"} />
|
||||
<h1>Faction Augmentations</h1>
|
||||
<p>
|
||||
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
||||
powerful upgrades that will enhance your abilities.
|
||||
</p>
|
||||
<StdButton onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} />
|
||||
<StdButton
|
||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}
|
||||
text={"Sort by Reputation"}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}
|
||||
text={"Sort by Default Order"}
|
||||
/>
|
||||
<br />
|
||||
{augListElems}
|
||||
{ownedElem}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,58 +1,66 @@
|
||||
/**
|
||||
* React Component for the popup used to create a new gang.
|
||||
*/
|
||||
import React from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React from "react";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface ICreateGangPopupProps {
|
||||
popupId: string;
|
||||
facName: string;
|
||||
p: IPlayer;
|
||||
engine: IEngine;
|
||||
}
|
||||
interface ICreateGangPopupProps {
|
||||
popupId: string;
|
||||
facName: string;
|
||||
}
|
||||
|
||||
export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement {
|
||||
|
||||
const combatGangText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const combatGangText =
|
||||
"This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
|
||||
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
|
||||
"is more important. However, well-managed combat gangs can progress faster than hacking ones.";
|
||||
|
||||
const hackingGangText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
const hackingGangText =
|
||||
"This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " +
|
||||
"Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " +
|
||||
"is not as important.";
|
||||
|
||||
function isHacking(): boolean {
|
||||
return ["NiteSec", "The Black Hand"].includes(props.facName);
|
||||
}
|
||||
function isHacking(): boolean {
|
||||
return ["NiteSec", "The Black Hand"].includes(props.facName);
|
||||
}
|
||||
|
||||
function createGang(): void {
|
||||
props.p.startGang(props.facName, isHacking());
|
||||
removePopup(props.popupId);
|
||||
props.engine.loadGangContent();
|
||||
}
|
||||
function createGang(): void {
|
||||
player.startGang(props.facName, isHacking());
|
||||
removePopup(props.popupId);
|
||||
router.toGang();
|
||||
}
|
||||
|
||||
function onKeyUp(event: React.KeyboardEvent): void {
|
||||
if (event.keyCode === 13) createGang();
|
||||
}
|
||||
function onKeyUp(event: React.KeyboardEvent): void {
|
||||
if (event.keyCode === 13) createGang();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
Would you like to create a new Gang with {props.facName}?
|
||||
<br/>
|
||||
<br/>
|
||||
Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It also resets your reputation with this faction.
|
||||
<br/>
|
||||
<br/>
|
||||
{ (isHacking()) ? hackingGangText : combatGangText }
|
||||
<br/>
|
||||
<br/>
|
||||
Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each of these Factions have all Augmentations available.
|
||||
<div className="popup-box-input-div" >
|
||||
<StdButton onClick={createGang} onKeyUp={onKeyUp} text="Create Gang" style={{float: "right"}} autoFocus={true}/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
Would you like to create a new Gang with {props.facName}?
|
||||
<br />
|
||||
<br />
|
||||
Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It
|
||||
also resets your reputation with this faction.
|
||||
<br />
|
||||
<br />
|
||||
{isHacking() ? hackingGangText : combatGangText}
|
||||
<br />
|
||||
<br />
|
||||
Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each
|
||||
of these Factions have all Augmentations available.
|
||||
<div className="popup-box-input-div">
|
||||
<StdButton
|
||||
onClick={createGang}
|
||||
onKeyUp={onKeyUp}
|
||||
text="Create Gang"
|
||||
style={{ float: "right" }}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* This is the component for displaying a single faction's UI, not the list of all
|
||||
* accessible factions
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { AugmentationsPage } from "./AugmentationsPage";
|
||||
import { DonateOption } from "./DonateOption";
|
||||
@ -11,30 +11,21 @@ import { Info } from "./Info";
|
||||
import { Option } from "./Option";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { createSleevePurchasesFromCovenantPopup } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
|
||||
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { use } from "../../ui/Context";
|
||||
import { CreateGangPopup } from "./CreateGangPopup";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
faction: Faction | null;
|
||||
p: IPlayer;
|
||||
startHackingMissionFn: (faction: Faction) => void;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
rerenderFlag: boolean;
|
||||
purchasingAugs: boolean;
|
||||
faction: Faction;
|
||||
};
|
||||
|
||||
// Info text for all options on the UI
|
||||
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " + "faction reputation";
|
||||
const hackingMissionInfo =
|
||||
@ -72,91 +63,68 @@ const GangNames = [
|
||||
"The Black Hand",
|
||||
];
|
||||
|
||||
export class FactionRoot extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
if (props.faction === null) throw new Error("Trying to render the Faction page with null faction");
|
||||
super(props);
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
const faction = props.faction;
|
||||
if (faction === null) throw new Error("Trying to render the Faction page with null faction");
|
||||
|
||||
this.state = {
|
||||
rerenderFlag: false,
|
||||
purchasingAugs: false,
|
||||
faction: props.faction,
|
||||
};
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [, setRerenderFlag] = useState(false);
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(false);
|
||||
|
||||
this.manageGang = this.manageGang.bind(this);
|
||||
this.rerender = this.rerender.bind(this);
|
||||
this.routeToMain = this.routeToMain.bind(this);
|
||||
this.routeToPurchaseAugs = this.routeToPurchaseAugs.bind(this);
|
||||
this.sleevePurchases = this.sleevePurchases.bind(this);
|
||||
this.startFieldWork = this.startFieldWork.bind(this);
|
||||
this.startHackingContracts = this.startHackingContracts.bind(this);
|
||||
this.startHackingMission = this.startHackingMission.bind(this);
|
||||
this.startSecurityWork = this.startSecurityWork.bind(this);
|
||||
}
|
||||
|
||||
manageGang(): void {
|
||||
function manageGang(faction: Faction): void {
|
||||
// If player already has a gang, just go to the gang UI
|
||||
if (this.props.p.inGang()) {
|
||||
return this.props.engine.loadGangContent();
|
||||
if (player.inGang()) {
|
||||
return router.toGang();
|
||||
}
|
||||
|
||||
const popupId = "create-gang-popup";
|
||||
createPopup(popupId, CreateGangPopup, {
|
||||
popupId: popupId,
|
||||
facName: this.state.faction.name,
|
||||
p: this.props.p,
|
||||
engine: this.props.engine,
|
||||
facName: faction.name,
|
||||
});
|
||||
}
|
||||
|
||||
rerender(): void {
|
||||
this.setState((prevState) => {
|
||||
return {
|
||||
rerenderFlag: !prevState.rerenderFlag,
|
||||
};
|
||||
});
|
||||
function rerender(): void {
|
||||
setRerenderFlag((old) => !old);
|
||||
}
|
||||
|
||||
// Route to the main faction page
|
||||
routeToMain(): void {
|
||||
this.setState({ purchasingAugs: false });
|
||||
function routeToMain(): void {
|
||||
setPurchasingAugs(false);
|
||||
}
|
||||
|
||||
// Route to the purchase augmentation UI for this faction
|
||||
routeToPurchaseAugs(): void {
|
||||
this.setState({ purchasingAugs: true });
|
||||
function routeToPurchaseAugs(): void {
|
||||
setPurchasingAugs(true);
|
||||
}
|
||||
|
||||
sleevePurchases(): void {
|
||||
createSleevePurchasesFromCovenantPopup(this.props.p);
|
||||
function sleevePurchases(): void {
|
||||
createSleevePurchasesFromCovenantPopup(player);
|
||||
}
|
||||
|
||||
startFieldWork(): void {
|
||||
this.props.p.startFactionFieldWork(this.state.faction);
|
||||
function startFieldWork(faction: Faction): void {
|
||||
player.startFactionFieldWork(faction);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
startHackingContracts(): void {
|
||||
this.props.p.startFactionHackWork(this.state.faction);
|
||||
function startHackingContracts(faction: Faction): void {
|
||||
player.startFactionHackWork(faction);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
startHackingMission(): void {
|
||||
const fac = this.state.faction;
|
||||
this.props.p.singularityStopWork();
|
||||
this.props.engine.loadMissionContent();
|
||||
this.props.startHackingMissionFn(fac);
|
||||
function startHackingMission(faction: Faction): void {
|
||||
player.singularityStopWork();
|
||||
props.startHackingMissionFn(faction);
|
||||
}
|
||||
|
||||
startSecurityWork(): void {
|
||||
this.props.p.startFactionSecurityWork(this.state.faction);
|
||||
function startSecurityWork(faction: Faction): void {
|
||||
player.startFactionSecurityWork(faction);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
return this.state.purchasingAugs ? this.renderAugmentationsPage() : this.renderMainPage();
|
||||
}
|
||||
|
||||
renderMainPage(): React.ReactNode {
|
||||
const p = this.props.p;
|
||||
const faction = this.state.faction;
|
||||
function MainPage({ faction }: { faction: Faction }): React.ReactElement {
|
||||
const p = player;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
@ -183,49 +151,51 @@ export class FactionRoot extends React.Component<IProps, IState> {
|
||||
<div className="faction-container">
|
||||
<h1>{faction.name}</h1>
|
||||
<Info faction={faction} factionInfo={factionInfo} />
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={this.manageGang} />}
|
||||
{canAccessGang && <Option buttonText={"Manage Gang"} infoText={gangInfo} onClick={() => manageGang(faction)} />}
|
||||
{!isPlayersGang && factionInfo.offerHackingMission && (
|
||||
<Option buttonText={"Hacking Mission"} infoText={hackingMissionInfo} onClick={this.startHackingMission} />
|
||||
<Option
|
||||
buttonText={"Hacking Mission"}
|
||||
infoText={hackingMissionInfo}
|
||||
onClick={() => startHackingMission(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={this.startHackingContracts}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={this.startFieldWork} />
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerSecurityWork && (
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={this.startSecurityWork} />
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offersWork() && (
|
||||
<DonateOption
|
||||
faction={this.state.faction}
|
||||
p={this.props.p}
|
||||
rerender={this.rerender}
|
||||
faction={faction}
|
||||
p={player}
|
||||
rerender={rerender}
|
||||
favorToDonate={favorToDonate}
|
||||
disabled={!canDonate}
|
||||
/>
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={this.routeToPurchaseAugs} />
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={routeToPurchaseAugs} />
|
||||
{canPurchaseSleeves && (
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={this.sleevePurchases}
|
||||
onClick={sleevePurchases}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderAugmentationsPage(): React.ReactNode {
|
||||
return (
|
||||
<>
|
||||
<AugmentationsPage faction={this.state.faction} p={this.props.p} routeToMainPage={this.routeToMain} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={routeToMain} />
|
||||
) : (
|
||||
<MainPage faction={faction} />
|
||||
);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ interface IProps {
|
||||
player: IPlayer;
|
||||
faction: Faction;
|
||||
aug: Augmentation;
|
||||
rerender: () => void;
|
||||
popupId: string;
|
||||
}
|
||||
|
||||
@ -24,6 +25,7 @@ export function PurchaseAugmentationPopup(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
purchaseAugmentation(props.aug, props.faction);
|
||||
props.rerender();
|
||||
removePopup(props.popupId);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import * as React from "react";
|
||||
import { getNextNeurofluxLevel, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||
import { PurchaseAugmentationPopup } from "./PurchaseAugmentationPopup";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
@ -28,63 +27,56 @@ type IProps = {
|
||||
rerender: () => void;
|
||||
};
|
||||
|
||||
export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
aug: Augmentation;
|
||||
export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
||||
const aug = Augmentations[props.augName];
|
||||
if (aug == null) throw new Error(`aug ${props.augName} does not exists`);
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
const aug = Augmentations[this.props.augName];
|
||||
if (aug == null) throw new Error(`aug ${this.props.augName} does not exists`);
|
||||
this.aug = aug;
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
function getMoneyCost(): number {
|
||||
return aug.baseCost * props.faction.getInfo().augmentationPriceMult;
|
||||
}
|
||||
|
||||
getMoneyCost(): number {
|
||||
return this.aug.baseCost * this.props.faction.getInfo().augmentationPriceMult;
|
||||
function getRepCost(): number {
|
||||
return aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
getRepCost(): number {
|
||||
return this.aug.baseRepRequirement * this.props.faction.getInfo().augmentationRepRequirementMult;
|
||||
}
|
||||
|
||||
handleClick(): void {
|
||||
function handleClick(): void {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
const popupId = "purchase-augmentation-popup";
|
||||
createPopup(popupId, PurchaseAugmentationPopup, {
|
||||
aug: this.aug,
|
||||
faction: this.props.faction,
|
||||
player: this.props.p,
|
||||
aug: aug,
|
||||
faction: props.faction,
|
||||
player: props.p,
|
||||
rerender: props.rerender,
|
||||
popupId: popupId,
|
||||
});
|
||||
} else {
|
||||
purchaseAugmentation(this.aug, this.props.faction);
|
||||
purchaseAugmentation(aug, props.faction);
|
||||
props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the player has the prerequisite Augmentations
|
||||
hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(this.aug);
|
||||
function hasPrereqs(): boolean {
|
||||
return hasAugmentationPrereqs(aug);
|
||||
}
|
||||
|
||||
// Whether the player has enough rep for this Augmentation
|
||||
hasReputation(): boolean {
|
||||
return this.props.faction.playerReputation >= this.getRepCost();
|
||||
function hasReputation(): boolean {
|
||||
return props.faction.playerReputation >= getRepCost();
|
||||
}
|
||||
|
||||
// Whether the player has this augmentations (purchased OR installed)
|
||||
owned(): boolean {
|
||||
function owned(): boolean {
|
||||
let owned = false;
|
||||
for (const queuedAug of this.props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === this.props.augName) {
|
||||
for (const queuedAug of props.p.queuedAugmentations) {
|
||||
if (queuedAug.name === props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const installedAug of this.props.p.augmentations) {
|
||||
if (installedAug.name === this.props.augName) {
|
||||
for (const installedAug of props.p.augmentations) {
|
||||
if (installedAug.name === props.augName) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
@ -93,96 +85,94 @@ export class PurchaseableAugmentation extends React.Component<IProps, any> {
|
||||
return owned;
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
if (this.aug == null) {
|
||||
console.error(
|
||||
`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${this.props.augName}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const moneyCost = this.getMoneyCost();
|
||||
const repCost = this.getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled = false;
|
||||
let status: JSX.Element = <></>;
|
||||
let color = "";
|
||||
if (!this.hasPrereqs()) {
|
||||
disabled = true;
|
||||
status = <>LOCKED (Requires {this.aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite)</>;
|
||||
color = "red";
|
||||
} else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) {
|
||||
disabled = true;
|
||||
} else if (this.hasReputation()) {
|
||||
status = (
|
||||
<>
|
||||
UNLOCKED (at {Reputation(repCost)} faction reputation) - <Money money={moneyCost} player={this.props.p} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
disabled = true;
|
||||
status = (
|
||||
<>
|
||||
LOCKED (Requires {Reputation(repCost)} faction reputation - <Money money={moneyCost} player={this.props.p} />)
|
||||
</>
|
||||
);
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
};
|
||||
if (color !== "") {
|
||||
txtStyle.color = color;
|
||||
}
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = this.aug.name;
|
||||
if (this.aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
let tooltip = <></>;
|
||||
if (typeof this.aug.info === "string")
|
||||
tooltip = (
|
||||
<>
|
||||
<span dangerouslySetInnerHTML={{ __html: this.aug.info }} />
|
||||
<br />
|
||||
<br />
|
||||
{this.aug.stats}
|
||||
</>
|
||||
);
|
||||
else
|
||||
tooltip = (
|
||||
<>
|
||||
{this.aug.info}
|
||||
<br />
|
||||
<br />
|
||||
{this.aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={this.aug.name}>
|
||||
<span
|
||||
style={{
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}}
|
||||
>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={this.handleClick}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
text={btnTxt}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<p style={txtStyle}>{status}</p>
|
||||
</span>
|
||||
</li>
|
||||
if (aug == null) {
|
||||
console.error(
|
||||
`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${props.augName}`,
|
||||
);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const moneyCost = getMoneyCost();
|
||||
const repCost = getRepCost();
|
||||
|
||||
// Determine UI properties
|
||||
let disabled = false;
|
||||
let status: JSX.Element = <></>;
|
||||
let color = "";
|
||||
if (!hasPrereqs()) {
|
||||
disabled = true;
|
||||
status = <>LOCKED (Requires {aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite)</>;
|
||||
color = "red";
|
||||
} else if (aug.name !== AugmentationNames.NeuroFluxGovernor && (aug.owned || owned())) {
|
||||
disabled = true;
|
||||
} else if (hasReputation()) {
|
||||
status = (
|
||||
<>
|
||||
UNLOCKED (at {Reputation(repCost)} faction reputation) - <Money money={moneyCost} player={props.p} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
disabled = true;
|
||||
status = (
|
||||
<>
|
||||
LOCKED (Requires {Reputation(repCost)} faction reputation - <Money money={moneyCost} player={props.p} />)
|
||||
</>
|
||||
);
|
||||
color = "red";
|
||||
}
|
||||
|
||||
const txtStyle: IMap<string> = {
|
||||
display: "inline-block",
|
||||
};
|
||||
if (color !== "") {
|
||||
txtStyle.color = color;
|
||||
}
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = aug.name;
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeurofluxLevel()}`;
|
||||
}
|
||||
|
||||
let tooltip = <></>;
|
||||
if (typeof aug.info === "string")
|
||||
tooltip = (
|
||||
<>
|
||||
<span dangerouslySetInnerHTML={{ __html: aug.info }} />
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
else
|
||||
tooltip = (
|
||||
<>
|
||||
{aug.info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={aug.name}>
|
||||
<span
|
||||
style={{
|
||||
margin: "4px",
|
||||
padding: "4px",
|
||||
}}
|
||||
>
|
||||
<StdButton
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
text={btnTxt}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<p style={txtStyle}>{status}</p>
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
@ -2,20 +2,19 @@
|
||||
* React Component for all the gang stuff.
|
||||
*/
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { ManagementSubpage } from "./ManagementSubpage";
|
||||
import { TerritorySubpage } from "./TerritorySubpage";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Gang } from "../Gang";
|
||||
import { displayFactionContent } from "../../Faction/FactionHelpers";
|
||||
|
||||
interface IProps {
|
||||
gang: Gang;
|
||||
player: IPlayer;
|
||||
engine: IEngine;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
export function GangRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [management, setManagement] = useState(true);
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
@ -25,8 +24,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
}, []);
|
||||
|
||||
function back(): void {
|
||||
props.engine.loadFactionContent();
|
||||
displayFactionContent(props.gang.facName);
|
||||
router.toFaction(Factions[props.gang.facName]);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -48,11 +46,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
>
|
||||
Gang Territory
|
||||
</a>
|
||||
{management ? (
|
||||
<ManagementSubpage gang={props.gang} player={props.player} />
|
||||
) : (
|
||||
<TerritorySubpage gang={props.gang} />
|
||||
)}
|
||||
{management ? <ManagementSubpage gang={props.gang} player={player} /> : <TerritorySubpage gang={props.gang} />}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import { Page, routing } from ".././ui/navigationTracking";
|
||||
import { Root } from "./ui/Root";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../IEngine";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
let container: HTMLElement;
|
||||
|
||||
(function () {
|
||||
function setContainer(): void {
|
||||
const c = document.getElementById("infiltration-container");
|
||||
if (c === null) throw new Error("huh?");
|
||||
container = c;
|
||||
document.removeEventListener("DOMContentLoaded", setContainer);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", setContainer);
|
||||
})();
|
||||
|
||||
function calcDifficulty(player: IPlayer, startingDifficulty: number): number {
|
||||
const totalStats = player.strength + player.defense + player.dexterity + player.agility + player.charisma;
|
||||
const difficulty = startingDifficulty - Math.pow(totalStats, 0.9) / 250 - player.intelligence / 1600;
|
||||
if (difficulty < 0) return 0;
|
||||
if (difficulty > 3) return 3;
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
export function displayInfiltrationContent(
|
||||
engine: IEngine,
|
||||
player: IPlayer,
|
||||
location: string,
|
||||
startingDifficulty: number,
|
||||
maxLevel: number,
|
||||
): void {
|
||||
if (!routing.isOn(Page.Infiltration)) return;
|
||||
|
||||
const difficulty = calcDifficulty(player, startingDifficulty);
|
||||
|
||||
ReactDOM.render(
|
||||
<Root
|
||||
Engine={engine}
|
||||
Player={player}
|
||||
Location={location}
|
||||
StartingDifficulty={startingDifficulty}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={maxLevel}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { use } from "../../ui/Context";
|
||||
import React, { useState } from "react";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Countdown } from "./Countdown";
|
||||
@ -14,8 +13,6 @@ import { WireCuttingGame } from "./WireCuttingGame";
|
||||
import { Victory } from "./Victory";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
@ -40,6 +37,8 @@ const minigames = [
|
||||
];
|
||||
|
||||
export function Game(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [level, setLevel] = useState(1);
|
||||
const [stage, setStage] = useState(Stage.Countdown);
|
||||
const [results, setResults] = useState("");
|
||||
@ -89,12 +88,10 @@ export function Game(props: IProps): React.ReactElement {
|
||||
pushResult(false);
|
||||
// Kill the player immediately if they use automation, so
|
||||
// it's clear they're not meant to
|
||||
const damage = options?.automated ? props.Player.hp : props.StartingDifficulty * 3;
|
||||
if (props.Player.takeDamage(damage)) {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (menu === null) throw new Error("mainmenu-container not found");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
const damage = options?.automated ? player.hp : props.StartingDifficulty * 3;
|
||||
if (player.takeDamage(damage)) {
|
||||
router.toCity();
|
||||
return;
|
||||
}
|
||||
setupNextGame();
|
||||
}
|
||||
@ -112,8 +109,6 @@ export function Game(props: IProps): React.ReactElement {
|
||||
case Stage.Sell:
|
||||
stageComponent = (
|
||||
<Victory
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
StartingDifficulty={props.StartingDifficulty}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
|
53
src/Infiltration/ui/InfiltrationRoot.tsx
Normal file
53
src/Infiltration/ui/InfiltrationRoot.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import React, { useState } from "react";
|
||||
import { Intro } from "./Intro";
|
||||
import { Game } from "./Game";
|
||||
import { LocationName } from "../../Locations/data/LocationNames";
|
||||
import { Locations } from "../../Locations/Locations";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IProps {
|
||||
location: LocationName;
|
||||
}
|
||||
function calcDifficulty(player: IPlayer, startingDifficulty: number): number {
|
||||
const totalStats = player.strength + player.defense + player.dexterity + player.agility + player.charisma;
|
||||
const difficulty = startingDifficulty - Math.pow(totalStats, 0.9) / 250 - player.intelligence / 1600;
|
||||
if (difficulty < 0) return 0;
|
||||
if (difficulty > 3) return 3;
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
export function InfiltrationRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [start, setStart] = useState(false);
|
||||
|
||||
const loc = Locations[props.location];
|
||||
if (loc.infiltrationData === undefined) throw new Error("Trying to do infiltration on invalid location.");
|
||||
const startingDifficulty = loc.infiltrationData.startingSecurityLevel;
|
||||
const difficulty = calcDifficulty(player, startingDifficulty);
|
||||
|
||||
function cancel(): void {
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
return (
|
||||
<Intro
|
||||
Location={props.location}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={loc.infiltrationData.maxClearanceLevel}
|
||||
start={() => setStart(true)}
|
||||
cancel={cancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Game
|
||||
StartingDifficulty={startingDifficulty}
|
||||
Difficulty={difficulty}
|
||||
MaxLevel={loc.infiltrationData.maxClearanceLevel}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
Location: string;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
|
@ -1,49 +0,0 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import React, { useState } from "react";
|
||||
import { Intro } from "./Intro";
|
||||
import { Game } from "./Game";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
Location: string;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
}
|
||||
|
||||
export function Root(props: IProps): React.ReactElement {
|
||||
const [start, setStart] = useState(false);
|
||||
|
||||
function cancel(): void {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (menu === null) throw new Error("mainmenu-container not found");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
return (
|
||||
<Intro
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
Location={props.Location}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
start={() => setStart(true)}
|
||||
cancel={cancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Game
|
||||
Player={props.Player}
|
||||
Engine={props.Engine}
|
||||
StartingDifficulty={props.StartingDifficulty}
|
||||
Difficulty={props.Difficulty}
|
||||
MaxLevel={props.MaxLevel}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { IEngine } from "../../IEngine";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import React, { useState } from "react";
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
@ -7,23 +5,21 @@ import Grid from "@mui/material/Grid";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
interface IProps {
|
||||
Player: IPlayer;
|
||||
Engine: IEngine;
|
||||
StartingDifficulty: number;
|
||||
Difficulty: number;
|
||||
MaxLevel: number;
|
||||
}
|
||||
|
||||
export function Victory(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [faction, setFaction] = useState("none");
|
||||
|
||||
function quitInfiltration(): void {
|
||||
const menu = document.getElementById("mainmenu-container");
|
||||
if (!menu) throw new Error("mainmenu-container somehow null");
|
||||
menu.style.visibility = "visible";
|
||||
props.Engine.loadLocationContent();
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
const levelBonus = props.MaxLevel * Math.pow(1.01, props.MaxLevel);
|
||||
@ -43,8 +39,8 @@ export function Victory(props: IProps): React.ReactElement {
|
||||
BitNodeMultipliers.InfiltrationMoney;
|
||||
|
||||
function sell(): void {
|
||||
props.Player.gainMoney(moneyGain);
|
||||
props.Player.recordMoneySource(moneyGain, "infiltration");
|
||||
player.gainMoney(moneyGain);
|
||||
player.recordMoneySource(moneyGain, "infiltration");
|
||||
quitInfiltration();
|
||||
}
|
||||
|
||||
@ -70,7 +66,7 @@ export function Victory(props: IProps): React.ReactElement {
|
||||
<option key={"none"} value={"none"}>
|
||||
{"none"}
|
||||
</option>
|
||||
{props.Player.factions
|
||||
{player.factions
|
||||
.filter((f) => Factions[f].getInfo().offersWork())
|
||||
.map((f) => (
|
||||
<option key={f} value={f}>
|
||||
|
@ -3,418 +3,347 @@
|
||||
*
|
||||
* This subcomponent renders all of the buttons for applying to jobs at a company
|
||||
*/
|
||||
import * as React from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { ApplyToJobButton } from "./ApplyToJobButton";
|
||||
|
||||
import { Location } from "../Location";
|
||||
import { Locations } from "../Locations";
|
||||
import { LocationName } from "../data/LocationNames";
|
||||
|
||||
import { IEngine } from "../../IEngine";
|
||||
|
||||
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 { StdButton } from "../../ui/React/StdButton";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
import { use } from "../../ui/Context";
|
||||
import { QuitJobPopup } from "../../Company/ui/QuitJobPopup";
|
||||
|
||||
type IProps = {
|
||||
engine: IEngine;
|
||||
locName: LocationName;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
employedHere: boolean;
|
||||
};
|
||||
|
||||
const blockStyleMarkup = {
|
||||
display: "block",
|
||||
};
|
||||
|
||||
export class CompanyLocation extends React.Component<IProps, IState> {
|
||||
export function CompanyLocation(props: IProps): React.ReactElement {
|
||||
const p = use.Player();
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
const company = Companies[props.locName];
|
||||
if (company == null) throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
|
||||
|
||||
/**
|
||||
* Reference to the Location that this component is being rendered for
|
||||
*/
|
||||
const location = Locations[props.locName];
|
||||
if (location == null) {
|
||||
throw new Error(`CompanyLocation component constructed with invalid location: ${props.locName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of company position that player holds, if applicable
|
||||
*/
|
||||
const jobTitle = p.jobs[props.locName] ? p.jobs[props.locName] : null;
|
||||
|
||||
/**
|
||||
* CompanyPosition object for the job that the player holds at this company
|
||||
* (if he has one)
|
||||
*/
|
||||
companyPosition: CompanyPosition | null = null;
|
||||
const companyPosition = jobTitle ? CompanyPositions[jobTitle] : null;
|
||||
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
p.location = props.locName;
|
||||
|
||||
/**
|
||||
* 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.quit = this.quit.bind(this);
|
||||
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.startInfiltration = this.startInfiltration.bind(this);
|
||||
this.work = this.work.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) {
|
||||
throw new Error(`CompanyLocation component constructed with invalid company: ${props.locName}`);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
employedHere: false,
|
||||
};
|
||||
|
||||
this.props.p.location = props.locName;
|
||||
|
||||
this.checkIfEmployedHere(false);
|
||||
}
|
||||
|
||||
applyForAgentJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForAgentJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForAgentJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForAgentJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForBusinessConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForBusinessConsultantJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForBusinessConsultantJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForBusinessJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForBusinessJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForBusinessJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForBusinessJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForEmployeeJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForEmployeeJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForItJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForItJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForItJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForItJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForPartTimeEmployeeJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForPartTimeEmployeeJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForPartTimeEmployeeJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForPartTimeWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForPartTimeWaiterJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForPartTimeWaiterJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSecurityJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSecurityJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSecurityJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSecurityJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSoftwareConsultantJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSoftwareConsultantJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSoftwareConsultantJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForSoftwareJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForSoftwareJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForSoftwareJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForSoftwareJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
applyForWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
function applyForWaiterJob(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
this.props.p.applyForWaiterJob();
|
||||
this.checkIfEmployedHere(true);
|
||||
p.applyForWaiterJob();
|
||||
rerender();
|
||||
}
|
||||
|
||||
checkIfEmployedHere(updateState = false): void {
|
||||
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>): void {
|
||||
function startInfiltration(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
const loc = this.location;
|
||||
if (!loc.infiltrationData) {
|
||||
console.error(`trying to start infiltration at ${this.props.locName} but the infiltrationData is null`);
|
||||
return;
|
||||
}
|
||||
const loc = location;
|
||||
if (!loc.infiltrationData)
|
||||
throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`);
|
||||
|
||||
this.props.engine.loadInfiltrationContent(
|
||||
this.props.locName,
|
||||
loc.infiltrationData.startingSecurityLevel,
|
||||
loc.infiltrationData.maxClearanceLevel,
|
||||
);
|
||||
|
||||
const data = loc.infiltrationData;
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
router.toInfiltration(props.locName);
|
||||
}
|
||||
|
||||
work(e: React.MouseEvent<HTMLElement>): void {
|
||||
function work(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pos = this.companyPosition;
|
||||
const pos = companyPosition;
|
||||
if (pos instanceof CompanyPosition) {
|
||||
if (pos.isPartTimeJob() || pos.isSoftwareConsultantJob() || pos.isBusinessConsultantJob()) {
|
||||
this.props.p.startWorkPartTime(this.props.locName);
|
||||
p.startWorkPartTime(props.locName);
|
||||
} else {
|
||||
this.props.p.startWork(this.props.locName);
|
||||
p.startWork(props.locName);
|
||||
}
|
||||
router.toWork();
|
||||
}
|
||||
}
|
||||
|
||||
quit(e: React.MouseEvent<HTMLElement>): void {
|
||||
function quit(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) return;
|
||||
const popupId = `quit-job-popup`;
|
||||
createPopup(popupId, QuitJobPopup, {
|
||||
locName: this.props.locName,
|
||||
company: this.company,
|
||||
player: this.props.p,
|
||||
onQuit: () => this.checkIfEmployedHere(true),
|
||||
locName: props.locName,
|
||||
company: company,
|
||||
player: p,
|
||||
onQuit: rerender,
|
||||
popupId: popupId,
|
||||
});
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const isEmployedHere = this.jobTitle != null;
|
||||
const favorGain = this.company.getFavorGain();
|
||||
const isEmployedHere = jobTitle != null;
|
||||
const favorGain = company.getFavorGain();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isEmployedHere && (
|
||||
<div>
|
||||
<p>Job Title: {this.jobTitle}</p>
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company reputation: {Reputation(this.company.playerReputation)}
|
||||
<span className={"tooltiptext"}>
|
||||
You will earn {Favor(favorGain[0])} company favor upon resetting after installing Augmentations
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company Favor: {Favor(this.company.favor)}
|
||||
<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>
|
||||
<br />
|
||||
<br />
|
||||
<p style={blockStyleMarkup}>-------------------------</p>
|
||||
<br />
|
||||
<StdButton onClick={this.work} text={"Work"} />
|
||||
|
||||
<StdButton onClick={this.quit} text={"Quit"} />
|
||||
</div>
|
||||
)}
|
||||
{this.company.hasAgentPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]}
|
||||
onClick={this.applyForAgentJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Agent Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasBusinessConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]}
|
||||
onClick={this.applyForBusinessConsultantJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Business Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasBusinessPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]}
|
||||
onClick={this.applyForBusinessJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Business Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]}
|
||||
onClick={this.applyForEmployeeJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be an Employee"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]}
|
||||
onClick={this.applyForPartTimeEmployeeJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a part-time Employee"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasITPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]}
|
||||
onClick={this.applyForItJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for IT Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSecurityPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]}
|
||||
onClick={this.applyForSecurityJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Security Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSoftwareConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]}
|
||||
onClick={this.applyForSoftwareConsultantJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Software Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasSoftwarePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]}
|
||||
onClick={this.applyForSoftwareJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply for Software Job"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]}
|
||||
onClick={this.applyForWaiterJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a Waiter"}
|
||||
/>
|
||||
)}
|
||||
{this.company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={this.company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]}
|
||||
onClick={this.applyForPartTimeWaiterJob}
|
||||
p={this.props.p}
|
||||
style={this.btnStyle}
|
||||
text={"Apply to be a part-time Waiter"}
|
||||
/>
|
||||
)}
|
||||
{this.location.infiltrationData != null && (
|
||||
<StdButton onClick={this.startInfiltration} style={this.btnStyle} text={"Infiltrate Company"} />
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{isEmployedHere && (
|
||||
<div>
|
||||
<p>Job Title: {jobTitle}</p>
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company reputation: {Reputation(company.playerReputation)}
|
||||
<span className={"tooltiptext"}>
|
||||
You will earn {Favor(favorGain[0])} company favor upon resetting after installing Augmentations
|
||||
</span>
|
||||
</p>
|
||||
<br />
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<p className={"tooltip"}>
|
||||
Company Favor: {Favor(company.favor)}
|
||||
<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>
|
||||
<br />
|
||||
<br />
|
||||
<p style={{ display: "block" }}>-------------------------</p>
|
||||
<br />
|
||||
<StdButton onClick={work} text={"Work"} />
|
||||
|
||||
<StdButton onClick={quit} text={"Quit"} />
|
||||
</div>
|
||||
)}
|
||||
{company.hasAgentPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.AgentCompanyPositions[0]]}
|
||||
onClick={applyForAgentJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Agent Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasBusinessConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessConsultantCompanyPositions[0]]}
|
||||
onClick={applyForBusinessConsultantJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Business Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasBusinessPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.BusinessCompanyPositions[0]]}
|
||||
onClick={applyForBusinessJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Business Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[1]]}
|
||||
onClick={applyForEmployeeJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be an Employee"}
|
||||
/>
|
||||
)}
|
||||
{company.hasEmployeePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[1]]}
|
||||
onClick={applyForPartTimeEmployeeJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a part-time Employee"}
|
||||
/>
|
||||
)}
|
||||
{company.hasITPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.ITCompanyPositions[0]]}
|
||||
onClick={applyForItJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for IT Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSecurityPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SecurityCompanyPositions[2]]}
|
||||
onClick={applyForSecurityJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Security Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSoftwareConsultantPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareConsultantCompanyPositions[0]]}
|
||||
onClick={applyForSoftwareConsultantJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Software Consultant Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasSoftwarePositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.SoftwareCompanyPositions[0]]}
|
||||
onClick={applyForSoftwareJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply for Software Job"}
|
||||
/>
|
||||
)}
|
||||
{company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.MiscCompanyPositions[0]]}
|
||||
onClick={applyForWaiterJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a Waiter"}
|
||||
/>
|
||||
)}
|
||||
{company.hasWaiterPositions() && (
|
||||
<ApplyToJobButton
|
||||
company={company}
|
||||
entryPosType={CompanyPositions[posNames.PartTimeCompanyPositions[0]]}
|
||||
onClick={applyForPartTimeWaiterJob}
|
||||
p={p}
|
||||
style={{ display: "block" }}
|
||||
text={"Apply to be a part-time Waiter"}
|
||||
/>
|
||||
)}
|
||||
{location.infiltrationData != null && (
|
||||
<StdButton onClick={startInfiltration} style={{ display: "block" }} text={"Infiltrate Company"} />
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -60,14 +60,7 @@ export class GenericLocation extends React.Component<IProps, any> {
|
||||
const content: React.ReactNode[] = [];
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Company)) {
|
||||
content.push(
|
||||
<CompanyLocation
|
||||
engine={this.props.engine}
|
||||
key={"companylocation"}
|
||||
locName={this.props.loc.name}
|
||||
p={this.props.p}
|
||||
/>,
|
||||
);
|
||||
content.push(<CompanyLocation key={"companylocation"} locName={this.props.loc.name} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Gym)) {
|
||||
@ -79,7 +72,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} />);
|
||||
content.push(<SlumsLocation key={"slumslocation"} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Special)) {
|
||||
@ -97,7 +90,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} />);
|
||||
content.push(<UniversityLocation key={"universitylocation"} loc={this.props.loc} />);
|
||||
}
|
||||
|
||||
if (this.props.loc.types.includes(LocationType.Casino)) {
|
||||
|
@ -6,225 +6,209 @@
|
||||
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";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
export class SlumsLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.btnStyle = { display: "block" };
|
||||
|
||||
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<HTMLElement>): void {
|
||||
export function SlumsLocation(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
function shoplift(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Shoplift.commit(this.props.p);
|
||||
Crimes.Shoplift.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
robStore(e: React.MouseEvent<HTMLElement>): void {
|
||||
function robStore(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.RobStore.commit(this.props.p);
|
||||
Crimes.RobStore.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
mug(e: React.MouseEvent<HTMLElement>): void {
|
||||
function mug(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Mug.commit(this.props.p);
|
||||
Crimes.Mug.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
larceny(e: React.MouseEvent<HTMLElement>): void {
|
||||
function larceny(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Larceny.commit(this.props.p);
|
||||
Crimes.Larceny.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
dealDrugs(e: React.MouseEvent<HTMLElement>): void {
|
||||
function dealDrugs(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.DealDrugs.commit(this.props.p);
|
||||
Crimes.DealDrugs.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
bondForgery(e: React.MouseEvent<HTMLElement>): void {
|
||||
function bondForgery(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.BondForgery.commit(this.props.p);
|
||||
Crimes.BondForgery.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
traffickArms(e: React.MouseEvent<HTMLElement>): void {
|
||||
function traffickArms(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.TraffickArms.commit(this.props.p);
|
||||
Crimes.TraffickArms.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
homicide(e: React.MouseEvent<HTMLElement>): void {
|
||||
function homicide(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Homicide.commit(this.props.p);
|
||||
Crimes.Homicide.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
|
||||
function grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.GrandTheftAuto.commit(this.props.p);
|
||||
Crimes.GrandTheftAuto.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
kidnap(e: React.MouseEvent<HTMLElement>): void {
|
||||
function kidnap(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Kidnap.commit(this.props.p);
|
||||
Crimes.Kidnap.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
assassinate(e: React.MouseEvent<HTMLElement>): void {
|
||||
function assassinate(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Assassination.commit(this.props.p);
|
||||
Crimes.Assassination.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
heist(e: React.MouseEvent<HTMLElement>): void {
|
||||
function heist(e: React.MouseEvent<HTMLElement>): void {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
Crimes.Heist.commit(this.props.p);
|
||||
Crimes.Heist.commit(player);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
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);
|
||||
const shopliftChance = Crimes.Shoplift.successRate(player);
|
||||
const robStoreChance = Crimes.RobStore.successRate(player);
|
||||
const mugChance = Crimes.Mug.successRate(player);
|
||||
const larcenyChance = Crimes.Larceny.successRate(player);
|
||||
const drugsChance = Crimes.DealDrugs.successRate(player);
|
||||
const bondChance = Crimes.BondForgery.successRate(player);
|
||||
const armsChance = Crimes.TraffickArms.successRate(player);
|
||||
const homicideChance = Crimes.Homicide.successRate(player);
|
||||
const gtaChance = Crimes.GrandTheftAuto.successRate(player);
|
||||
const kidnapChance = Crimes.Kidnap.successRate(player);
|
||||
const assassinateChance = Crimes.Assassination.successRate(player);
|
||||
const heistChance = Crimes.Heist.successRate(player);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<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"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={shoplift}
|
||||
style={{ display: "block" }}
|
||||
text={`Shoplift (${numeralWrapper.formatPercentage(shopliftChance)} chance of success)`}
|
||||
tooltip={"Attempt to shoplift from a low-end retailer"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={robStore}
|
||||
style={{ display: "block" }}
|
||||
text={`Rob store (${numeralWrapper.formatPercentage(robStoreChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit armed robbery on a high-end store"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={mug}
|
||||
style={{ display: "block" }}
|
||||
text={`Mug someone (${numeralWrapper.formatPercentage(mugChance)} chance of success)`}
|
||||
tooltip={"Attempt to mug a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={larceny}
|
||||
style={{ display: "block" }}
|
||||
text={`Larceny (${numeralWrapper.formatPercentage(larcenyChance)} chance of success)`}
|
||||
tooltip={"Attempt to rob property from someone's house"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={dealDrugs}
|
||||
style={{ display: "block" }}
|
||||
text={`Deal Drugs (${numeralWrapper.formatPercentage(drugsChance)} chance of success)`}
|
||||
tooltip={"Attempt to deal drugs"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={bondForgery}
|
||||
style={{ display: "block" }}
|
||||
text={`Bond Forgery (${numeralWrapper.formatPercentage(bondChance)} chance of success)`}
|
||||
tooltip={"Attempt to forge corporate bonds"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={traffickArms}
|
||||
style={{ display: "block" }}
|
||||
text={`Traffick illegal Arms (${numeralWrapper.formatPercentage(armsChance)} chance of success)`}
|
||||
tooltip={"Attempt to smuggle illegal arms into the city"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={homicide}
|
||||
style={{ display: "block" }}
|
||||
text={`Homicide (${numeralWrapper.formatPercentage(homicideChance)} chance of success)`}
|
||||
tooltip={"Attempt to murder a random person on the street"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={grandTheftAuto}
|
||||
style={{ display: "block" }}
|
||||
text={`Grand theft Auto (${numeralWrapper.formatPercentage(gtaChance)} chance of success)`}
|
||||
tooltip={"Attempt to commit grand theft auto"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={kidnap}
|
||||
style={{ display: "block" }}
|
||||
text={`Kidnap and Ransom (${numeralWrapper.formatPercentage(kidnapChance)} chance of success)`}
|
||||
tooltip={"Attempt to kidnap and ransom a high-profile-target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={assassinate}
|
||||
style={{ display: "block" }}
|
||||
text={`Assassinate (${numeralWrapper.formatPercentage(assassinateChance)} chance of success)`}
|
||||
tooltip={"Attempt to assassinate a high-profile target"}
|
||||
/>
|
||||
<AutoupdatingStdButton
|
||||
intervalTime={5e3}
|
||||
onClick={heist}
|
||||
style={{ display: "block" }}
|
||||
text={`Heist (${numeralWrapper.formatPercentage(heistChance)} chance of success)`}
|
||||
tooltip={"Attempt to pull off the ultimate heist"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -8,154 +8,134 @@ import * as React from "react";
|
||||
import { Location } from "../Location";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { getServer } from "../../Server/ServerHelpers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { SpecialServerIps } from "../../Server/SpecialServerIps";
|
||||
|
||||
import { StdButton } from "../../ui/React/StdButton";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { use } from "../../ui/Context";
|
||||
|
||||
type IProps = {
|
||||
loc: Location;
|
||||
p: IPlayer;
|
||||
};
|
||||
|
||||
export class UniversityLocation extends React.Component<IProps, any> {
|
||||
/**
|
||||
* Stores button styling that sets them all to block display
|
||||
*/
|
||||
btnStyle: any;
|
||||
export function UniversityLocation(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
|
||||
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);
|
||||
this.management = this.management.bind(this);
|
||||
this.leadership = this.leadership.bind(this);
|
||||
|
||||
this.calculateCost = this.calculateCost.bind(this);
|
||||
}
|
||||
|
||||
calculateCost(): number {
|
||||
const ip = SpecialServerIps.getIp(this.props.loc.name);
|
||||
function calculateCost(): number {
|
||||
const ip = SpecialServerIps.getIp(props.loc.name);
|
||||
const server = getServer(ip);
|
||||
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return this.props.loc.costMult;
|
||||
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return props.loc.costMult;
|
||||
const discount = (server as Server).backdoorInstalled ? 0.9 : 1;
|
||||
return this.props.loc.costMult * discount;
|
||||
return props.loc.costMult * discount;
|
||||
}
|
||||
|
||||
take(stat: string): void {
|
||||
const loc = this.props.loc;
|
||||
this.props.p.startClass(this.calculateCost(), loc.expMult, stat);
|
||||
function take(stat: string): void {
|
||||
const loc = props.loc;
|
||||
player.startClass(calculateCost(), loc.expMult, stat);
|
||||
router.toWork();
|
||||
}
|
||||
|
||||
study(): void {
|
||||
this.take(CONSTANTS.ClassStudyComputerScience);
|
||||
function study(): void {
|
||||
take(CONSTANTS.ClassStudyComputerScience);
|
||||
}
|
||||
|
||||
dataStructures(): void {
|
||||
this.take(CONSTANTS.ClassDataStructures);
|
||||
function dataStructures(): void {
|
||||
take(CONSTANTS.ClassDataStructures);
|
||||
}
|
||||
|
||||
networks(): void {
|
||||
this.take(CONSTANTS.ClassNetworks);
|
||||
function networks(): void {
|
||||
take(CONSTANTS.ClassNetworks);
|
||||
}
|
||||
|
||||
algorithms(): void {
|
||||
this.take(CONSTANTS.ClassAlgorithms);
|
||||
function algorithms(): void {
|
||||
take(CONSTANTS.ClassAlgorithms);
|
||||
}
|
||||
|
||||
management(): void {
|
||||
this.take(CONSTANTS.ClassManagement);
|
||||
function management(): void {
|
||||
take(CONSTANTS.ClassManagement);
|
||||
}
|
||||
|
||||
leadership(): void {
|
||||
this.take(CONSTANTS.ClassLeadership);
|
||||
function leadership(): void {
|
||||
take(CONSTANTS.ClassLeadership);
|
||||
}
|
||||
|
||||
render(): React.ReactNode {
|
||||
const costMult: number = this.calculateCost();
|
||||
const costMult: number = calculateCost();
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
const earnHackingExpTooltip = `Gain hacking experience!`;
|
||||
const earnCharismaExpTooltip = `Gain charisma experience!`;
|
||||
const earnHackingExpTooltip = `Gain hacking experience!`;
|
||||
const earnCharismaExpTooltip = `Gain charisma experience!`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={this.study}
|
||||
style={this.btnStyle}
|
||||
text={`Study Computer Science (free)`}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.dataStructures}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Data Structures course (
|
||||
<Money money={dataStructuresCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.networks}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Networks course (
|
||||
<Money money={networksCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.algorithms}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Algorithms course (
|
||||
<Money money={algorithmsCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.management}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Management course (
|
||||
<Money money={managementCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={this.leadership}
|
||||
style={this.btnStyle}
|
||||
text={
|
||||
<>
|
||||
Take Leadership course (
|
||||
<Money money={leadershipCost} player={this.props.p} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<StdButton
|
||||
onClick={study}
|
||||
style={{ display: "block" }}
|
||||
text={`Study Computer Science (free)`}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={dataStructures}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Data Structures course (
|
||||
<Money money={dataStructuresCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={networks}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Networks course (
|
||||
<Money money={networksCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={algorithms}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Algorithms course (
|
||||
<Money money={algorithmsCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnHackingExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={management}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Management course (
|
||||
<Money money={managementCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
<StdButton
|
||||
onClick={leadership}
|
||||
style={{ display: "block" }}
|
||||
text={
|
||||
<>
|
||||
Take Leadership course (
|
||||
<Money money={leadershipCost} player={player} /> / sec)
|
||||
</>
|
||||
}
|
||||
tooltip={earnCharismaExpTooltip}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Engine } from "./engine";
|
||||
import { displayFactionContent } from "./Faction/FactionHelpers";
|
||||
import { Player } from "./Player";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
@ -1187,7 +1185,7 @@ HackingMission.prototype.process = function (numCycles = 1) {
|
||||
});
|
||||
|
||||
// Update timer and check if player lost
|
||||
this.time -= storedCycles * Engine._idleSpeed;
|
||||
this.time -= storedCycles * CONSTANTS._idleSpeed;
|
||||
if (this.time <= 0) {
|
||||
this.finishMission(false);
|
||||
return;
|
||||
@ -1595,18 +1593,6 @@ HackingMission.prototype.finishMission = function (win) {
|
||||
} else {
|
||||
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
|
||||
}
|
||||
|
||||
// Clear mission container
|
||||
var container = document.getElementById("mission-container");
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
// Return to Faction page
|
||||
document.getElementById("mainmenu-container").style.visibility = "visible";
|
||||
document.getElementById("character-overview").style.visibility = "visible";
|
||||
Engine.loadFactionContent();
|
||||
displayFactionContent(this.faction.name);
|
||||
};
|
||||
|
||||
export { HackingMission, inMission, setInMission, currMission };
|
||||
|
@ -121,8 +121,33 @@ export interface IPlayer {
|
||||
bladeburner_analysis_mult: number;
|
||||
bladeburner_success_chance_mult: number;
|
||||
|
||||
workRepGained: number;
|
||||
createProgramName: string;
|
||||
timeWorkedCreateProgram: number;
|
||||
crimeType: string;
|
||||
timeNeededToCompleteWork: number;
|
||||
focus: boolean;
|
||||
className: string;
|
||||
currentWorkFactionName: string;
|
||||
workType: string;
|
||||
currentWorkFactionDescription: string;
|
||||
timeWorked: number;
|
||||
workMoneyGained: number;
|
||||
workMoneyGainRate: number;
|
||||
workRepGained: number;
|
||||
workRepGainRate: number;
|
||||
workHackExpGained: number;
|
||||
workHackExpGainRate: number;
|
||||
workStrExpGained: number;
|
||||
workStrExpGainRate: number;
|
||||
workDefExpGained: number;
|
||||
workDefExpGainRate: number;
|
||||
workDexExpGained: number;
|
||||
workDexExpGainRate: number;
|
||||
workAgiExpGained: number;
|
||||
workAgiExpGainRate: number;
|
||||
workChaExpGained: number;
|
||||
workChaExpGainRate: number;
|
||||
workMoneyLossRate: number;
|
||||
|
||||
// Methods
|
||||
applyForAgentJob(sing?: boolean): boolean | void;
|
||||
@ -209,4 +234,12 @@ export interface IPlayer {
|
||||
receiveInvite(factionName: string): void;
|
||||
updateSkillLevels(): void;
|
||||
gainCodingContractReward(reward: ICodingContractReward, difficulty?: number): string;
|
||||
stopFocusing(): void;
|
||||
finishFactionWork(cancelled: boolean, sing?: boolean): void;
|
||||
finishClass(sing?: boolean): void;
|
||||
finishWork(cancelled: boolean, sing?: boolean): void;
|
||||
cancelationPenalty(): number;
|
||||
finishWorkPartTime(sing?: boolean): void;
|
||||
finishCrime(cancelled: boolean): void;
|
||||
finishCreateProgramWork(cancelled: boolean): void;
|
||||
}
|
||||
|
@ -14,10 +14,8 @@ import { CONSTANTS } from "../../Constants";
|
||||
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 { resetGangs } from "../../Gang/AllGangs";
|
||||
import { hasHacknetServers } from "../../Hacknet/HacknetHelpers";
|
||||
import { Cities } from "../../Locations/Cities";
|
||||
@ -48,18 +46,12 @@ 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 { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { ReputationRate } from "../../ui/React/ReputationRate";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
|
||||
|
||||
export function init() {
|
||||
/* Initialize Player's home computer */
|
||||
@ -518,8 +510,6 @@ export function resetWorkStatus(generalType, group, workType) {
|
||||
this.currentWorkFactionDescription = "";
|
||||
this.createProgramName = "";
|
||||
this.className = "";
|
||||
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById("work-in-progress-text"));
|
||||
}
|
||||
|
||||
export function processWorkEarnings(numCycles = 1) {
|
||||
@ -573,25 +563,6 @@ export function startWork(companyName) {
|
||||
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;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "visible";
|
||||
focusButton.innerHTML = "Do something else simultaneously";
|
||||
focusButton.addEventListener("click", () => {
|
||||
this.stopFocusing();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function cancelationPenalty() {
|
||||
@ -607,11 +578,11 @@ 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) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.workRepGainRate = this.getWorkRepGain();
|
||||
this.processWorkEarnings(numCycles);
|
||||
@ -622,63 +593,7 @@ export function work(numCycles) {
|
||||
}
|
||||
|
||||
const comp = Companies[this.companyName];
|
||||
let companyRep = "0";
|
||||
if (comp == null || !(comp instanceof Company)) {
|
||||
console.error(`Could not find Company: ${this.companyName}`);
|
||||
} else {
|
||||
companyRep = comp.playerReputation;
|
||||
}
|
||||
|
||||
influenceStockThroughCompanyWork(comp, this.workRepGainRate, numCycles);
|
||||
|
||||
const position = this.jobs[this.companyName];
|
||||
|
||||
const penalty = this.cancelationPenalty();
|
||||
|
||||
const penaltyString = penalty === 0.5 ? "half" : "three-quarters";
|
||||
|
||||
var elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} ({ReputationRate(this.workRepGainRate * CYCLES_PER_SEC)}) reputation for this
|
||||
company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, but you will only
|
||||
gain {penaltyString} of the reputation you've earned so far.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
}
|
||||
|
||||
export function finishWork(cancelled, sing = false) {
|
||||
@ -731,10 +646,7 @@ export function finishWork(cancelled, sing = false) {
|
||||
dialogBoxCreate(content);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
Engine.loadLocationContent(false);
|
||||
|
||||
if (sing) {
|
||||
var res =
|
||||
@ -781,27 +693,17 @@ export function startWorkPartTime(companyName) {
|
||||
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) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer8Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.workRepGainRate = this.getWorkRepGain();
|
||||
this.processWorkEarnings(numCycles);
|
||||
@ -810,60 +712,6 @@ export function workPartTime(numCycles) {
|
||||
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer8Hours) {
|
||||
return this.finishWorkPartTime();
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working as a {position} at {this.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} (
|
||||
{Reputation(`${numeralWrapper.formatExp(this.workRepGainRate * CYCLES_PER_SEC)} / sec`)}
|
||||
) reputation for this company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
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.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
}
|
||||
|
||||
export function finishWorkPartTime(sing = false) {
|
||||
@ -894,10 +742,7 @@ export function finishWorkPartTime(sing = false) {
|
||||
dialogBoxCreate(content);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
Engine.loadLocationContent(false);
|
||||
if (sing) {
|
||||
var res =
|
||||
"You worked for " +
|
||||
@ -928,17 +773,11 @@ export function finishWorkPartTime(sing = false) {
|
||||
}
|
||||
|
||||
export function startFocusing() {
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
this.focus = true;
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function stopFocusing() {
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.focus = false;
|
||||
Engine.loadTerminalContent();
|
||||
}
|
||||
|
||||
/* Working for Faction */
|
||||
@ -957,24 +796,6 @@ export function startFactionWork(faction) {
|
||||
this.currentWorkFactionName = faction.name;
|
||||
|
||||
this.timeNeededToCompleteWork = CONSTANTS.MillisecondsPer20Hours;
|
||||
|
||||
const cancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
cancelButton.innerHTML = "Stop Faction Work";
|
||||
cancelButton.addEventListener("click", () => {
|
||||
this.finishFactionWork(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "visible";
|
||||
focusButton.innerHTML = "Do something else simultaneously";
|
||||
focusButton.addEventListener("click", () => {
|
||||
this.stopFocusing();
|
||||
return false;
|
||||
});
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function startFactionHackWork(faction) {
|
||||
@ -1046,11 +867,11 @@ export function workForFaction(numCycles) {
|
||||
|
||||
//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) {
|
||||
if (this.timeWorked + CONSTANTS._idleSpeed * numCycles >= CONSTANTS.MillisecondsPer20Hours) {
|
||||
overMax = true;
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / Engine._idleSpeed);
|
||||
numCycles = Math.round((CONSTANTS.MillisecondsPer20Hours - this.timeWorked) / CONSTANTS._idleSpeed);
|
||||
}
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
|
||||
this.processWorkEarnings(numCycles);
|
||||
|
||||
@ -1058,44 +879,6 @@ export function workForFaction(numCycles) {
|
||||
if (overMax || this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) {
|
||||
return this.finishFactionWork(false);
|
||||
}
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently {this.currentWorkFactionDescription} for your faction {faction.name}
|
||||
<br />
|
||||
(Current Faction Reputation: {Reputation(faction.playerReputation)}). <br />
|
||||
You have been doing this for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={this.workMoneyGained} /> ({MoneyRate(this.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(this.workRepGained)} ({ReputationRate(this.workRepGainRate * CYCLES_PER_SEC)}) reputation for this
|
||||
faction <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
|
||||
<br />
|
||||
There is no penalty for cancelling earlier.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
}
|
||||
|
||||
export function finishFactionWork(cancelled, sing = false) {
|
||||
@ -1125,13 +908,8 @@ export function finishFactionWork(cancelled, sing = false) {
|
||||
);
|
||||
}
|
||||
|
||||
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 " +
|
||||
@ -1419,19 +1197,6 @@ export function startCreateProgramWork(programName, time, reqLevel) {
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function createProgramWork(numCycles) {
|
||||
@ -1441,28 +1206,12 @@ export function createProgramWork(numCycles) {
|
||||
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;
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
this.timeWorkedCreateProgram += CONSTANTS._idleSpeed * numCycles * skillMult;
|
||||
|
||||
if (this.timeWorkedCreateProgram >= this.timeNeededToCompleteWork) {
|
||||
this.finishCreateProgramWork(false);
|
||||
}
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You are currently working on coding {programName}.<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
The program is {((this.timeWorkedCreateProgram / this.timeNeededToCompleteWork) * 100).toFixed(2)}
|
||||
% complete. <br />
|
||||
If you cancel, your work will be saved and you can come back to complete the program later.
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
}
|
||||
|
||||
export function finishCreateProgramWork(cancelled) {
|
||||
@ -1483,12 +1232,8 @@ export function finishCreateProgramWork(cancelled) {
|
||||
this.gainIntelligenceExp(this.createProgramReqLvl / CONSTANTS.IntelligenceProgramBaseExpGain);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
Engine.loadTerminalContent();
|
||||
this.resetWorkStatus();
|
||||
}
|
||||
|
||||
@ -1501,7 +1246,7 @@ export function startClass(costMult, expMult, className) {
|
||||
|
||||
this.className = className;
|
||||
|
||||
const gameCPS = 1000 / Engine._idleSpeed;
|
||||
const gameCPS = 1000 / CONSTANTS._idleSpeed;
|
||||
|
||||
//Find cost and exp gain per game cycle
|
||||
var cost = 0;
|
||||
@ -1564,62 +1309,11 @@ export function startClass(costMult, expMult, className) {
|
||||
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;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function takeClass(numCycles) {
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
var className = this.className;
|
||||
|
||||
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
|
||||
this.processWorkEarnings(numCycles);
|
||||
|
||||
const elem = document.getElementById("work-in-progress-text");
|
||||
ReactDOM.render(
|
||||
<>
|
||||
You have been {className} for {convertTimeMsToTimeElapsedString(this.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
This has cost you: <br />
|
||||
<Money money={-this.workMoneyGained} /> ({MoneyRate(this.workMoneyLossRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
You have gained: <br />
|
||||
{numeralWrapper.formatExp(this.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
{numeralWrapper.formatExp(this.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(this.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(this.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(this.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
{numeralWrapper.formatExp(this.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(this.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
You may cancel at any time
|
||||
</>,
|
||||
elem,
|
||||
);
|
||||
}
|
||||
|
||||
//The 'sing' argument defines whether or not this function was called
|
||||
@ -1650,12 +1344,8 @@ export function finishClass(sing = false) {
|
||||
);
|
||||
}
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
|
||||
this.isWorking = false;
|
||||
|
||||
Engine.loadLocationContent(false);
|
||||
if (sing) {
|
||||
var res =
|
||||
"After " +
|
||||
@ -1708,49 +1398,12 @@ export function startCrime(crimeType, hackExp, strExp, defExp, dexExp, agiExp, c
|
||||
this.workMoneyGained = money * this.crime_money_mult * BitNodeMultipliers.CrimeMoney;
|
||||
|
||||
this.timeNeededToCompleteWork = time;
|
||||
|
||||
//Remove all old event listeners from Cancel button
|
||||
const newCancelButton = clearEventListeners("work-in-progress-cancel-button");
|
||||
newCancelButton.innerHTML = "Cancel crime";
|
||||
newCancelButton.addEventListener("click", () => {
|
||||
this.finishCrime(true);
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusButton = clearEventListeners("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
|
||||
//Display Work In Progress Screen
|
||||
Engine.loadWorkInProgressContent();
|
||||
}
|
||||
|
||||
export function commitCrime(numCycles) {
|
||||
this.timeWorked += Engine._idleSpeed * numCycles;
|
||||
this.timeWorked += CONSTANTS._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 +
|
||||
".<br>" +
|
||||
"Time remaining: " +
|
||||
convertTimeMsToTimeElapsedString(this.timeNeededToCompleteWork - this.timeWorked) +
|
||||
"<br>" +
|
||||
progressBar.replace(/ /g, " ");
|
||||
if (this.timeWorked >= this.timeNeededToCompleteWork) this.finishCrime(false);
|
||||
}
|
||||
|
||||
export function finishCrime(cancelled) {
|
||||
@ -1892,11 +1545,9 @@ export function finishCrime(cancelled) {
|
||||
}
|
||||
this.committingCrimeThruSingFn = false;
|
||||
this.singFnCrimeWorkerScript = null;
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
this.isWorking = false;
|
||||
this.crimeType = "";
|
||||
this.resetWorkStatus();
|
||||
Engine.loadLocationContent(false);
|
||||
}
|
||||
|
||||
//Cancels the player's current "work" assignment and gives the proper rewards
|
||||
|
@ -3,7 +3,6 @@ import { augmentationExists, initAugmentations } from "./Augmentation/Augmentati
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { writeCinematicText } from "./CinematicText";
|
||||
import { Companies, initCompanies } from "./Company/Companies";
|
||||
import { resetIndustryResearchTrees } from "./Corporation/IndustryData";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
@ -25,13 +24,7 @@ import { SpecialServerIps, prestigeSpecialServerIps, SpecialServerNames } from "
|
||||
import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
|
||||
import { Terminal } from "./Terminal";
|
||||
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||
import { createElement } from "../utils/uiHelpers/createElement";
|
||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
@ -39,9 +32,6 @@ const BitNode8StartingMoney = 250e6;
|
||||
|
||||
// Prestige by purchasing augmentation
|
||||
function prestigeAugmentation() {
|
||||
// Set Navigation to Terminal screen, for any logic that depends on it
|
||||
routing.navigateTo(Page.Terminal);
|
||||
|
||||
initBitNodeMultipliers(Player);
|
||||
|
||||
const megaCorpFactions = [
|
||||
@ -62,9 +52,6 @@ function prestigeAugmentation() {
|
||||
});
|
||||
Player.prestigeAugmentation();
|
||||
|
||||
Terminal.clear();
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
// Delete all Worker Scripts objects
|
||||
prestigeWorkerScripts();
|
||||
|
||||
@ -244,11 +231,6 @@ function prestigeSourceFile(flume) {
|
||||
// Messages
|
||||
initMessages();
|
||||
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "visible";
|
||||
Terminal.clear();
|
||||
Engine.loadTerminalContent();
|
||||
|
||||
// BitNode 3: Corporatocracy
|
||||
if (Player.bitNodeN === 3) {
|
||||
homeComp.messages.push(LiteratureNames.CorporationManagementHandbook);
|
||||
@ -258,56 +240,6 @@ function prestigeSourceFile(flume) {
|
||||
);
|
||||
}
|
||||
|
||||
// BitNode 6: Bladeburner
|
||||
if (Player.bitNodeN === 6) {
|
||||
var cinematicText = [
|
||||
"In the middle of the 21st century, OmniTek Incorporated advanced robot evolution " +
|
||||
"with their Synthoids (synthetic androids), a being virtually identical to a human.",
|
||||
"------",
|
||||
"Their sixth-generation Synthoids, called MK-VI, were stronger, faster, and more " +
|
||||
"intelligent than humans. Many argued that the MK-VI Synthoids were the first " +
|
||||
"example of sentient AI.",
|
||||
"------",
|
||||
"Unfortunately, in 2070 a terrorist group called Ascendis Totalis hacked into OmniTek and " +
|
||||
"uploaded a rogue AI into their Synthoid manufacturing facilities.",
|
||||
"------",
|
||||
"The MK-VI Synthoids infected by the rogue AI turned hostile toward humanity, initiating " +
|
||||
"the deadliest conflict in human history. This dark chapter is now known as the Synthoid Uprising.",
|
||||
"------",
|
||||
"In the aftermath of the Uprising, further manufacturing of Synthoids with advanced AI " +
|
||||
"was banned. MK-VI Synthoids that did not have the rogue Ascendis Totalis AI were " +
|
||||
"allowed to continue their existence.",
|
||||
"------",
|
||||
"The intelligence community believes that not all of the rogue MK-VI Synthoids from the Uprising were " +
|
||||
"found and destroyed, and that many of them are blending in as normal humans in society today. " +
|
||||
"As a result, many nations have created Bladeburner divisions, special units that are tasked with " +
|
||||
"investigating and dealing with Synthoid threats.",
|
||||
];
|
||||
writeCinematicText(cinematicText)
|
||||
.then(function () {
|
||||
var popupId = "bladeburner-bitnode-start-nsa-notification";
|
||||
var txt = createElement("p", {
|
||||
innerText:
|
||||
"Visit the National Security Agency (NSA) to apply for their Bladeburner " +
|
||||
"division! You will need 100 of each combat stat before doing this.",
|
||||
});
|
||||
var brEl = createElement("br");
|
||||
var okBtn = createElement("a", {
|
||||
class: "a-link-button",
|
||||
innerText: "Got it!",
|
||||
padding: "8px",
|
||||
clickListener: () => {
|
||||
removeElementById(popupId);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
createPopup(popupId, [txt, brEl, okBtn]);
|
||||
})
|
||||
.catch(function (e) {
|
||||
exceptionAlert(e);
|
||||
});
|
||||
}
|
||||
|
||||
// BitNode 8: Ghost of Wall Street
|
||||
if (Player.bitNodeN === 8) {
|
||||
Player.money = new Decimal(BitNode8StartingMoney);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { ITerminal } from "../Terminal/ITerminal";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "../ui/Router";
|
||||
|
||||
export interface IProgramCreate {
|
||||
level: number;
|
||||
@ -12,12 +13,12 @@ export interface IProgramCreate {
|
||||
export class Program {
|
||||
name = "";
|
||||
create: IProgramCreate | null;
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
create: IProgramCreate | null,
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void,
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void,
|
||||
) {
|
||||
this.name = name;
|
||||
this.create = create;
|
||||
|
@ -3,6 +3,7 @@ import { CONSTANTS } from "../../Constants";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { ITerminal } from "../../Terminal/ITerminal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../../utils/StringHelperFunctions";
|
||||
@ -30,7 +31,7 @@ export interface IProgramCreationParams {
|
||||
key: string;
|
||||
name: string;
|
||||
create: IProgramCreate | null;
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]) => void;
|
||||
}
|
||||
|
||||
export const programsMetadata: IProgramCreationParams[] = [
|
||||
@ -43,7 +44,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(1),
|
||||
time: CONSTANTS.MillisecondsPerFiveMinutes,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot nuke this kind of server.");
|
||||
return;
|
||||
@ -72,7 +73,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(50),
|
||||
time: CONSTANTS.MillisecondsPerFiveMinutes * 2,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot run BruteSSH.exe on this kind of server.");
|
||||
return;
|
||||
@ -96,7 +97,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(100),
|
||||
time: CONSTANTS.MillisecondsPerHalfHour,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot run FTPCrack.exe on this kind of server.");
|
||||
return;
|
||||
@ -120,7 +121,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(250),
|
||||
time: CONSTANTS.MillisecondsPer2Hours,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot run relaySMTP.exe on this kind of server.");
|
||||
return;
|
||||
@ -144,7 +145,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(500),
|
||||
time: CONSTANTS.MillisecondsPer4Hours,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot run HTTPWorm.exe on this kind of server.");
|
||||
return;
|
||||
@ -168,7 +169,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(750),
|
||||
time: CONSTANTS.MillisecondsPer8Hours,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer): void => {
|
||||
if (!(server instanceof Server)) {
|
||||
terminal.error("Cannot run SQLInject.exe on this kind of server.");
|
||||
return;
|
||||
@ -192,7 +193,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(75),
|
||||
time: CONSTANTS.MillisecondsPerQuarterHour,
|
||||
},
|
||||
run: (terminal: ITerminal): void => {
|
||||
run: (router: IRouter, terminal: ITerminal): void => {
|
||||
terminal.print("This executable cannot be run.");
|
||||
terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5.");
|
||||
},
|
||||
@ -206,7 +207,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(400),
|
||||
time: CONSTANTS.MillisecondsPer2Hours,
|
||||
},
|
||||
run: (terminal: ITerminal): void => {
|
||||
run: (router: IRouter, terminal: ITerminal): void => {
|
||||
terminal.print("This executable cannot be run.");
|
||||
terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
|
||||
},
|
||||
@ -220,7 +221,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(75),
|
||||
time: CONSTANTS.MillisecondsPerHalfHour,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer, server: BaseServer, args: string[]): void => {
|
||||
if (args.length !== 1) {
|
||||
terminal.print("Must pass a server hostname or IP as an argument for ServerProfiler.exe");
|
||||
return;
|
||||
@ -270,7 +271,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: requireHackingLevel(25),
|
||||
time: CONSTANTS.MillisecondsPerQuarterHour,
|
||||
},
|
||||
run: (terminal: ITerminal): void => {
|
||||
run: (router: IRouter, terminal: ITerminal): void => {
|
||||
terminal.print("This executable cannot be run.");
|
||||
terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'.");
|
||||
terminal.print("When using scan-analyze, click on a server's hostname to connect to it.");
|
||||
@ -285,10 +286,11 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
req: bitFlumeRequirements(),
|
||||
time: CONSTANTS.MillisecondsPerFiveMinutes / 20,
|
||||
},
|
||||
run: (terminal: ITerminal, player: IPlayer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer): void => {
|
||||
const popupId = "bitflume-popup";
|
||||
createPopup(popupId, BitFlumePopup, {
|
||||
player: player,
|
||||
router: router,
|
||||
popupId: popupId,
|
||||
});
|
||||
},
|
||||
@ -297,7 +299,7 @@ export const programsMetadata: IProgramCreationParams[] = [
|
||||
key: "Flight",
|
||||
name: "fl1ght.exe",
|
||||
create: null,
|
||||
run: (terminal: ITerminal, player: IPlayer): void => {
|
||||
run: (router: IRouter, terminal: ITerminal, player: IPlayer): void => {
|
||||
const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement * 30);
|
||||
const fulfilled =
|
||||
player.augmentations.length >= numAugReq && player.money.gt(1e11) && player.hacking_skill >= 2500;
|
||||
|
@ -1,15 +1,13 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { use } from "../../ui/Context";
|
||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
||||
|
||||
import { Box, ButtonGroup, Tooltip, Typography } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function ProgramsRoot(props: IProps): React.ReactElement {
|
||||
export function ProgramsRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
@ -31,13 +29,18 @@ export function ProgramsRoot(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
</Box>
|
||||
<ButtonGroup>
|
||||
{getAvailableCreatePrograms(props.player).map((program) => {
|
||||
{getAvailableCreatePrograms(player).map((program) => {
|
||||
const create = program.create;
|
||||
if (create === null) return <></>;
|
||||
|
||||
return (
|
||||
<Tooltip key={program.name} title={create.tooltip}>
|
||||
<Button onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
{program.name}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
6
src/RedPill.d.ts
vendored
6
src/RedPill.d.ts
vendored
@ -1,6 +1,2 @@
|
||||
export declare let redPillFlag: boolean;
|
||||
export declare function hackWorldDaemon(
|
||||
currentNodeNumber: number,
|
||||
flume: boolean = false,
|
||||
quick: boolean = false,
|
||||
): void;
|
||||
export declare function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number);
|
||||
|
@ -1,7 +1,6 @@
|
||||
/**
|
||||
* Implementation for what happens when you destroy a BitNode
|
||||
*/
|
||||
import { Engine } from "./engine";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeSourceFile } from "./Prestige";
|
||||
import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
|
||||
@ -9,20 +8,10 @@ import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { SourceFiles } from "./SourceFile/SourceFiles";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { BitverseRoot } from "./BitNode/ui/BitverseRoot";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
let redPillFlag = false;
|
||||
function hackWorldDaemon(currentNodeNumber, flume = false, quick = false) {
|
||||
// Clear the screen
|
||||
const container = document.getElementById("red-pill-container");
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
Engine.loadRedPillContent();
|
||||
ReactDOM.render(
|
||||
<BitverseRoot destroyedBitNodeNum={currentNodeNumber} flume={flume} enter={enterBitNode} quick={quick} />,
|
||||
container,
|
||||
);
|
||||
function hackWorldDaemon(router, flume = false, quick = false) {
|
||||
router.toBitVerse(flume, quick);
|
||||
redPillFlag = true;
|
||||
}
|
||||
|
||||
@ -68,12 +57,12 @@ function giveSourceFile(bitNodeNumber) {
|
||||
Player.intelligence = 1;
|
||||
}
|
||||
dialogBoxCreate(
|
||||
"You received a Source-File for destroying a Bit Node!<br><br>" + sourceFile.name + "<br><br>" + sourceFile.info,
|
||||
"You received a Source-File for destroying a BitNode!<br><br>" + sourceFile.name + "<br><br>" + sourceFile.info,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function enterBitNode(flume, destroyedBitNode, newBitNode) {
|
||||
export function enterBitNode(router, flume, destroyedBitNode, newBitNode) {
|
||||
if (!flume) {
|
||||
giveSourceFile(destroyedBitNode);
|
||||
} else {
|
||||
@ -86,12 +75,14 @@ function enterBitNode(flume, destroyedBitNode, newBitNode) {
|
||||
Player.intelligence = 1;
|
||||
}
|
||||
redPillFlag = false;
|
||||
const container = document.getElementById("red-pill-container");
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
// Set new Bit Node
|
||||
Player.bitNodeN = newBitNode;
|
||||
|
||||
if (newBitNode === 6) {
|
||||
router.toBladeburnerCinematic();
|
||||
} else {
|
||||
router.toTerminal();
|
||||
}
|
||||
prestigeSourceFile(flume);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
import { calculateRamUsage } from "./RamCalculations";
|
||||
import { ScriptUrl } from "./ScriptUrl";
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
|
||||
import { setTimeoutRef } from "../utils/SetTimeoutRef";
|
||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import clsx from "clsx";
|
||||
import { styled, useTheme, Theme, CSSObject } from "@mui/material/styles";
|
||||
import { styled, Theme, CSSObject } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import MuiDrawer from "@mui/material/Drawer";
|
||||
@ -15,8 +15,6 @@ import Typography from "@mui/material/Typography";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Badge from "@mui/material/Badge";
|
||||
|
||||
import { TTheme as BBTheme, colors } from "../../ui/React/Theme";
|
||||
|
||||
import ComputerIcon from "@mui/icons-material/Computer";
|
||||
import LastPageIcon from "@mui/icons-material/LastPage"; // Terminal
|
||||
import CreateIcon from "@mui/icons-material/Create"; // Create Script
|
||||
@ -57,8 +55,6 @@ import { cinematicTextFlag } from "../../CinematicText";
|
||||
import { KEY } from "../../../utils/helpers/keyCodes";
|
||||
import { FconfSettings } from "../../Fconf/FconfSettings";
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
width: theme.spacing(31),
|
||||
transition: theme.transitions.create("width", {
|
||||
@ -97,7 +93,7 @@ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== "open"
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
active: {
|
||||
borderLeft: "3px solid " + colors.primary,
|
||||
borderLeft: "3px solid " + theme.palette.primary.main,
|
||||
},
|
||||
listitem: {},
|
||||
}),
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { buyStock, sellStock, shortStock, sellShort } from "./BuyingAndSelling";
|
||||
import { IOrderBook } from "./IOrderBook";
|
||||
import { IStockMarket } from "./IStockMarket";
|
||||
import { Order } from "./Order";
|
||||
@ -9,23 +8,17 @@ import { InitStockMetadata } from "./data/InitStockMetadata";
|
||||
import { OrderTypes } from "./data/OrderTypes";
|
||||
import { PositionTypes } from "./data/PositionTypes";
|
||||
import { StockSymbols } from "./data/StockSymbols";
|
||||
import { StockMarketRoot } from "./ui/StockMarketRoot";
|
||||
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { Player } from "../Player";
|
||||
import { IMap } from "../types";
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
|
||||
import { Page, routing } from ".././ui/navigationTracking";
|
||||
import { numeralWrapper } from ".././ui/numeralFormat";
|
||||
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
export let StockMarket: IStockMarket = {
|
||||
lastUpdate: 0,
|
||||
Orders: {},
|
||||
@ -150,7 +143,6 @@ export function loadStockMarket(saveString: string): void {
|
||||
ticksUntilCycle: 0,
|
||||
} as IStockMarket;
|
||||
} else {
|
||||
console.log(JSON.parse(saveString, Reviver));
|
||||
StockMarket = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
}
|
||||
@ -314,14 +306,6 @@ export function processStockPrices(numCycles = 1): void {
|
||||
}
|
||||
}
|
||||
|
||||
let stockMarketContainer: HTMLElement | null = null;
|
||||
function setStockMarketContainer(): void {
|
||||
stockMarketContainer = document.getElementById("generic-react-container");
|
||||
document.removeEventListener("DOMContentLoaded", setStockMarketContainer);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", setStockMarketContainer);
|
||||
|
||||
export function initStockMarketFnForReact(): void {
|
||||
initStockMarket();
|
||||
initSymbolToStockMap();
|
||||
|
@ -36,7 +36,7 @@ type IProps = {
|
||||
stockMarket: IStockMarket;
|
||||
};
|
||||
|
||||
export function StockMarketRoot(props: IProps) {
|
||||
export function StockMarketRoot(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
|
@ -56,10 +56,10 @@ export interface ITerminal {
|
||||
startAnalyze(): void;
|
||||
startBackdoor(player: IPlayer): void;
|
||||
startHack(player: IPlayer): void;
|
||||
finishHack(player: IPlayer, cancelled?: boolean): void;
|
||||
finishBackdoor(player: IPlayer, cancelled?: boolean): void;
|
||||
finishHack(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
finishBackdoor(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
finishAnalyze(player: IPlayer, cancelled?: boolean): void;
|
||||
finishAction(player: IPlayer, cancelled?: boolean): void;
|
||||
finishAction(router: IRouter, player: IPlayer, cancelled?: boolean): void;
|
||||
getFilepath(filename: string): string;
|
||||
getFile(player: IPlayer, filename: string): Script | TextFile | string | null;
|
||||
getScript(player: IPlayer, filename: string): Script | null;
|
||||
@ -74,7 +74,7 @@ export interface ITerminal {
|
||||
executeCommands(router: IRouter, player: IPlayer, commands: string): void;
|
||||
// If there was any changes, will return true, once.
|
||||
pollChanges(): boolean;
|
||||
process(player: IPlayer, cycles: number): void;
|
||||
process(router: IRouter, player: IPlayer, cycles: number): void;
|
||||
prestige(): void;
|
||||
getProgressText(): string;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import { IRouter } from "../ui/Router";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
import { hackWorldDaemon } from "../RedPill";
|
||||
import { Programs } from "../Programs/Programs";
|
||||
import { CodingContractResult } from "../CodingContracts";
|
||||
|
||||
@ -86,11 +85,11 @@ export class Terminal implements ITerminal {
|
||||
// Excludes the trailing forward slash
|
||||
currDir = "/";
|
||||
|
||||
process(player: IPlayer, cycles: number): void {
|
||||
process(router: IRouter, player: IPlayer, cycles: number): void {
|
||||
if (this.action === null) return;
|
||||
this.action.timeLeft -= (CONSTANTS._idleSpeed * cycles) / 1000;
|
||||
this.hasChanges = true;
|
||||
if (this.action.timeLeft < 0) this.finishAction(player, false);
|
||||
if (this.action.timeLeft < 0) this.finishAction(router, player, false);
|
||||
}
|
||||
|
||||
pollChanges(): boolean {
|
||||
@ -138,7 +137,7 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
|
||||
// Complete the hack/analyze command
|
||||
finishHack(player: IPlayer, cancelled = false): void {
|
||||
finishHack(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (cancelled) return;
|
||||
const server = player.getCurrentServer();
|
||||
|
||||
@ -156,7 +155,7 @@ export class Terminal implements ITerminal {
|
||||
if (player.bitNodeN == null) {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
router.toBitVerse(false, false);
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
@ -190,7 +189,7 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
}
|
||||
|
||||
finishBackdoor(player: IPlayer, cancelled = false): void {
|
||||
finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (!cancelled) {
|
||||
const server = player.getCurrentServer();
|
||||
if (
|
||||
@ -200,7 +199,7 @@ export class Terminal implements ITerminal {
|
||||
if (player.bitNodeN == null) {
|
||||
player.bitNodeN = 1;
|
||||
}
|
||||
hackWorldDaemon(player.bitNodeN);
|
||||
router.toBitVerse(false, false);
|
||||
return;
|
||||
}
|
||||
server.backdoorInstalled = true;
|
||||
@ -238,16 +237,16 @@ export class Terminal implements ITerminal {
|
||||
}
|
||||
}
|
||||
|
||||
finishAction(player: IPlayer, cancelled = false): void {
|
||||
finishAction(router: IRouter, player: IPlayer, cancelled = false): void {
|
||||
if (this.action === null) {
|
||||
if (!cancelled) throw new Error("Finish action called when there was no action");
|
||||
return;
|
||||
}
|
||||
this.print(this.getProgressText());
|
||||
if (this.action.action === "h") {
|
||||
this.finishHack(player, cancelled);
|
||||
this.finishHack(router, player, cancelled);
|
||||
} else if (this.action.action === "b") {
|
||||
this.finishBackdoor(player, cancelled);
|
||||
this.finishBackdoor(router, player, cancelled);
|
||||
} else if (this.action.action === "a") {
|
||||
this.finishAnalyze(player, cancelled);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ export function runProgram(
|
||||
for (const program of Object.values(Programs)) {
|
||||
if (program.name === programName) {
|
||||
program.run(
|
||||
router,
|
||||
terminal,
|
||||
player,
|
||||
server,
|
||||
|
@ -17,21 +17,21 @@ import { FconfSettings } from "../../Fconf/FconfSettings";
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
textfield: {
|
||||
margin: 0,
|
||||
margin: theme.spacing(0),
|
||||
width: "100%",
|
||||
},
|
||||
input: {
|
||||
backgroundColor: "#000",
|
||||
},
|
||||
nopadding: {
|
||||
padding: 0,
|
||||
padding: theme.spacing(0),
|
||||
},
|
||||
preformatted: {
|
||||
whiteSpace: "pre-wrap",
|
||||
margin: 0,
|
||||
margin: theme.spacing(0),
|
||||
},
|
||||
list: {
|
||||
padding: 0,
|
||||
padding: theme.spacing(0),
|
||||
height: "100%",
|
||||
},
|
||||
}),
|
||||
@ -147,7 +147,7 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
|
||||
if (ref) ref.focus();
|
||||
// Cancel action
|
||||
if (event.keyCode === KEY.C && event.ctrlKey) {
|
||||
terminal.finishAction(player, true);
|
||||
terminal.finishAction(router, player, true);
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", keyDown);
|
||||
|
485
src/engine.jsx
485
src/engine.jsx
@ -1,74 +1,44 @@
|
||||
/**
|
||||
* Game engine. Handles the main game loop as well as the main UI pages
|
||||
*
|
||||
* TODO: Separate UI functionality into its own component
|
||||
* Game engine. Handles the main game loop.
|
||||
*/
|
||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import { initAugmentations, installAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||
import { onExport } from "./ExportBonus";
|
||||
import { AugmentationsRoot } from "./Augmentation/ui/Root";
|
||||
import { initAugmentations } from "./Augmentation/AugmentationHelpers";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
||||
import { CharacterOverview } from "./ui/React/CharacterOverview";
|
||||
import { generateRandomContract } from "./CodingContractGenerator";
|
||||
import { initCompanies } from "./Company/Companies";
|
||||
import { Corporation } from "./Corporation/Corporation";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { DevMenuRoot } from "./DevMenu";
|
||||
import { Factions, initFactions } from "./Faction/Factions";
|
||||
import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers";
|
||||
import { FactionsRoot } from "./Faction/ui/FactionsRoot";
|
||||
import { Root as BladeburnerRoot } from "./Bladeburner/ui/Root";
|
||||
import { Root as GangRoot } from "./Gang/ui/Root";
|
||||
import { SidebarRoot } from "./Sidebar/ui/SidebarRoot";
|
||||
import { CorporationRoot } from "./Corporation/ui/CorporationRoot";
|
||||
import { ResleeveRoot } from "./PersonObjects/Resleeving/ui/ResleeveRoot";
|
||||
import { GameOptionsRoot } from "./ui/React/GameOptionsRoot";
|
||||
import { GameRoot } from "./ui/GameRoot";
|
||||
import { GameRoot, Router } from "./ui/GameRoot";
|
||||
import { TTheme as Theme } from "./ui/React/Theme";
|
||||
import { SleeveRoot } from "./PersonObjects/Sleeve/ui/SleeveRoot";
|
||||
import { displayInfiltrationContent } from "./Infiltration/Helper";
|
||||
import {
|
||||
getHackingWorkRepGain,
|
||||
getFactionSecurityWorkRepGain,
|
||||
getFactionFieldWorkRepGain,
|
||||
} from "./PersonObjects/formulas/reputation";
|
||||
import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
||||
import { HacknetRoot } from "./Hacknet/ui/HacknetRoot";
|
||||
import { iTutorialStart } from "./InteractiveTutorial";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
import { LocationRoot } from "./Locations/ui/Root";
|
||||
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
|
||||
import { inMission, currMission } from "./Missions";
|
||||
import { workerScripts } from "./Netscript/WorkerScripts";
|
||||
import { loadAllRunningScripts, updateOnlineScriptTimes } from "./NetscriptWorker";
|
||||
import { Player } from "./Player";
|
||||
import { prestigeAugmentation } from "./Prestige";
|
||||
import { ProgramsRoot } from "./Programs/ui/ProgramsRoot";
|
||||
import { saveObject, loadGame } from "./SaveObject";
|
||||
import { Root as ScriptEditorRoot } from "./ScriptEditor/ui/Root";
|
||||
import { initForeignServers, AllServers } from "./Server/AllServers";
|
||||
import { initForeignServers } from "./Server/AllServers";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
||||
import { initSpecialServerIps } from "./Server/SpecialServerIps";
|
||||
import { initSymbolToStockMap, processStockPrices } from "./StockMarket/StockMarket";
|
||||
import { MilestonesRoot } from "./Milestones/ui/MilestonesRoot";
|
||||
import { TerminalRoot } from "./Terminal/ui/TerminalRoot";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { TutorialRoot } from "./Tutorial/ui/TutorialRoot";
|
||||
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
||||
|
||||
import { CharacterInfo } from "./ui/CharacterInfo";
|
||||
import { Page, routing } from "./ui/navigationTracking";
|
||||
import { Money } from "./ui/React/Money";
|
||||
import { Hashes } from "./ui/React/Hashes";
|
||||
import { Reputation } from "./ui/React/Reputation";
|
||||
|
||||
import { ActiveScriptsRoot } from "./ui/ActiveScripts/Root";
|
||||
import { MainMenuLinks } from "./ui/MainMenu/Links";
|
||||
|
||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
|
||||
@ -79,347 +49,19 @@ import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
const Engine = {
|
||||
// Clickable objects
|
||||
Clickables: {
|
||||
// Main menu buttons
|
||||
saveMainMenuButton: null,
|
||||
deleteMainMenuButton: null,
|
||||
},
|
||||
|
||||
// Display objects
|
||||
// TODO-Refactor this into its own component
|
||||
Display: {
|
||||
// Generic page that most react loads into.
|
||||
content: null,
|
||||
// Main menu content
|
||||
infiltrationContent: null,
|
||||
workInProgressContent: null,
|
||||
redPillContent: null,
|
||||
cinematicTextContent: null,
|
||||
missionContent: null,
|
||||
overview: null,
|
||||
},
|
||||
|
||||
indexedDb: undefined,
|
||||
|
||||
// Time variables (milliseconds unix epoch time)
|
||||
_lastUpdate: new Date().getTime(),
|
||||
_idleSpeed: 200, // Speed (in ms) at which the main loop is updated
|
||||
|
||||
loadTerminalContent: function () {
|
||||
// Engine.hideAllContent();
|
||||
// Engine.Display.content.style.display = "block";
|
||||
// routing.navigateTo(Page.CharacterInfo);
|
||||
// ReactDOM.render(
|
||||
// <Theme>
|
||||
// <TerminalRoot terminal={Terminal} engine={this} player={Player} />
|
||||
// </Theme>,
|
||||
// Engine.Display.content,
|
||||
// );
|
||||
// MainMenuLinks.Stats.classList.add("active");
|
||||
},
|
||||
|
||||
loadCharacterContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.CharacterInfo);
|
||||
ReactDOM.render(<CharacterInfo player={Player} />, Engine.Display.content);
|
||||
MainMenuLinks.Stats.classList.add("active");
|
||||
},
|
||||
|
||||
loadScriptEditorContent: function (filename = "", code = "") {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.ScriptEditor);
|
||||
MainMenuLinks.ScriptEditor.classList.add("active");
|
||||
ReactDOM.render(
|
||||
<ScriptEditorRoot filename={filename} code={code} player={Player} engine={this} />,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
loadActiveScriptsContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.ActiveScripts);
|
||||
MainMenuLinks.ActiveScripts.classList.add("active");
|
||||
ReactDOM.render(<ActiveScriptsRoot p={Player} workerScripts={workerScripts} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadHacknetNodesContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.HacknetNodes);
|
||||
MainMenuLinks.HacknetNodes.classList.add("active");
|
||||
ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadCreateProgramContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.CreateProgram);
|
||||
MainMenuLinks.CreateProgram.classList.add("active");
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<ProgramsRoot player={Player} />
|
||||
</Theme>,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
loadFactionsContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Factions);
|
||||
MainMenuLinks.Factions.classList.add("active");
|
||||
ReactDOM.render(<FactionsRoot player={Player} engine={this} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
// TODO reactify
|
||||
loadFactionContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Faction);
|
||||
},
|
||||
|
||||
loadAugmentationsContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Augmentations);
|
||||
MainMenuLinks.Augmentations.classList.add("active");
|
||||
|
||||
function backup() {
|
||||
saveObject.exportGame();
|
||||
onExport(Player);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<AugmentationsRoot exportGameFn={backup} installAugmentationsFn={installAugmentations} />,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
loadMilestonesContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Milestones);
|
||||
MainMenuLinks.Milestones.classList.add("active");
|
||||
ReactDOM.render(<MilestonesRoot player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadLocationContent: function (initiallyInCity = true) {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Location);
|
||||
MainMenuLinks.City.classList.add("active");
|
||||
ReactDOM.render(
|
||||
<LocationRoot initiallyInCity={initiallyInCity} engine={Engine} p={Player} />,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
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.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Location);
|
||||
MainMenuLinks.Travel.classList.add("active");
|
||||
ReactDOM.render(<LocationRoot initiallyInCity={false} engine={Engine} p={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
Engine.hideAllContent();
|
||||
Player.gotoLocation(Player.companyName);
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Location);
|
||||
MainMenuLinks.Job.classList.add("active");
|
||||
ReactDOM.render(<LocationRoot initiallyInCity={false} engine={Engine} p={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
// TODO reactify
|
||||
loadWorkInProgressContent: function () {
|
||||
Engine.hideAllContent();
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
console.log("hiding loadWorkInProgressContent");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
Engine.Display.workInProgressContent.style.display = "block";
|
||||
console.log(Engine.Display.workInProgressContent);
|
||||
routing.navigateTo(Page.WorkInProgress);
|
||||
},
|
||||
|
||||
loadRedPillContent: function () {
|
||||
Engine.hideAllContent();
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
Engine.Display.redPillContent.style.display = "block";
|
||||
routing.navigateTo(Page.RedPill);
|
||||
},
|
||||
|
||||
// TODO reactify
|
||||
loadCinematicTextContent: function () {
|
||||
Engine.hideAllContent();
|
||||
var mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
Engine.Display.cinematicTextContent.style.display = "block";
|
||||
routing.navigateTo(Page.CinematicText);
|
||||
},
|
||||
|
||||
// TODO reactify
|
||||
loadInfiltrationContent: function (name, difficulty, maxLevel) {
|
||||
Engine.hideAllContent();
|
||||
const mainMenu = document.getElementById("mainmenu-container");
|
||||
mainMenu.style.visibility = "hidden";
|
||||
Engine.Display.infiltrationContent.style.display = "block";
|
||||
routing.navigateTo(Page.Infiltration);
|
||||
displayInfiltrationContent(this, Player, name, difficulty, maxLevel);
|
||||
},
|
||||
|
||||
loadStockMarketContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.StockMarket);
|
||||
MainMenuLinks.StockMarket.classList.add("active");
|
||||
//displayStockMarketContent();
|
||||
},
|
||||
|
||||
loadGangContent: function () {
|
||||
if (!Player.inGang()) return;
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Gang);
|
||||
MainMenuLinks.Gang.classList.add("active");
|
||||
ReactDOM.render(<GangRoot engine={this} gang={Player.gang} player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadMissionContent: function () {
|
||||
Engine.hideAllContent();
|
||||
document.getElementById("mainmenu-container").style.visibility = "hidden";
|
||||
document.getElementById("character-overview").style.visibility = "hidden";
|
||||
Engine.Display.missionContent.style.display = "block";
|
||||
routing.navigateTo(Page.Mission);
|
||||
},
|
||||
|
||||
loadCorporationContent: function () {
|
||||
if (!(Player.corporation instanceof Corporation)) return;
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Corporation);
|
||||
MainMenuLinks.Corporation.classList.add("active");
|
||||
ReactDOM.render(<CorporationRoot corp={Player.corporation} player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadBladeburnerContent: function () {
|
||||
if (!(Player.bladeburner instanceof Bladeburner)) return;
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Bladeburner);
|
||||
MainMenuLinks.Bladeburner.classList.add("active");
|
||||
ReactDOM.render(
|
||||
<BladeburnerRoot bladeburner={Player.bladeburner} player={Player} engine={this} />,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
loadSleevesContent: function () {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.content.style.display = "block";
|
||||
routing.navigateTo(Page.Sleeves);
|
||||
ReactDOM.render(<SleeveRoot player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadResleevingContent: function () {
|
||||
Engine.hideAllContent();
|
||||
routing.navigateTo(Page.Resleeves);
|
||||
Engine.Display.content.style.display = "block";
|
||||
MainMenuLinks.City.classList.add("active");
|
||||
ReactDOM.render(<ResleeveRoot player={Player} />, Engine.Display.content);
|
||||
},
|
||||
|
||||
loadGameOptionsContent: function () {
|
||||
Engine.hideAllContent();
|
||||
routing.navigateTo(Page.GameOptions);
|
||||
Engine.Display.content.style.display = "block";
|
||||
MainMenuLinks.City.classList.add("active");
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<GameOptionsRoot
|
||||
player={Player}
|
||||
save={() => saveObject.saveGame(Engine.indexedDb)}
|
||||
delete={() => saveObject.deleteGame(Engine.indexedDb)}
|
||||
export={() => saveObject.exportGame()}
|
||||
import={() => saveObject.importGame()}
|
||||
forceKill={() => {
|
||||
for (const hostname of Object.keys(AllServers)) {
|
||||
AllServers[hostname].runningScripts = [];
|
||||
}
|
||||
dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
|
||||
}}
|
||||
softReset={() => {
|
||||
dialogBoxCreate("Soft Reset!");
|
||||
prestigeAugmentation();
|
||||
}}
|
||||
/>
|
||||
</Theme>,
|
||||
Engine.Display.content,
|
||||
);
|
||||
},
|
||||
|
||||
// Helper function that hides all content
|
||||
hideAllContent: function () {
|
||||
// Engine.Display.content.style.display = "none";
|
||||
// Engine.Display.content.scrollTop = 0;
|
||||
// ReactDOM.unmountComponentAtNode(Engine.Display.content);
|
||||
|
||||
Engine.Display.infiltrationContent.style.display = "none";
|
||||
ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent);
|
||||
|
||||
Engine.Display.workInProgressContent.style.display = "none";
|
||||
Engine.Display.redPillContent.style.display = "none";
|
||||
Engine.Display.cinematicTextContent.style.display = "none";
|
||||
Engine.Display.missionContent.style.display = "none";
|
||||
},
|
||||
|
||||
displayCharacterOverviewInfo: function () {
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<CharacterOverview player={Player} save={() => saveObject.saveGame(Engine.indexedDb)} />
|
||||
</Theme>,
|
||||
document.getElementById("character-overview"),
|
||||
);
|
||||
},
|
||||
|
||||
// Main Game Loop
|
||||
idleTimer: function () {
|
||||
// Get time difference
|
||||
const _thisUpdate = new Date().getTime();
|
||||
let diff = _thisUpdate - Engine._lastUpdate;
|
||||
const offset = diff % Engine._idleSpeed;
|
||||
|
||||
// Divide this by cycle time to determine how many cycles have elapsed since last update
|
||||
diff = Math.floor(diff / Engine._idleSpeed);
|
||||
|
||||
if (diff > 0) {
|
||||
// Update the game engine by the calculated number of cycles
|
||||
Engine._lastUpdate = _thisUpdate - offset;
|
||||
Player.lastUpdate = _thisUpdate - offset;
|
||||
Engine.updateGame(diff);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(Engine.idleTimer);
|
||||
},
|
||||
|
||||
updateGame: function (numCycles = 1) {
|
||||
const time = numCycles * Engine._idleSpeed;
|
||||
const time = numCycles * CONSTANTS._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {
|
||||
Player.totalPlaytime = 0;
|
||||
}
|
||||
@ -433,7 +75,7 @@ const Engine = {
|
||||
Player.playtimeSinceLastAug += time;
|
||||
Player.playtimeSinceLastBitnode += time;
|
||||
|
||||
Terminal.process(Player, numCycles);
|
||||
Terminal.process(Router, Player, numCycles);
|
||||
|
||||
// Working
|
||||
if (Player.isWorking) {
|
||||
@ -581,7 +223,7 @@ const Engine = {
|
||||
}
|
||||
if (Player.bladeburner instanceof Bladeburner) {
|
||||
try {
|
||||
Player.bladeburner.process(Player);
|
||||
Player.bladeburner.process(Router, Player);
|
||||
} catch (e) {
|
||||
exceptionAlert("Exception caught in Bladeburner.process(): " + e);
|
||||
}
|
||||
@ -598,42 +240,11 @@ const Engine = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used in game when clicking on a main menu header (NOT used for initialization)
|
||||
* @param open {boolean} Whether header is being opened or closed
|
||||
* @param elems {HTMLElement[]} li Elements under header
|
||||
* @param links {HTMLElement[]} a elements under header
|
||||
*/
|
||||
toggleMainMenuHeader: function (open, elems, links) {
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
if (open) {
|
||||
elems[i].style.opacity = 1;
|
||||
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
||||
} else {
|
||||
elems[i].style.opacity = 0;
|
||||
elems[i].style.maxHeight = null;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < links.length; ++i) {
|
||||
if (open) {
|
||||
links[i].style.opacity = 1;
|
||||
links[i].style.maxHeight = links[i].scrollHeight + "px";
|
||||
links[i].style.pointerEvents = "auto";
|
||||
} else {
|
||||
links[i].style.opacity = 0;
|
||||
links[i].style.maxHeight = null;
|
||||
links[i].style.pointerEvents = "none";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
load: function (saveString) {
|
||||
// Load game from save or create new game
|
||||
if (loadGame(saveString)) {
|
||||
initBitNodeMultipliers(Player);
|
||||
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
||||
Engine.init(); // Initialize buttons, work, etc.
|
||||
updateSourceFileFlags(Player);
|
||||
initAugmentations(); // Also calls Player.reapplyAllAugmentations()
|
||||
Player.reapplyAllSourceFiles();
|
||||
@ -645,7 +256,7 @@ const Engine = {
|
||||
Engine._lastUpdate = new Date().getTime();
|
||||
const lastUpdate = Player.lastUpdate;
|
||||
const timeOffline = Engine._lastUpdate - lastUpdate;
|
||||
const numCyclesOffline = Math.floor(timeOffline / Engine._idleSpeed);
|
||||
const numCyclesOffline = Math.floor(timeOffline / CONSTANTS._idleSpeed);
|
||||
|
||||
let offlineReputation = 0;
|
||||
const offlineHackingIncome = (Player.moneySourceA.hacking / Player.playtimeSinceLastAug) * timeOffline * 0.75;
|
||||
@ -667,6 +278,7 @@ const Engine = {
|
||||
} else {
|
||||
Player.work(numCyclesOffline);
|
||||
}
|
||||
Player.focus = false;
|
||||
} else {
|
||||
for (let i = 0; i < Player.factions.length; i++) {
|
||||
const facName = Player.factions[i];
|
||||
@ -741,7 +353,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Update total playtime
|
||||
var time = numCyclesOffline * Engine._idleSpeed;
|
||||
var time = numCyclesOffline * CONSTANTS._idleSpeed;
|
||||
if (Player.totalPlaytime == null) {
|
||||
Player.totalPlaytime = 0;
|
||||
}
|
||||
@ -794,72 +406,27 @@ const Engine = {
|
||||
},
|
||||
|
||||
setDisplayElements: function () {
|
||||
// Engine.Display.content = document.getElementById("generic-react-container");
|
||||
// Engine.Display.content.style.display = "none";
|
||||
|
||||
Engine.Display.missionContent = document.getElementById("mission-container");
|
||||
Engine.Display.missionContent.style.display = "none";
|
||||
|
||||
// Work In Progress
|
||||
Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container");
|
||||
Engine.Display.workInProgressContent.style.display = "none";
|
||||
|
||||
// Red Pill / Hack World Daemon
|
||||
Engine.Display.redPillContent = document.getElementById("red-pill-container");
|
||||
Engine.Display.redPillContent.style.display = "none";
|
||||
|
||||
Engine.Display.infiltrationContent = document.getElementById("infiltration-container");
|
||||
Engine.Display.infiltrationContent.style.display = "none";
|
||||
|
||||
// Cinematic Text
|
||||
Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container");
|
||||
Engine.Display.cinematicTextContent.style.display = "none";
|
||||
|
||||
Engine.Display.overview = document.getElementById("character-overview");
|
||||
},
|
||||
|
||||
// Initialization
|
||||
init: function () {
|
||||
// Player was working cancel button
|
||||
|
||||
Engine.displayCharacterOverviewInfo();
|
||||
if (Player.isWorking) {
|
||||
var cancelButton = document.getElementById("work-in-progress-cancel-button");
|
||||
cancelButton.addEventListener("click", function () {
|
||||
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
||||
Player.finishFactionWork(true);
|
||||
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
|
||||
Player.finishCreateProgramWork(true);
|
||||
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
|
||||
Player.finishClass();
|
||||
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
|
||||
Player.finishCrime(true);
|
||||
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
||||
Player.finishWorkPartTime();
|
||||
} else {
|
||||
Player.finishWork(true);
|
||||
}
|
||||
});
|
||||
|
||||
const focusButton = document.getElementById("work-in-progress-something-else-button");
|
||||
focusButton.style.visibility = "hidden";
|
||||
const focusable = [CONSTANTS.WorkTypeFaction, CONSTANTS.WorkTypeCompanyPartTime, CONSTANTS.WorkTypeCompany];
|
||||
if (focusable.includes(Player.workType)) {
|
||||
focusButton.style.visibility = "visible";
|
||||
focusButton.addEventListener("click", function () {
|
||||
Player.stopFocusing();
|
||||
});
|
||||
}
|
||||
|
||||
Engine.loadWorkInProgressContent();
|
||||
} else {
|
||||
Engine.loadTerminalContent();
|
||||
}
|
||||
},
|
||||
|
||||
start: function () {
|
||||
// Run main loop
|
||||
Engine.idleTimer();
|
||||
// Get time difference
|
||||
const _thisUpdate = new Date().getTime();
|
||||
let diff = _thisUpdate - Engine._lastUpdate;
|
||||
const offset = diff % CONSTANTS._idleSpeed;
|
||||
|
||||
// Divide this by cycle time to determine how many cycles have elapsed since last update
|
||||
diff = Math.floor(diff / CONSTANTS._idleSpeed);
|
||||
|
||||
if (diff > 0) {
|
||||
// Update the game engine by the calculated number of cycles
|
||||
Engine._lastUpdate = _thisUpdate - offset;
|
||||
Player.lastUpdate = _thisUpdate - offset;
|
||||
Engine.updateGame(diff);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(Engine.start);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -45,25 +45,8 @@
|
||||
<div id="generic-react-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="infiltration-container" class="generic-fullscreen-container"></div>
|
||||
<div id="mission-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Work in progress screen -->
|
||||
<div id="work-in-progress-container" class="generic-fullscreen-container">
|
||||
<p id="work-in-progress-text"></p>
|
||||
|
||||
<button id="work-in-progress-cancel-button" class="work-button">Cancel Work</button>
|
||||
<button id="work-in-progress-something-else-button" class="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Red Pill Container -->
|
||||
<div id="red-pill-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Cinematic Text Container -->
|
||||
<div id="cinematic-text-container" class="generic-fullscreen-container"></div>
|
||||
|
||||
<!-- Interactive Tutorial Text Screen -->
|
||||
<div id="interactive-tutorial-wrapper">
|
||||
<div id="interactive-tutorial-container">
|
||||
@ -74,9 +57,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Character Overview Screen -->
|
||||
<div id="character-overview"></div>
|
||||
|
||||
<!-- Status text -->
|
||||
<div id="status-text-container">
|
||||
<p id="status-text"></p>
|
||||
|
19
src/ui/Context.ts
Normal file
19
src/ui/Context.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import React, { useContext } from "react";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { IRouter } from "./Router";
|
||||
|
||||
export const Context: {
|
||||
Player: React.Context<IPlayer>;
|
||||
Router: React.Context<IRouter>;
|
||||
} = {
|
||||
Player: React.createContext<IPlayer>({} as IPlayer),
|
||||
Router: React.createContext<IRouter>({} as IRouter),
|
||||
};
|
||||
|
||||
export const use: {
|
||||
Player: () => IPlayer;
|
||||
Router: () => IRouter;
|
||||
} = {
|
||||
Player: () => useContext(Context.Player),
|
||||
Router: () => useContext(Context.Router),
|
||||
};
|
@ -7,11 +7,11 @@ import { installAugmentations } from "../Augmentation/AugmentationHelpers";
|
||||
import { saveObject } from "../SaveObject";
|
||||
import { onExport } from "../ExportBonus";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
import { CityName } from "../Locations/data/CityNames";
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { prestigeAugmentation } from "../Prestige";
|
||||
import { dialogBoxCreate } from "../../utils/DialogBox";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling";
|
||||
import {
|
||||
cancelOrder,
|
||||
@ -29,12 +29,14 @@ import Typography from "@mui/material/Typography";
|
||||
|
||||
import { Page, IRouter } from "./Router";
|
||||
import { SidebarRoot } from "../Sidebar/ui/SidebarRoot";
|
||||
import { AugmentationsRoot } from "../Augmentation/ui/Root";
|
||||
import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot";
|
||||
import { DevMenuRoot } from "../DevMenu";
|
||||
import { Root as BladeburnerRoot } from "../Bladeburner/ui/Root";
|
||||
import { Root as GangRoot } from "../Gang/ui/Root";
|
||||
import { BladeburnerRoot } from "../Bladeburner/ui/BladeburnerRoot";
|
||||
import { GangRoot } from "../Gang/ui/GangRoot";
|
||||
import { CorporationRoot } from "../Corporation/ui/CorporationRoot";
|
||||
import { InfiltrationRoot } from "../Infiltration/ui/InfiltrationRoot";
|
||||
import { ResleeveRoot } from "../PersonObjects/Resleeving/ui/ResleeveRoot";
|
||||
import { WorkInProgressRoot } from "./WorkInProgressRoot";
|
||||
import { GameOptionsRoot } from "../ui/React/GameOptionsRoot";
|
||||
import { SleeveRoot } from "../PersonObjects/Sleeve/ui/SleeveRoot";
|
||||
import { HacknetRoot } from "../Hacknet/ui/HacknetRoot";
|
||||
@ -44,15 +46,20 @@ import { Root as ScriptEditorRoot } from "../ScriptEditor/ui/Root";
|
||||
import { MilestonesRoot } from "../Milestones/ui/MilestonesRoot";
|
||||
import { TerminalRoot } from "../Terminal/ui/TerminalRoot";
|
||||
import { TutorialRoot } from "../Tutorial/ui/TutorialRoot";
|
||||
import { ActiveScriptsRoot } from "../ui/ActiveScripts/Root";
|
||||
import { ActiveScriptsRoot } from "../ui/ActiveScripts/ActiveScriptsRoot";
|
||||
import { FactionsRoot } from "../Faction/ui/FactionsRoot";
|
||||
import { FactionRoot } from "../Faction/ui/FactionRoot";
|
||||
import { CharacterInfo } from "./CharacterInfo";
|
||||
import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot";
|
||||
import { StockMarketRoot } from "../StockMarket/ui/StockMarketRoot";
|
||||
import { BitverseRoot } from "../BitNode/ui/BitverseRoot";
|
||||
import { CharacterOverview } from "./React/CharacterOverview";
|
||||
import { BladeburnerCinematic } from "../Bladeburner/ui/BladeburnerCinematic";
|
||||
import { workerScripts } from "../Netscript/WorkerScripts";
|
||||
|
||||
import { startHackingMission } from "../Faction/FactionHelpers";
|
||||
import { enterBitNode } from "../RedPill";
|
||||
import { Context } from "./Context";
|
||||
|
||||
interface IProps {
|
||||
terminal: ITerminal;
|
||||
@ -65,6 +72,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
root: {
|
||||
"-ms-overflow-style": "none" /* for Internet Explorer, Edge */,
|
||||
"scrollbar-width": "none" /* for Firefox */,
|
||||
margin: theme.spacing(0),
|
||||
},
|
||||
}),
|
||||
);
|
||||
@ -72,13 +80,111 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
let filename = "";
|
||||
let code = "";
|
||||
|
||||
export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement {
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [faction, setFaction] = useState<Faction | null>(null);
|
||||
const [page, setPage] = useState(Page.Terminal);
|
||||
const classes = useStyles();
|
||||
export let Router: IRouter = {
|
||||
page: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toActiveScripts: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toAugmentations: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toBitVerse: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toBladeburner: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toCharacterInfo: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toCity: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toCorporation: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toCreateProgram: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toDevMenu: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toFaction: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toFactions: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toGameOptions: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toGang: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toHacknetNodes: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toInfiltration: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toJob: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toMilestones: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toResleeves: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toScriptEditor: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toSleeves: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toStockMarket: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toTerminal: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toTravel: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toTutorial: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toWork: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toBladeburnerCinematic: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
};
|
||||
|
||||
const router = {
|
||||
function determineStartPage(player: IPlayer): Page {
|
||||
if (player.isWorking) return Page.Work;
|
||||
return Page.Terminal;
|
||||
}
|
||||
|
||||
export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement {
|
||||
const classes = useStyles();
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [faction, setFaction] = useState<Faction | null>(
|
||||
player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : null,
|
||||
);
|
||||
const [page, setPage] = useState(determineStartPage(player));
|
||||
|
||||
const [flume, setFlume] = useState<boolean>(false);
|
||||
const [quick, setQuick] = useState<boolean>(false);
|
||||
const [location, setLocation] = useState<LocationName>(LocationName.Sector12);
|
||||
|
||||
const [cinematicText, setCinematicText] = useState("");
|
||||
|
||||
Router = {
|
||||
page: () => page,
|
||||
toActiveScripts: () => setPage(Page.ActiveScripts),
|
||||
toAugmentations: () => setPage(Page.Augmentations),
|
||||
toBladeburner: () => setPage(Page.Bladeburner),
|
||||
@ -86,9 +192,9 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
toCorporation: () => setPage(Page.Corporation),
|
||||
toCreateProgram: () => setPage(Page.CreateProgram),
|
||||
toDevMenu: () => setPage(Page.DevMenu),
|
||||
toFaction: (faction: Faction) => {
|
||||
toFaction: (faction?: Faction) => {
|
||||
setPage(Page.Faction);
|
||||
setFaction(faction);
|
||||
if (faction) setFaction(faction);
|
||||
},
|
||||
toFactions: () => setPage(Page.Factions),
|
||||
toGameOptions: () => setPage(Page.Options),
|
||||
@ -110,7 +216,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
setPage(Page.Job);
|
||||
},
|
||||
toCity: () => {
|
||||
// TODO This is bad.
|
||||
// TODO This conversion is bad.
|
||||
player.gotoLocation(player.city as unknown as LocationName);
|
||||
setPage(Page.City);
|
||||
},
|
||||
@ -118,6 +224,20 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
player.gotoLocation(LocationName.TravelAgency);
|
||||
setPage(Page.Travel);
|
||||
},
|
||||
toBitVerse: (flume: boolean, quick: boolean) => {
|
||||
setFlume(flume);
|
||||
setQuick(quick);
|
||||
setPage(Page.BitVerse);
|
||||
},
|
||||
toInfiltration: (location: LocationName) => {
|
||||
setLocation(location);
|
||||
setPage(Page.Infiltration);
|
||||
},
|
||||
toWork: () => setPage(Page.Work),
|
||||
toBladeburnerCinematic: () => {
|
||||
setPage(Page.BladeburnerCinematic);
|
||||
setCinematicText(cinematicText);
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -126,94 +246,119 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box display="flex" flexDirection="row" width="100%">
|
||||
<SidebarRoot player={player} router={router} page={page} />
|
||||
<Box ref={contentRef} className={classes.root} flexGrow={1} display="block" width="100%" px={1} height="100vh">
|
||||
{page === Page.Terminal ? (
|
||||
<TerminalRoot terminal={terminal} router={router} player={player} />
|
||||
) : page === Page.Sleeves ? (
|
||||
<SleeveRoot player={player} />
|
||||
) : page === Page.Stats ? (
|
||||
<CharacterInfo player={player} />
|
||||
) : page === Page.CreateScript ? (
|
||||
<ScriptEditorRoot filename={filename} code={code} player={player} router={router} />
|
||||
) : page === Page.ActiveScripts ? (
|
||||
<ActiveScriptsRoot p={player} workerScripts={workerScripts} />
|
||||
) : page === Page.Hacknet ? (
|
||||
<HacknetRoot player={player} />
|
||||
) : page === Page.CreateProgram ? (
|
||||
<ProgramsRoot player={player} />
|
||||
) : page === Page.Factions ? (
|
||||
<FactionsRoot player={player} router={router} />
|
||||
) : page === Page.Faction ? (
|
||||
<FactionRoot engine={engine} faction={faction} p={player} startHackingMissionFn={startHackingMission} />
|
||||
) : page === Page.Milestones ? (
|
||||
<MilestonesRoot player={player} />
|
||||
) : page === Page.Tutorial ? (
|
||||
<TutorialRoot />
|
||||
) : page === Page.DevMenu ? (
|
||||
<DevMenuRoot player={player} engine={engine} />
|
||||
) : page === Page.Gang ? (
|
||||
<GangRoot engine={engine} gang={player.gang} player={player} />
|
||||
) : page === Page.Corporation ? (
|
||||
<CorporationRoot corp={player.corporation} player={player} />
|
||||
) : page === Page.Bladeburner ? (
|
||||
<BladeburnerRoot bladeburner={player.bladeburner} player={player} engine={engine} />
|
||||
) : page === Page.Resleeves ? (
|
||||
<ResleeveRoot player={player} />
|
||||
) : page === Page.Travel ? (
|
||||
<TravelAgencyRoot p={player} router={router} />
|
||||
) : page === Page.StockMarket ? (
|
||||
<StockMarketRoot
|
||||
buyStockLong={buyStock}
|
||||
buyStockShort={shortStock}
|
||||
cancelOrder={cancelOrder}
|
||||
eventEmitterForReset={eventEmitterForUiReset}
|
||||
initStockMarket={initStockMarketFnForReact}
|
||||
p={player}
|
||||
placeOrder={placeOrder}
|
||||
sellStockLong={sellStock}
|
||||
sellStockShort={sellShort}
|
||||
stockMarket={StockMarket}
|
||||
/>
|
||||
) : page === Page.City ? (
|
||||
<LocationRoot initiallyInCity={true} engine={engine} p={player} router={router} />
|
||||
) : page === Page.Job ? (
|
||||
<LocationRoot initiallyInCity={false} engine={engine} p={player} router={router} />
|
||||
) : page === Page.Options ? (
|
||||
<GameOptionsRoot
|
||||
player={player}
|
||||
save={() => saveObject.saveGame(engine.indexedDb)}
|
||||
delete={() => saveObject.deleteGame(engine.indexedDb)}
|
||||
export={() => saveObject.exportGame()}
|
||||
import={() => saveObject.importGame()}
|
||||
forceKill={() => {
|
||||
for (const hostname of Object.keys(AllServers)) {
|
||||
AllServers[hostname].runningScripts = [];
|
||||
}
|
||||
dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
|
||||
}}
|
||||
softReset={() => {
|
||||
dialogBoxCreate("Soft Reset!");
|
||||
prestigeAugmentation();
|
||||
}}
|
||||
/>
|
||||
) : page === Page.Augmentations ? (
|
||||
<AugmentationsRoot
|
||||
exportGameFn={() => {
|
||||
saveObject.exportGame();
|
||||
onExport(player);
|
||||
}}
|
||||
installAugmentationsFn={installAugmentations}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<Typography>Cannot load</Typography>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
<Context.Player.Provider value={player}>
|
||||
<Context.Router.Provider value={Router}>
|
||||
<CharacterOverview save={() => saveObject.saveGame(engine.indexedDb)} />
|
||||
{page === Page.BitVerse ? (
|
||||
<BitverseRoot flume={flume} enter={enterBitNode} quick={quick} />
|
||||
) : page === Page.Infiltration ? (
|
||||
<InfiltrationRoot location={location} />
|
||||
) : page === Page.BladeburnerCinematic ? (
|
||||
<BladeburnerCinematic />
|
||||
) : page === Page.Work ? (
|
||||
<WorkInProgressRoot />
|
||||
) : (
|
||||
<Box display="flex" flexDirection="row" width="100%">
|
||||
<SidebarRoot player={player} router={Router} page={page} />
|
||||
<Box
|
||||
ref={contentRef}
|
||||
className={classes.root}
|
||||
flexGrow={1}
|
||||
display="block"
|
||||
width="100%"
|
||||
px={1}
|
||||
height="100vh"
|
||||
>
|
||||
{page === Page.Terminal ? (
|
||||
<TerminalRoot terminal={terminal} router={Router} player={player} />
|
||||
) : page === Page.Sleeves ? (
|
||||
<SleeveRoot player={player} />
|
||||
) : page === Page.Stats ? (
|
||||
<CharacterInfo player={player} />
|
||||
) : page === Page.CreateScript ? (
|
||||
<ScriptEditorRoot filename={filename} code={code} player={player} router={Router} />
|
||||
) : page === Page.ActiveScripts ? (
|
||||
<ActiveScriptsRoot p={player} workerScripts={workerScripts} />
|
||||
) : page === Page.Hacknet ? (
|
||||
<HacknetRoot player={player} />
|
||||
) : page === Page.CreateProgram ? (
|
||||
<ProgramsRoot />
|
||||
) : page === Page.Factions ? (
|
||||
<FactionsRoot player={player} router={Router} />
|
||||
) : page === Page.Faction ? (
|
||||
<FactionRoot faction={faction} startHackingMissionFn={startHackingMission} />
|
||||
) : page === Page.Milestones ? (
|
||||
<MilestonesRoot player={player} />
|
||||
) : page === Page.Tutorial ? (
|
||||
<TutorialRoot />
|
||||
) : page === Page.DevMenu ? (
|
||||
<DevMenuRoot player={player} engine={engine} router={Router} />
|
||||
) : page === Page.Gang ? (
|
||||
<GangRoot gang={player.gang} />
|
||||
) : page === Page.Corporation ? (
|
||||
<CorporationRoot corp={player.corporation} player={player} />
|
||||
) : page === Page.Bladeburner ? (
|
||||
<BladeburnerRoot bladeburner={player.bladeburner} />
|
||||
) : page === Page.Resleeves ? (
|
||||
<ResleeveRoot player={player} />
|
||||
) : page === Page.Travel ? (
|
||||
<TravelAgencyRoot p={player} router={Router} />
|
||||
) : page === Page.StockMarket ? (
|
||||
<StockMarketRoot
|
||||
buyStockLong={buyStock}
|
||||
buyStockShort={shortStock}
|
||||
cancelOrder={cancelOrder}
|
||||
eventEmitterForReset={eventEmitterForUiReset}
|
||||
initStockMarket={initStockMarketFnForReact}
|
||||
p={player}
|
||||
placeOrder={placeOrder}
|
||||
sellStockLong={sellStock}
|
||||
sellStockShort={sellShort}
|
||||
stockMarket={StockMarket}
|
||||
/>
|
||||
) : page === Page.City ? (
|
||||
<LocationRoot initiallyInCity={true} engine={engine} p={player} router={Router} />
|
||||
) : page === Page.Job ? (
|
||||
<LocationRoot initiallyInCity={false} engine={engine} p={player} router={Router} />
|
||||
) : page === Page.Options ? (
|
||||
<GameOptionsRoot
|
||||
player={player}
|
||||
save={() => saveObject.saveGame(engine.indexedDb)}
|
||||
delete={() => saveObject.deleteGame(engine.indexedDb)}
|
||||
export={() => saveObject.exportGame()}
|
||||
import={() => saveObject.importGame()}
|
||||
forceKill={() => {
|
||||
for (const hostname of Object.keys(AllServers)) {
|
||||
AllServers[hostname].runningScripts = [];
|
||||
}
|
||||
dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
|
||||
}}
|
||||
softReset={() => {
|
||||
dialogBoxCreate("Soft Reset!");
|
||||
prestigeAugmentation();
|
||||
Router.toTerminal();
|
||||
}}
|
||||
/>
|
||||
) : page === Page.Augmentations ? (
|
||||
<AugmentationsRoot
|
||||
exportGameFn={() => {
|
||||
saveObject.exportGame();
|
||||
onExport(player);
|
||||
}}
|
||||
installAugmentationsFn={() => {
|
||||
installAugmentations();
|
||||
Router.toTerminal();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<Typography>Cannot load</Typography>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Context.Router.Provider>
|
||||
</Context.Player.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -2,20 +2,16 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Reputation } from "./Reputation";
|
||||
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Button from "@mui/material/Button";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Fab from "@mui/material/Fab";
|
||||
@ -23,15 +19,17 @@ import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||
|
||||
import { colors } from "./Theme";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Page } from "../../ui/Router";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
save: () => void;
|
||||
}
|
||||
|
||||
function Intelligence({ player }: { player: IPlayer }): React.ReactElement {
|
||||
if (player.intelligence === 0) return <></>;
|
||||
function Intelligence(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const classes = useStyles();
|
||||
if (player.intelligence === 0) return <></>;
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
||||
@ -44,9 +42,11 @@ function Intelligence({ player }: { player: IPlayer }): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
function Work({ player }: { player: IPlayer }): React.ReactElement {
|
||||
if (!player.isWorking || player.focus) return <></>;
|
||||
function Work(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const classes = useStyles();
|
||||
if (!player.isWorking || player.focus) return <></>;
|
||||
return (
|
||||
<>
|
||||
<TableRow>
|
||||
@ -61,7 +61,14 @@ function Work({ player }: { player: IPlayer }): React.ReactElement {
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row" align="center" colSpan={2} classes={{ root: classes.cellNone }}>
|
||||
<Button onClick={() => player.startFocusing()}>Focus</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
player.startFocusing();
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
Focus
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
@ -101,7 +108,12 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
export function CharacterOverview({ player, save }: IProps): React.ReactElement {
|
||||
export function CharacterOverview({ save }: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
|
||||
if (router.page() === Page.BitVerse) return <></>;
|
||||
|
||||
const setRerender = useState(false)[1];
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
@ -112,7 +124,7 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<>
|
||||
<div style={{ position: "fixed", top: 0, right: 0, zIndex: 1500 }}>
|
||||
<Box display="flex" justifyContent="flex-end" flexDirection={"column"}>
|
||||
<Collapse in={open}>
|
||||
<Paper square>
|
||||
@ -205,8 +217,8 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<Intelligence player={player} />
|
||||
<Work player={player} />
|
||||
<Intelligence />
|
||||
<Work />
|
||||
|
||||
<TableRow>
|
||||
<TableCell align="center" colSpan={2} classes={{ root: classes.cellNone }}>
|
||||
@ -226,6 +238,6 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement
|
||||
</Fab>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -4,24 +4,34 @@ import { CinematicLine } from "./CinematicLine";
|
||||
|
||||
interface IProps {
|
||||
lines: string[];
|
||||
auto?: boolean;
|
||||
onDone?: () => void;
|
||||
}
|
||||
|
||||
export function CinematicText(props: IProps): React.ReactElement {
|
||||
const [i, setI] = useState(0);
|
||||
const [done, setDone] = useState(false);
|
||||
|
||||
function advance(): void {
|
||||
const newI = i + 1;
|
||||
setI(newI);
|
||||
if (newI >= props.lines.length && props.onDone) props.onDone();
|
||||
if (newI >= props.lines.length) {
|
||||
if (props.onDone && props.auto) props.onDone();
|
||||
setDone(true);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{props.lines.slice(0, i).map((line, i) => (
|
||||
<pre key={i}>{line}</pre>
|
||||
))}
|
||||
{props.lines.length > i && <CinematicLine key={i} text={props.lines[i]} onDone={advance} />}
|
||||
</>
|
||||
{!props.auto && props.onDone && done && (
|
||||
<button className="std-button" onClick={props.onDone}>
|
||||
Continue ...
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -28,12 +28,9 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
width: 50,
|
||||
padding: 2,
|
||||
padding: theme.spacing(2),
|
||||
userSelect: "none",
|
||||
},
|
||||
pad: {
|
||||
padding: 2,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { createTheme, ThemeProvider, Theme, StyledEngineProvider, adaptV4Theme } from "@mui/material/styles";
|
||||
import { createTheme, ThemeProvider, Theme, StyledEngineProvider } from "@mui/material/styles";
|
||||
|
||||
declare module "@mui/styles/defaultTheme" {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { LocationName } from "../Locations/data/LocationNames";
|
||||
/**
|
||||
* The full-screen page the player is currently be on.
|
||||
* These pages are mutually exclusive.
|
||||
@ -6,26 +7,30 @@ import { Faction } from "../Faction/Faction";
|
||||
export enum Page {
|
||||
ActiveScripts,
|
||||
Augmentations,
|
||||
BitVerse,
|
||||
Bladeburner,
|
||||
Stats,
|
||||
City,
|
||||
Corporation,
|
||||
CreateProgram,
|
||||
CreateScript,
|
||||
DevMenu,
|
||||
Faction,
|
||||
Factions,
|
||||
Options,
|
||||
Gang,
|
||||
Hacknet,
|
||||
Infiltration,
|
||||
Job,
|
||||
Milestones,
|
||||
Options,
|
||||
Resleeves,
|
||||
CreateScript,
|
||||
Sleeves,
|
||||
Stats,
|
||||
StockMarket,
|
||||
Terminal,
|
||||
Travel,
|
||||
Tutorial,
|
||||
Work,
|
||||
BladeburnerCinematic,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,19 +42,22 @@ export interface IRouter {
|
||||
// toMission(): void;
|
||||
// toRedPill(): void;
|
||||
// toworkInProgress(): void;
|
||||
page(): Page;
|
||||
toActiveScripts(): void;
|
||||
toAugmentations(): void;
|
||||
toBitVerse(flume: boolean, quick: boolean): void;
|
||||
toBladeburner(): void;
|
||||
toCharacterInfo(): void;
|
||||
toCity(): void; // travel ? city ?
|
||||
toCorporation(): void;
|
||||
toCreateProgram(): void;
|
||||
toDevMenu(): void;
|
||||
toFaction(faction: Faction): void; // faction name
|
||||
toFaction(faction?: Faction): void; // faction name
|
||||
toFactions(): void;
|
||||
toGameOptions(): void;
|
||||
toGang(): void;
|
||||
toHacknetNodes(): void;
|
||||
toCity(): void; // travel ? city ?
|
||||
toInfiltration(location: LocationName): void;
|
||||
toJob(): void;
|
||||
toMilestones(): void;
|
||||
toResleeves(): void;
|
||||
@ -59,4 +67,6 @@ export interface IRouter {
|
||||
toTerminal(): void;
|
||||
toTravel(): void;
|
||||
toTutorial(): void;
|
||||
toWork(): void;
|
||||
toBladeburnerCinematic(): void;
|
||||
}
|
||||
|
336
src/ui/WorkInProgressRoot.tsx
Normal file
336
src/ui/WorkInProgressRoot.tsx
Normal file
@ -0,0 +1,336 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { use } from "./Context";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { numeralWrapper } from "./numeralFormat";
|
||||
import { Reputation } from "./React/Reputation";
|
||||
import { ReputationRate } from "./React/ReputationRate";
|
||||
import { MoneyRate } from "./React/MoneyRate";
|
||||
import { Money } from "./React/Money";
|
||||
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { Company } from "../Company/Company";
|
||||
import { Companies } from "../Company/Companies";
|
||||
import { createProgressBarText } from "../../utils/helpers/createProgressBarText";
|
||||
|
||||
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
|
||||
|
||||
export function WorkInProgressRoot(): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, CONSTANTS.MilliPerCycle);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const faction = Factions[player.currentWorkFactionName];
|
||||
if (player.workType == CONSTANTS.WorkTypeFaction) {
|
||||
function cancel(): void {
|
||||
router.toFaction();
|
||||
player.finishFactionWork(true);
|
||||
}
|
||||
function unfocus(): void {
|
||||
router.toFaction();
|
||||
player.stopFocusing();
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
You are currently {player.currentWorkFactionDescription} for your faction {faction.name}
|
||||
<br />
|
||||
(Current Faction Reputation: {Reputation(faction.playerReputation)}). <br />
|
||||
You have been doing this for {convertTimeMsToTimeElapsedString(player.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={player.workMoneyGained} /> ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(player.workRepGained)} ({ReputationRate(player.workRepGainRate * CYCLES_PER_SEC)}) reputation for
|
||||
this faction <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(player.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(player.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(player.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 20 hours. You can cancel earlier if you wish.
|
||||
<br />
|
||||
There is no penalty for cancelling earlier.
|
||||
</p>
|
||||
|
||||
<button onClick={cancel} className="work-button">
|
||||
Stop Faction Work
|
||||
</button>
|
||||
<button onClick={unfocus} className="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const className = player.className;
|
||||
if (player.className !== "") {
|
||||
function cancel(): void {
|
||||
player.finishClass(true);
|
||||
router.toCity();
|
||||
}
|
||||
function unfocus(): void {
|
||||
player.stopFocusing();
|
||||
router.toCity();
|
||||
}
|
||||
|
||||
let stopText = "";
|
||||
if (
|
||||
className == CONSTANTS.ClassGymStrength ||
|
||||
className == CONSTANTS.ClassGymDefense ||
|
||||
className == CONSTANTS.ClassGymDexterity ||
|
||||
className == CONSTANTS.ClassGymAgility
|
||||
) {
|
||||
stopText = "Stop training at gym";
|
||||
} else {
|
||||
stopText = "Stop taking course";
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
You have been {className} for {convertTimeMsToTimeElapsedString(player.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
This has cost you: <br />
|
||||
<Money money={-player.workMoneyGained} /> ({MoneyRate(player.workMoneyLossRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
You have gained: <br />
|
||||
{numeralWrapper.formatExp(player.workHackExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp <br />
|
||||
{numeralWrapper.formatExp(player.workStrExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp <br />
|
||||
{numeralWrapper.formatExp(player.workDefExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp <br />
|
||||
{numeralWrapper.formatExp(player.workDexExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(player.workAgiExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp <br />
|
||||
{numeralWrapper.formatExp(player.workChaExpGained)} (
|
||||
{numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp <br />
|
||||
You may cancel at any time
|
||||
</p>
|
||||
|
||||
<button onClick={cancel} className="work-button">
|
||||
{stopText}
|
||||
</button>
|
||||
<button onClick={unfocus} className="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (player.workType == CONSTANTS.WorkTypeCompany) {
|
||||
const comp = Companies[player.companyName];
|
||||
let companyRep = 0;
|
||||
if (comp == null || !(comp instanceof Company)) {
|
||||
throw new Error(`Could not find Company: ${player.companyName}`);
|
||||
}
|
||||
companyRep = comp.playerReputation;
|
||||
|
||||
function cancel(): void {
|
||||
player.finishWork(true);
|
||||
router.toJob();
|
||||
}
|
||||
function unfocus(): void {
|
||||
player.stopFocusing();
|
||||
router.toJob();
|
||||
}
|
||||
|
||||
const position = player.jobs[player.companyName];
|
||||
|
||||
const penalty = player.cancelationPenalty();
|
||||
|
||||
const penaltyString = penalty === 0.5 ? "half" : "three-quarters";
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={player.workMoneyGained} /> ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(player.workRepGained)} ({ReputationRate(player.workRepGainRate * CYCLES_PER_SEC)}) reputation for
|
||||
this company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(player.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(player.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(player.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
You will automatically finish after working for 8 hours. You can cancel earlier if you wish, but you will only
|
||||
gain {penaltyString} of the reputation you've earned so far.
|
||||
</p>
|
||||
|
||||
<button onClick={cancel} className="work-button">
|
||||
Stop Working
|
||||
</button>
|
||||
<button onClick={unfocus} className="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
||||
function cancel(): void {
|
||||
player.finishWork(true);
|
||||
router.toJob();
|
||||
}
|
||||
function unfocus(): void {
|
||||
player.stopFocusing();
|
||||
router.toJob();
|
||||
}
|
||||
const comp = Companies[player.companyName];
|
||||
let companyRep = 0;
|
||||
if (comp == null || !(comp instanceof Company)) {
|
||||
throw new Error(`Could not find Company: ${player.companyName}`);
|
||||
}
|
||||
companyRep = comp.playerReputation;
|
||||
|
||||
const position = player.jobs[player.companyName];
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "}
|
||||
{Reputation(companyRep)})<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
You have earned: <br />
|
||||
<br />
|
||||
<Money money={player.workMoneyGained} /> ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)}) <br />
|
||||
<br />
|
||||
{Reputation(player.workRepGained)} (
|
||||
{Reputation(`${numeralWrapper.formatExp(player.workRepGainRate * CYCLES_PER_SEC)} / sec`)}
|
||||
) reputation for this company <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workHackExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) hacking exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workStrExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) strength exp <br />
|
||||
{numeralWrapper.formatExp(player.workDefExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) defense exp <br />
|
||||
{numeralWrapper.formatExp(player.workDexExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) dexterity exp <br />
|
||||
{numeralWrapper.formatExp(player.workAgiExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) agility exp <br />
|
||||
<br />
|
||||
{numeralWrapper.formatExp(player.workChaExpGained)} (
|
||||
{`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`}
|
||||
) charisma exp <br />
|
||||
<br />
|
||||
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.
|
||||
</p>
|
||||
|
||||
<button onClick={cancel} className="work-button">
|
||||
Stop Working
|
||||
</button>
|
||||
<button onClick={unfocus} className="work-button">
|
||||
Do something else simultaneously
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (player.crimeType !== "") {
|
||||
const percent = Math.round((player.timeWorked / player.timeNeededToCompleteWork) * 100);
|
||||
let numBars = Math.round(percent / 5);
|
||||
if (numBars < 0) {
|
||||
numBars = 0;
|
||||
}
|
||||
if (numBars > 20) {
|
||||
numBars = 20;
|
||||
}
|
||||
// const progressBar = "[" + Array(numBars + 1).join("|") + Array(20 - numBars + 1).join(" ") + "]";
|
||||
const progressBar = createProgressBarText({ progress: (numBars + 1) / 20, totalTicks: 20 });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>You are attempting to {player.crimeType}.</p>
|
||||
<br />
|
||||
|
||||
<p>Time remaining: {convertTimeMsToTimeElapsedString(player.timeNeededToCompleteWork - player.timeWorked)}</p>
|
||||
|
||||
<br />
|
||||
<pre>{progressBar}</pre>
|
||||
|
||||
<button className="work-button" onClick={() => player.finishCrime(true)}>
|
||||
Cancel crime
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (player.createProgramName !== "") {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
You are currently working on coding {player.createProgramName}.<br />
|
||||
<br />
|
||||
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
|
||||
<br />
|
||||
<br />
|
||||
The program is {((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)}
|
||||
% complete. <br />
|
||||
If you cancel, your work will be saved and you can come back to complete the program later.
|
||||
</p>
|
||||
<button className="work-button" onClick={() => player.finishCreateProgramWork(true)}>
|
||||
Cancel work on creating program
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
setTimeout(() => router.toCity(), 50);
|
||||
return <></>;
|
||||
}
|
Reference in New Issue
Block a user