UI: Close coding contract popup on prestige (#2285)

This commit is contained in:
catloversg
2025-08-11 16:30:44 +07:00
committed by GitHub
parent f0ca10e1b1
commit c124c45270
4 changed files with 75 additions and 42 deletions

View 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]>();

View File

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

View File

@@ -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()

View File

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