bitburner-src/src/CodingContractGenerator.ts

206 lines
6.7 KiB
TypeScript
Raw Normal View History

import {
2021-09-05 01:09:30 +02:00
CodingContract,
CodingContractRewardType,
CodingContractTypes,
ICodingContractReward,
} from "./CodingContracts";
import { currentNodeMults } from "./BitNode/BitNodeMultipliers";
import { Factions } from "./Faction/Factions";
import { Player } from "@player";
2021-10-07 22:56:01 +02:00
import { GetServer, GetAllServers } from "./Server/AllServers";
2021-10-07 23:55:49 +02:00
import { SpecialServers } from "./Server/data/SpecialServers";
import { Server } from "./Server/Server";
2021-10-07 22:04:04 +02:00
import { BaseServer } from "./Server/BaseServer";
2021-09-25 20:42:57 +02:00
import { getRandomInt } from "./utils/helpers/getRandomInt";
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath";
2021-05-01 09:17:31 +02:00
export function generateRandomContract(): void {
2021-09-05 01:09:30 +02:00
// First select a random problem type
const problemType = getRandomProblemType();
2021-09-05 01:09:30 +02:00
// Then select a random reward type. 'Money' will always be the last reward type
const reward = getRandomReward();
2021-09-05 01:09:30 +02:00
// Choose random server
const randServer = getRandomServer();
2021-09-05 01:09:30 +02:00
const contractFn = getRandomFilename(randServer, reward);
const contract = new CodingContract(contractFn, problemType, reward);
2021-09-05 01:09:30 +02:00
randServer.addContract(contract);
}
2021-05-01 09:17:31 +02:00
export function generateRandomContractOnHome(): void {
2021-09-05 01:09:30 +02:00
// First select a random problem type
const problemType = getRandomProblemType();
2021-09-05 01:09:30 +02:00
// Then select a random reward type. 'Money' will always be the last reward type
const reward = getRandomReward();
2021-09-05 01:09:30 +02:00
// Choose random server
const serv = Player.getHomeComputer();
2021-09-05 01:09:30 +02:00
const contractFn = getRandomFilename(serv, reward);
const contract = new CodingContract(contractFn, problemType, reward);
2021-09-05 01:09:30 +02:00
serv.addContract(contract);
}
export const generateDummyContract = (problemType: string): string => {
2022-10-09 08:56:11 +02:00
if (!CodingContractTypes[problemType]) throw new Error(`Invalid problem type: '${problemType}'`);
const serv = Player.getHomeComputer();
const contractFn = getRandomFilename(serv);
const contract = new CodingContract(contractFn, problemType, null);
serv.addContract(contract);
return contractFn;
2022-10-09 08:56:11 +02:00
};
interface IGenerateContractParams {
2021-09-05 01:09:30 +02:00
problemType?: string;
server?: string;
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
fn?: ContractFilePath;
}
2021-05-01 09:17:31 +02:00
export function generateContract(params: IGenerateContractParams): void {
2021-09-05 01:09:30 +02:00
// Problem Type
let problemType;
const problemTypes = Object.keys(CodingContractTypes);
if (params.problemType && problemTypes.includes(params.problemType)) {
2021-09-05 01:09:30 +02:00
problemType = params.problemType;
} else {
problemType = getRandomProblemType();
}
// Reward Type - This is always random for now
const reward = getRandomReward();
// Server
let server;
if (params.server != null) {
2021-10-07 22:56:01 +02:00
server = GetServer(params.server);
2021-09-05 01:09:30 +02:00
if (server == null) {
server = getRandomServer();
}
2021-09-05 01:09:30 +02:00
} else {
server = getRandomServer();
}
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
const filename = params.fn ? params.fn : getRandomFilename(server, reward);
2021-09-05 01:09:30 +02:00
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
const contract = new CodingContract(filename, problemType, reward);
2021-09-05 01:09:30 +02:00
server.addContract(contract);
}
// Ensures that a contract's reward type is valid
2021-09-09 05:47:34 +02:00
function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContractRewardType {
2021-09-05 01:09:30 +02:00
let type = rewardType; // Create copy
const factionsThatAllowHacking = Player.factions.filter((fac) => {
try {
return Factions[fac].getInfo().offerHackingWork;
} catch (e) {
2021-09-09 05:47:34 +02:00
console.error(`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`);
2021-09-05 01:09:30 +02:00
return false;
}
2021-09-05 01:09:30 +02:00
});
2021-09-09 05:47:34 +02:00
if (type === CodingContractRewardType.FactionReputation && factionsThatAllowHacking.length === 0) {
2021-09-05 01:09:30 +02:00
type = CodingContractRewardType.CompanyReputation;
}
2021-09-09 05:47:34 +02:00
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
2021-09-05 01:09:30 +02:00
type = CodingContractRewardType.CompanyReputation;
}
2021-09-09 05:47:34 +02:00
if (type === CodingContractRewardType.CompanyReputation && Object.keys(Player.jobs).length === 0) {
2021-09-05 01:09:30 +02:00
type = CodingContractRewardType.Money;
}
return type;
}
2021-05-01 09:17:31 +02:00
function getRandomProblemType(): string {
2021-09-05 01:09:30 +02:00
const problemTypes = Object.keys(CodingContractTypes);
const randIndex = getRandomInt(0, problemTypes.length - 1);
2021-09-05 01:09:30 +02:00
return problemTypes[randIndex];
}
function getRandomReward(): ICodingContractReward {
// Don't offer money reward by default if BN multiplier is 0 (e.g. BN8)
const rewardTypeUpperBound =
currentNodeMults.CodingContractMoney === 0 ? CodingContractRewardType.Money - 1 : CodingContractRewardType.Money;
const rewardType = sanitizeRewardType(getRandomInt(0, rewardTypeUpperBound));
2021-09-05 01:09:30 +02:00
// Add additional information based on the reward type
2021-11-06 02:01:23 +01:00
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
2021-09-05 01:09:30 +02:00
2023-06-26 04:53:35 +02:00
switch (rewardType) {
2021-09-05 01:09:30 +02:00
case CodingContractRewardType.FactionReputation: {
// Get a random faction that player is a part of. That
// faction must allow hacking contracts
const numFactions = factionsThatAllowHacking.length;
2021-09-09 05:47:34 +02:00
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
2023-06-26 04:53:35 +02:00
return { type: rewardType, name: randFaction };
}
2021-09-05 01:09:30 +02:00
case CodingContractRewardType.CompanyReputation: {
const allJobs = Object.keys(Player.jobs);
if (allJobs.length > 0) {
2023-06-26 04:53:35 +02:00
return { type: CodingContractRewardType.CompanyReputation, name: allJobs[getRandomInt(0, allJobs.length - 1)] };
2021-09-05 01:09:30 +02:00
}
2023-06-26 04:53:35 +02:00
return { type: CodingContractRewardType.Money };
2021-09-05 01:09:30 +02:00
}
default:
2023-06-26 04:53:35 +02:00
return { type: rewardType };
2021-09-05 01:09:30 +02:00
}
}
2021-10-07 22:04:04 +02:00
function getRandomServer(): BaseServer {
const servers = GetAllServers().filter((server: BaseServer) => server.serversOnNetwork.length !== 0);
2021-09-05 01:09:30 +02:00
let randIndex = getRandomInt(0, servers.length - 1);
2021-10-07 22:04:04 +02:00
let randServer = servers[randIndex];
2021-09-05 01:09:30 +02:00
// An infinite loop shouldn't ever happen, but to be safe we'll use
// a for loop with a limited number of tries
for (let i = 0; i < 200; ++i) {
if (
randServer instanceof Server &&
!randServer.purchasedByPlayer &&
2021-10-07 23:55:49 +02:00
randServer.hostname !== SpecialServers.WorldDaemon
2021-09-05 01:09:30 +02:00
) {
break;
}
2021-09-05 01:09:30 +02:00
randIndex = getRandomInt(0, servers.length - 1);
2021-10-07 22:04:04 +02:00
randServer = servers[randIndex];
2021-09-05 01:09:30 +02:00
}
2021-09-05 01:09:30 +02:00
return randServer;
}
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
function getRandomFilename(
server: BaseServer,
2023-06-26 04:53:35 +02:00
reward: ICodingContractReward = { type: CodingContractRewardType.Money },
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
): ContractFilePath {
2021-09-05 01:09:30 +02:00
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
for (let i = 0; i < 1000; ++i) {
if (
server.contracts.filter((c: CodingContract) => {
return c.fn === contractFn;
}).length <= 0
) {
break;
}
2021-09-05 01:09:30 +02:00
contractFn = `contract-${getRandomInt(0, 1e6)}`;
}
2023-06-26 04:53:35 +02:00
if ("name" in reward) {
// Only alphanumeric characters in the reward name.
contractFn += `-${reward.name.replace(/[^a-zA-Z0-9]/g, "")}`;
2021-09-05 01:09:30 +02:00
}
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
contractFn += ".cct";
const validatedPath = resolveContractFilePath(contractFn);
if (!validatedPath) throw new Error(`Generated contract path could not be validated: ${contractFn}`);
return validatedPath;
}