bitburner-src/src/CodingContracts.ts

176 lines
4.8 KiB
TypeScript
Raw Normal View History

2021-09-09 05:47:34 +02:00
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "./utils/JSONReviver";
2021-10-01 19:08:37 +02:00
import { CodingContractEvent } from "./ui/React/CodingContractModal";
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
/* Represents different types of problems that a Coding Contract can have */
2021-10-15 00:45:50 +02:00
class CodingContractType {
/** Function that generates a description of the problem */
2021-09-05 01:09:30 +02:00
desc: DescriptionFunc;
/** Number that generally represents the problem's difficulty. Bigger numbers = harder */
2021-09-05 01:09:30 +02:00
difficulty: number;
/** A function that randomly generates a valid 'data' for the problem */
2021-09-05 01:09:30 +02:00
generate: GeneratorFunc;
/** Name of the type of problem */
2021-09-05 01:09:30 +02:00
name: string;
/** The maximum number of tries the player gets on this kind of problem before it self-destructs */
2021-09-05 01:09:30 +02:00
numTries: number;
/** Stores a function that checks if the provided answer is correct */
2021-09-05 01:09:30 +02:00
solver: SolverFunc;
constructor(
name: string,
desc: DescriptionFunc,
gen: GeneratorFunc,
solver: SolverFunc,
diff: number,
numTries: number,
) {
this.name = name;
this.desc = desc;
this.generate = gen;
this.solver = solver;
this.difficulty = diff;
this.numTries = numTries;
}
}
/* Contract Types */
// tslint:disable-next-line
2022-10-03 18:12:16 +02:00
export const CodingContractTypes: Record<string, CodingContractType> = {};
for (const md of codingContractTypesMetadata) {
2021-09-05 01:09:30 +02:00
// tslint:disable-next-line
CodingContractTypes[md.name] = new CodingContractType(
md.name,
md.desc,
md.gen,
md.solver,
md.difficulty,
md.numTries,
);
}
/** Enum representing the different types of rewards a Coding Contract can give */
export enum CodingContractRewardType {
2021-09-05 01:09:30 +02:00
FactionReputation,
FactionReputationAll,
CompanyReputation,
Money, // This must always be the last reward type
}
/** Enum representing the result when trying to solve the Contract */
export enum CodingContractResult {
2021-09-05 01:09:30 +02:00
Success,
Failure,
Cancelled,
}
/** A class that represents the type of reward a contract gives */
export interface ICodingContractReward {
2021-09-05 01:09:30 +02:00
/* Name of Company/Faction name for reward, if applicable */
name?: string;
type: CodingContractRewardType;
}
/**
* A Coding Contract is a file that poses a programming-related problem to the Player.
* The player receives a reward if the problem is solved correctly
*/
export class CodingContract {
2021-09-05 01:09:30 +02:00
/* Relevant data for the contract's problem */
2022-07-18 08:28:21 +02:00
data: unknown;
2021-09-05 01:09:30 +02:00
/* Contract's filename */
fn: string;
2021-09-05 01:09:30 +02:00
/* Describes the reward given if this Contract is solved. The reward is actually
processed outside of this file */
2021-09-05 01:09:30 +02:00
reward: ICodingContractReward | null;
/* Number of times the Contract has been attempted */
tries = 0;
/* String representing the contract's type. Must match type in ContractTypes */
type: string;
2021-09-09 05:47:34 +02:00
constructor(fn = "", type = "Find Largest Prime Factor", reward: ICodingContractReward | null = null) {
2021-09-05 01:09:30 +02:00
this.fn = fn;
if (!this.fn.endsWith(".cct")) {
this.fn += ".cct";
}
2021-09-05 01:09:30 +02:00
// tslint:disable-next-line
if (CodingContractTypes[type] == null) {
2021-09-09 05:47:34 +02:00
throw new Error(`Error: invalid contract type: ${type} please contact developer`);
}
2021-05-01 09:17:31 +02:00
2021-09-05 01:09:30 +02:00
this.type = type;
this.data = CodingContractTypes[type].generate();
this.reward = reward;
}
2022-07-18 08:28:21 +02:00
getData(): unknown {
2021-09-05 01:09:30 +02:00
return this.data;
}
getDescription(): string {
return CodingContractTypes[this.type].desc(this.data);
}
getDifficulty(): number {
return CodingContractTypes[this.type].difficulty;
}
getMaxNumTries(): number {
return CodingContractTypes[this.type].numTries;
}
getType(): string {
return CodingContractTypes[this.type].name;
}
isSolution(solution: string): boolean {
return CodingContractTypes[this.type].solver(this.data, solution);
}
/** Creates a popup to prompt the player to solve the problem */
2021-09-05 01:09:30 +02:00
async prompt(): Promise<CodingContractResult> {
return new Promise<CodingContractResult>((resolve) => {
2021-10-01 19:08:37 +02:00
const props = {
c: this,
onClose: () => {
resolve(CodingContractResult.Cancelled);
2021-09-05 01:09:30 +02:00
},
2021-10-01 19:08:37 +02:00
onAttempt: (val: string) => {
if (this.isSolution(val)) {
resolve(CodingContractResult.Success);
} else {
resolve(CodingContractResult.Failure);
}
},
};
CodingContractEvent.emit(props);
2021-09-05 01:09:30 +02:00
});
}
/** Serialize the current file to a JSON save state. */
2022-07-15 01:00:10 +02:00
toJSON(): IReviverValue {
2021-09-05 01:09:30 +02:00
return Generic_toJSON("CodingContract", this);
}
2022-10-09 07:25:31 +02:00
/** Initializes a CodingContract from a JSON save state. */
2022-07-15 01:00:10 +02:00
static fromJSON(value: IReviverValue): CodingContract {
2021-09-05 01:09:30 +02:00
return Generic_fromJSON(CodingContract, value.data);
}
}
constructorsForReviver.CodingContract = CodingContract;