mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-10-23 10:13:13 +02:00
270 lines
7.5 KiB
TypeScript
270 lines
7.5 KiB
TypeScript
|
import { CompanyName, JobName, CityName, AugmentationName, LiteratureName, MessageFilename } from "@enums";
|
||
|
import { Server } from "../Server/Server";
|
||
|
import { GetServer } from "../Server/AllServers";
|
||
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||
|
import { serverMetadata } from "../Server/data/servers";
|
||
|
import { Companies } from "../Company/Companies";
|
||
|
import { formatReputation, formatMoney, formatRam } from "../ui/formatNumber";
|
||
|
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||
|
import type { Skills } from "../PersonObjects/Skills";
|
||
|
|
||
|
export interface JoinCondition {
|
||
|
toString(): string;
|
||
|
isSatisfied(p: PlayerObject): boolean;
|
||
|
}
|
||
|
|
||
|
export const haveBackdooredServer = (hostname: string): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Backdoor access to ${hostname} server`;
|
||
|
},
|
||
|
isSatisfied(): boolean {
|
||
|
const server = GetServer(hostname);
|
||
|
if (!(server instanceof Server)) {
|
||
|
throw new Error(`${hostname} should be a normal server`);
|
||
|
}
|
||
|
return server.backdoorInstalled;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const employedBy = (
|
||
|
companyName: CompanyName,
|
||
|
{ withRep }: { withRep: number } = { withRep: 0 },
|
||
|
): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
if (withRep == 0) {
|
||
|
return `Employed at ${companyName}`;
|
||
|
} else {
|
||
|
return `Employed at ${companyName} with ${formatReputation(withRep)} reputation`;
|
||
|
}
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
const company = Companies[companyName];
|
||
|
if (!company) return false;
|
||
|
const serverMeta = serverMetadata.find((s) => s.specialName === companyName);
|
||
|
const server = GetServer(serverMeta ? serverMeta.hostname : "");
|
||
|
const bonus = (server as Server).backdoorInstalled ? -100e3 : 0;
|
||
|
return Object.hasOwn(p.jobs, companyName) && company.playerReputation > withRep + bonus;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const executiveEmployee = (): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `CTO, CFO, or CEO of a company`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
const allPositions = Object.values(p.jobs);
|
||
|
return (
|
||
|
allPositions.includes(JobName.software7) || // CTO
|
||
|
allPositions.includes(JobName.business4) || // CFO
|
||
|
allPositions.includes(JobName.business5) // CEO
|
||
|
);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const notEmployee = (...companyNames: CompanyName[]): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Not working for the ${joinList(companyNames)}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
for (const companyName of companyNames) {
|
||
|
if (Object.hasOwn(p.jobs, companyName)) return false;
|
||
|
}
|
||
|
return true;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveAugmentations = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `${n || "No"} augmentations installed`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
if (n == 0) {
|
||
|
const augs = [...p.augmentations, ...p.queuedAugmentations].filter(
|
||
|
(a) => a.name !== AugmentationName.NeuroFluxGovernor,
|
||
|
);
|
||
|
return augs.length == 0;
|
||
|
}
|
||
|
return p.augmentations.length >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveMoney = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Have ${formatMoney(n)}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
return p.money >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveSkill = (skill: keyof Skills, n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `${capitalize(skill)} level ${n}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
return p.skills[skill] >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveCombatSkills = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `All combat skills level ${n}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
return p.skills.strength >= n && p.skills.defense >= n && p.skills.dexterity >= n && p.skills.agility >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveKarma = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `${n} karma`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
return p.karma <= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveKilledPeople = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `${n} people killed`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
return p.numPeopleKilled >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const locatedInCity = (...cities: CityName[]): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Located in ${joinList(cities)}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
for (const city of cities) {
|
||
|
if (p.city == city) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const totalHacknetRam = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Total Hacknet RAM of ${formatRam(n)}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
let total = 0;
|
||
|
for (const node of iterateHacknet(p)) {
|
||
|
total += node.ram;
|
||
|
if (total >= n) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const totalHacknetCores = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Total Hacknet cores of ${n}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
let total = 0;
|
||
|
for (const node of iterateHacknet(p)) {
|
||
|
total += node.cores;
|
||
|
if (total >= n) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const totalHacknetLevels = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Total Hacknet levels of ${n}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
let total = 0;
|
||
|
for (const node of iterateHacknet(p)) {
|
||
|
total += node.level;
|
||
|
if (total >= n) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveBladeburnerRank = (n: number): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Rank ${n} in the Bladeburner Division`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
const rank = p.bladeburner?.rank || 0;
|
||
|
return rank >= n;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveSourceFile = (...nodeNums: number[]): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `In BitNode ${joinList(nodeNums)} or have SourceFile ${joinList(nodeNums)}`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
for (const n of nodeNums) {
|
||
|
if (p.bitNodeN === n || p.sourceFileLvl(n) > 0) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const haveFile = (fileName: LiteratureName | MessageFilename): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return `Have the file '${fileName}'`;
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
const homeComputer = p.getHomeComputer();
|
||
|
return homeComputer.messages.includes(fileName);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
export const someCondition = (...conditions: JoinCondition[]): JoinCondition => ({
|
||
|
toString(): string {
|
||
|
return joinList(conditions.map((c) => c.toString()));
|
||
|
},
|
||
|
isSatisfied(p: PlayerObject): boolean {
|
||
|
for (const condition of conditions) {
|
||
|
if (condition.isSatisfied(p)) return true;
|
||
|
}
|
||
|
return false;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
/* helpers */
|
||
|
|
||
|
function capitalize(s: string) {
|
||
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
||
|
}
|
||
|
|
||
|
function joinList(list: (string | number)[], conjunction = "or", separator = ", ") {
|
||
|
if (list.length < 3) {
|
||
|
return list.join(` ${conjunction} `);
|
||
|
}
|
||
|
list = [...list];
|
||
|
list[list.length - 1] = `${conjunction} ${list[list.length - 1]}`;
|
||
|
return list.join(`${separator}`);
|
||
|
}
|
||
|
|
||
|
function* iterateHacknet(p: PlayerObject) {
|
||
|
for (let i = 0; i < p.hacknetNodes.length; ++i) {
|
||
|
const v = p.hacknetNodes[i];
|
||
|
if (typeof v === "string") {
|
||
|
const hserver = GetServer(v);
|
||
|
if (hserver === null || !(hserver instanceof HacknetServer))
|
||
|
throw new Error("player hacknet server was not HacknetServer");
|
||
|
yield {
|
||
|
ram: hserver.maxRam,
|
||
|
cores: hserver.cores,
|
||
|
level: hserver.level,
|
||
|
};
|
||
|
} else {
|
||
|
yield {
|
||
|
ram: v.ram,
|
||
|
cores: v.cores,
|
||
|
level: v.level,
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|