mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-23 06:32:26 +01:00
819e102fe1
Fixes #4067. The file name of a Coding Contract follows the format contract-xxx-rewardName.cct. The part `xxx` means a sequence of random decimal digits. The part `rewardName` can be an empty string if the player is not part of any faction nor is working for a company. However, if the player is working for a company or faction whose name has a special character, then the special character would also appear in the generated file name. We only want alphanumeric characters throughout the whole file name.
200 lines
5.8 KiB
TypeScript
200 lines
5.8 KiB
TypeScript
import {
|
|
CodingContract,
|
|
CodingContractRewardType,
|
|
CodingContractTypes,
|
|
ICodingContractReward,
|
|
} from "./CodingContracts";
|
|
import { Factions } from "./Faction/Factions";
|
|
import { Player } from "./Player";
|
|
import { GetServer, GetAllServers } from "./Server/AllServers";
|
|
import { SpecialServers } from "./Server/data/SpecialServers";
|
|
import { Server } from "./Server/Server";
|
|
import { BaseServer } from "./Server/BaseServer";
|
|
|
|
import { getRandomInt } from "./utils/helpers/getRandomInt";
|
|
|
|
export function generateRandomContract(): void {
|
|
// First select a random problem type
|
|
const problemType = getRandomProblemType();
|
|
|
|
// Then select a random reward type. 'Money' will always be the last reward type
|
|
const reward = getRandomReward();
|
|
|
|
// Choose random server
|
|
const randServer = getRandomServer();
|
|
|
|
const contractFn = getRandomFilename(randServer, reward);
|
|
const contract = new CodingContract(contractFn, problemType, reward);
|
|
|
|
randServer.addContract(contract);
|
|
}
|
|
|
|
export function generateRandomContractOnHome(): void {
|
|
// First select a random problem type
|
|
const problemType = getRandomProblemType();
|
|
|
|
// Then select a random reward type. 'Money' will always be the last reward type
|
|
const reward = getRandomReward();
|
|
|
|
// Choose random server
|
|
const serv = Player.getHomeComputer();
|
|
|
|
const contractFn = getRandomFilename(serv, reward);
|
|
const contract = new CodingContract(contractFn, problemType, reward);
|
|
|
|
serv.addContract(contract);
|
|
}
|
|
|
|
interface IGenerateContractParams {
|
|
problemType?: string;
|
|
server?: string;
|
|
fn?: string;
|
|
}
|
|
|
|
export function generateContract(params: IGenerateContractParams): void {
|
|
// Problem Type
|
|
let problemType;
|
|
const problemTypes = Object.keys(CodingContractTypes);
|
|
if (params.problemType != null && problemTypes.includes(params.problemType)) {
|
|
problemType = params.problemType;
|
|
} else {
|
|
problemType = getRandomProblemType();
|
|
}
|
|
|
|
// Reward Type - This is always random for now
|
|
const reward = getRandomReward();
|
|
|
|
// Server
|
|
let server;
|
|
if (params.server != null) {
|
|
server = GetServer(params.server);
|
|
if (server == null) {
|
|
server = getRandomServer();
|
|
}
|
|
} else {
|
|
server = getRandomServer();
|
|
}
|
|
|
|
// Filename
|
|
let fn;
|
|
if (params.fn != null) {
|
|
fn = params.fn;
|
|
} else {
|
|
fn = getRandomFilename(server, reward);
|
|
}
|
|
|
|
const contract = new CodingContract(fn, problemType, reward);
|
|
server.addContract(contract);
|
|
}
|
|
|
|
// Ensures that a contract's reward type is valid
|
|
function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContractRewardType {
|
|
let type = rewardType; // Create copy
|
|
|
|
const factionsThatAllowHacking = Player.factions.filter((fac) => {
|
|
try {
|
|
return Factions[fac].getInfo().offerHackingWork;
|
|
} catch (e) {
|
|
console.error(`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`);
|
|
return false;
|
|
}
|
|
});
|
|
if (type === CodingContractRewardType.FactionReputation && factionsThatAllowHacking.length === 0) {
|
|
type = CodingContractRewardType.CompanyReputation;
|
|
}
|
|
if (type === CodingContractRewardType.FactionReputationAll && factionsThatAllowHacking.length === 0) {
|
|
type = CodingContractRewardType.CompanyReputation;
|
|
}
|
|
if (type === CodingContractRewardType.CompanyReputation && Object.keys(Player.jobs).length === 0) {
|
|
type = CodingContractRewardType.Money;
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
function getRandomProblemType(): string {
|
|
const problemTypes = Object.keys(CodingContractTypes);
|
|
const randIndex = getRandomInt(0, problemTypes.length - 1);
|
|
|
|
return problemTypes[randIndex];
|
|
}
|
|
|
|
function getRandomReward(): ICodingContractReward {
|
|
const reward: ICodingContractReward = {
|
|
name: "",
|
|
type: getRandomInt(0, CodingContractRewardType.Money),
|
|
};
|
|
reward.type = sanitizeRewardType(reward.type);
|
|
|
|
// Add additional information based on the reward type
|
|
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
|
|
|
|
switch (reward.type) {
|
|
case CodingContractRewardType.FactionReputation: {
|
|
// Get a random faction that player is a part of. That
|
|
// faction must allow hacking contracts
|
|
const numFactions = factionsThatAllowHacking.length;
|
|
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
|
|
reward.name = randFaction;
|
|
break;
|
|
}
|
|
case CodingContractRewardType.CompanyReputation: {
|
|
const allJobs = Object.keys(Player.jobs);
|
|
if (allJobs.length > 0) {
|
|
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
|
|
} else {
|
|
reward.type = CodingContractRewardType.Money;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return reward;
|
|
}
|
|
|
|
function getRandomServer(): BaseServer {
|
|
const servers = GetAllServers().filter((server: BaseServer) => server.serversOnNetwork.length !== 0);
|
|
let randIndex = getRandomInt(0, servers.length - 1);
|
|
let randServer = servers[randIndex];
|
|
|
|
// 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 &&
|
|
randServer.hostname !== SpecialServers.WorldDaemon
|
|
) {
|
|
break;
|
|
}
|
|
randIndex = getRandomInt(0, servers.length - 1);
|
|
randServer = servers[randIndex];
|
|
}
|
|
|
|
return randServer;
|
|
}
|
|
|
|
function getRandomFilename(server: BaseServer, reward: ICodingContractReward): string {
|
|
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;
|
|
}
|
|
contractFn = `contract-${getRandomInt(0, 1e6)}`;
|
|
}
|
|
|
|
if (reward.name) {
|
|
// Only alphanumeric characters in the reward name.
|
|
contractFn += `-${reward.name.replace(/[^a-zA-Z0-9]/g, "")}`;
|
|
}
|
|
|
|
return contractFn;
|
|
}
|