mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
UI: Close coding contract popup on prestige (#2285)
This commit is contained in:
19
src/CodingContract/CodingContractEventEmitter.ts
Normal file
19
src/CodingContract/CodingContractEventEmitter.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { EventEmitter } from "../utils/EventEmitter";
|
||||
import type { CodingContract } from "./Contract";
|
||||
|
||||
export type CodingContractEventData = {
|
||||
codingContract: CodingContract;
|
||||
onClose: () => void;
|
||||
onAttempt: (answer: string) => void;
|
||||
};
|
||||
|
||||
type CodingContractEvent =
|
||||
| {
|
||||
type: "run";
|
||||
data: CodingContractEventData;
|
||||
}
|
||||
| {
|
||||
type: "close";
|
||||
};
|
||||
|
||||
export const CodingContractEventEmitter = new EventEmitter<[CodingContractEvent]>();
|
||||
@@ -2,10 +2,10 @@ import { FactionName, CodingContractName } from "@enums";
|
||||
import { CodingContractTypes } from "./ContractTypes";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
|
||||
import { CodingContractEvent } from "../ui/React/CodingContractModal";
|
||||
import { ContractFilePath, resolveContractFilePath } from "../Paths/ContractFilePath";
|
||||
import { assertObject } from "../utils/TypeAssertion";
|
||||
import { Result } from "../types";
|
||||
import { CodingContractEventEmitter } from "./CodingContractEventEmitter";
|
||||
|
||||
// Numeric enum
|
||||
/** Enum representing the different types of rewards a Coding Contract can give */
|
||||
@@ -150,13 +150,16 @@ export class CodingContract {
|
||||
/** Creates a popup to prompt the player to solve the problem */
|
||||
async prompt(): Promise<{ result: CodingContractResult; message?: string }> {
|
||||
return new Promise((resolve) => {
|
||||
CodingContractEvent.emit({
|
||||
c: this,
|
||||
onClose: () => {
|
||||
resolve({ result: CodingContractResult.Cancelled });
|
||||
},
|
||||
onAttempt: (val: string) => {
|
||||
resolve(this.isSolution(val));
|
||||
CodingContractEventEmitter.emit({
|
||||
type: "run",
|
||||
data: {
|
||||
codingContract: this,
|
||||
onClose: () => {
|
||||
resolve({ result: CodingContractResult.Cancelled });
|
||||
},
|
||||
onAttempt: (val: string) => {
|
||||
resolve(this.isSolution(val));
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ import { calculateExp } from "./PersonObjects/formulas/skill";
|
||||
import { currentNodeMults } from "./BitNode/BitNodeMultipliers";
|
||||
import { canAccessBitNodeFeature } from "./BitNode/BitNodeUtils";
|
||||
import { pendingUIShareJobIds } from "./NetworkShare/Share";
|
||||
import { CodingContractEventEmitter } from "./CodingContract/CodingContractEventEmitter";
|
||||
|
||||
const BitNode8StartingMoney = 250e6;
|
||||
function delayedDialog(message: string, canBeDismissedEasily = true) {
|
||||
@@ -105,6 +106,9 @@ export function prestigeAugmentation(): void {
|
||||
Terminal.clear();
|
||||
LogBoxClearEvents.emit();
|
||||
|
||||
// Close coding contract modal
|
||||
CodingContractEventEmitter.emit({ type: "close" });
|
||||
|
||||
// Recalculate the bonus for circadian modulator aug
|
||||
initCircadianModulator();
|
||||
|
||||
@@ -209,6 +213,9 @@ export function prestigeSourceFile(isFlume: boolean): void {
|
||||
Terminal.clear();
|
||||
LogBoxClearEvents.emit();
|
||||
|
||||
// Close coding contract modal
|
||||
CodingContractEventEmitter.emit({ type: "close" });
|
||||
|
||||
// Delete all servers except home computer
|
||||
prestigeAllServers(); // Must be done before initForeignServers()
|
||||
|
||||
|
||||
@@ -1,38 +1,50 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { KEY } from "../../utils/KeyboardEventKey";
|
||||
|
||||
import { CodingContract } from "../../CodingContract/Contract";
|
||||
import { CodingContractTypes } from "../../CodingContract/ContractTypes";
|
||||
import { CopyableText } from "./CopyableText";
|
||||
import { Modal } from "./Modal";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { pluralize } from "../../utils/I18nUtils";
|
||||
|
||||
interface CodingContractProps {
|
||||
c: CodingContract;
|
||||
onClose: () => void;
|
||||
onAttempt: (answer: string) => void;
|
||||
}
|
||||
|
||||
export const CodingContractEvent = new EventEmitter<[CodingContractProps]>();
|
||||
import {
|
||||
type CodingContractEventData,
|
||||
CodingContractEventEmitter,
|
||||
} from "../../CodingContract/CodingContractEventEmitter";
|
||||
|
||||
export function CodingContractModal(): React.ReactElement {
|
||||
const [contract, setContract] = useState<CodingContractProps | null>(null);
|
||||
const [eventData, setEventData] = useState<CodingContractEventData | null>(null);
|
||||
const [answer, setAnswer] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
return CodingContractEvent.subscribe((props) => setContract(props));
|
||||
const close = useCallback(() => {
|
||||
setEventData((old) => {
|
||||
old?.onClose();
|
||||
return null;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
CodingContractEventEmitter.subscribe((event) => {
|
||||
switch (event.type) {
|
||||
case "run":
|
||||
setEventData(event.data);
|
||||
break;
|
||||
case "close":
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}),
|
||||
[close],
|
||||
);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
contract?.onClose();
|
||||
eventData?.onClose();
|
||||
};
|
||||
}, [contract]);
|
||||
}, [eventData]);
|
||||
|
||||
if (contract === null) {
|
||||
if (eventData === null) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
@@ -41,30 +53,22 @@ export function CodingContractModal(): React.ReactElement {
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
if (contract === null) {
|
||||
if (eventData === null) {
|
||||
return;
|
||||
}
|
||||
const value = event.currentTarget.value;
|
||||
|
||||
if (event.key === KEY.ENTER && value !== "") {
|
||||
event.preventDefault();
|
||||
contract.onAttempt(answer);
|
||||
eventData.onAttempt(answer);
|
||||
setAnswer("");
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
if (contract === null) {
|
||||
return;
|
||||
}
|
||||
contract.onClose();
|
||||
setContract(null);
|
||||
}
|
||||
|
||||
const contractType = CodingContractTypes[contract.c.type];
|
||||
const contractType = CodingContractTypes[eventData.codingContract.type];
|
||||
const description = [];
|
||||
for (const [i, value] of contractType.desc(contract.c.getData()).split("\n").entries()) {
|
||||
for (const [i, value] of contractType.desc(eventData.codingContract.getData()).split("\n").entries()) {
|
||||
description.push(
|
||||
<span key={i} style={{ whiteSpace: "pre-wrap" }}>
|
||||
{value} <br />
|
||||
@@ -72,12 +76,12 @@ export function CodingContractModal(): React.ReactElement {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Modal open={contract !== null} onClose={close}>
|
||||
<CopyableText variant="h4" value={contract.c.type} />
|
||||
<Modal open={eventData !== null} onClose={close}>
|
||||
<CopyableText variant="h4" value={eventData.codingContract.type} />
|
||||
<Typography>
|
||||
You are attempting to solve a Coding Contract. You have{" "}
|
||||
{pluralize(contract.c.getMaxNumTries() - contract.c.tries, "try", "tries")} remaining, after which the contract
|
||||
will self-destruct.
|
||||
{pluralize(eventData.codingContract.getMaxNumTries() - eventData.codingContract.tries, "try", "tries")}{" "}
|
||||
remaining, after which the contract will self-destruct.
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography>{description}</Typography>
|
||||
@@ -96,7 +100,7 @@ export function CodingContractModal(): React.ReactElement {
|
||||
endAdornment: (
|
||||
<Button
|
||||
onClick={() => {
|
||||
contract.onAttempt(answer);
|
||||
eventData.onAttempt(answer);
|
||||
setAnswer("");
|
||||
close();
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user