bitburner-src/src/NetscriptFunctions/CodingContract.ts

125 lines
5.0 KiB
TypeScript
Raw Normal View History

2021-10-14 09:22:02 +02:00
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer";
import { is2DArray } from "../utils/helpers/is2DArray";
import { CodingContract } from "../CodingContracts";
2022-03-30 02:29:05 +02:00
import { CodingAttemptOptions, CodingContract as ICodingContract } from "../ScriptEditor/NetscriptDefinitions";
2022-05-08 01:08:07 +02:00
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
export function NetscriptCodingContract(player: IPlayer, workerScript: WorkerScript): InternalAPI<ICodingContract> {
const getCodingContract = function (
ctx: NetscriptContext,
func: string,
hostname: string,
filename: string,
): CodingContract {
const server = ctx.helper.getServer(hostname);
2021-11-20 21:01:04 +01:00
const contract = server.getContract(filename);
2021-10-14 09:22:02 +02:00
if (contract == null) {
2022-05-08 01:08:07 +02:00
throw ctx.makeRuntimeErrorMsg(`Cannot find contract '${filename}' on server '${hostname}'`);
2021-10-14 09:22:02 +02:00
}
return contract;
};
return {
2022-05-08 01:08:07 +02:00
attempt:
(ctx: NetscriptContext) =>
(
answer: any,
_filename: unknown,
_hostname: unknown = workerScript.hostname,
{ returnReward }: CodingAttemptOptions = { returnReward: false },
): boolean | string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const contract = getCodingContract(ctx, "attempt", hostname, filename);
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
// Convert answer to string. If the answer is a 2D array, then we have to
// manually add brackets for the inner arrays
if (is2DArray(answer)) {
const answerComponents = [];
for (let i = 0; i < answer.length; ++i) {
answerComponents.push(["[", answer[i].toString(), "]"].join(""));
}
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
answer = answerComponents.join(",");
} else {
answer = String(answer);
}
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
const creward = contract.reward;
if (creward === null) throw new Error("Somehow solved a contract that didn't have a reward");
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
const serv = ctx.helper.getServer(hostname);
if (contract.isSolution(answer)) {
const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
ctx.log(() => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
2021-11-20 21:01:04 +01:00
serv.removeContract(filename);
2022-05-08 01:08:07 +02:00
return returnReward ? reward : true;
2021-10-14 09:22:02 +02:00
} else {
2022-05-08 01:08:07 +02:00
++contract.tries;
if (contract.tries >= contract.getMaxNumTries()) {
ctx.log(() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`);
serv.removeContract(filename);
} else {
ctx.log(
() =>
`Coding Contract attempt '${filename}' failed. ${
contract.getMaxNumTries() - contract.tries
} attempts remaining.`,
);
2021-10-14 09:22:02 +02:00
}
2022-05-08 01:08:07 +02:00
return returnReward ? "" : false;
2021-10-14 09:22:02 +02:00
}
2022-05-08 01:08:07 +02:00
},
getContractType:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const contract = getCodingContract(ctx, "getContractType", hostname, filename);
return contract.getType();
},
getData:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): any => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const contract = getCodingContract(ctx, "getData", hostname, filename);
const data = contract.getData();
if (data.constructor === Array) {
// For two dimensional arrays, we have to copy the internal arrays using
// slice() as well. As of right now, no contract has arrays that have
// more than two dimensions
const copy = data.slice();
for (let i = 0; i < copy.length; ++i) {
if (data[i].constructor === Array) {
copy[i] = data[i].slice();
}
}
2021-10-14 09:22:02 +02:00
2022-05-08 01:08:07 +02:00
return copy;
} else {
return data;
}
},
getDescription:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): string => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const contract = getCodingContract(ctx, "getDescription", hostname, filename);
return contract.getDescription();
},
getNumTriesRemaining:
(ctx: NetscriptContext) =>
(_filename: unknown, _hostname: unknown = workerScript.hostname): number => {
const filename = ctx.helper.string("filename", _filename);
const hostname = ctx.helper.string("hostname", _hostname);
const contract = getCodingContract(ctx, "getNumTriesRemaining", hostname, filename);
return contract.getMaxNumTries() - contract.tries;
},
2021-10-14 09:22:02 +02:00
};
}