bitburner-src/src/Faction/FactionJoinCondition.ts

270 lines
7.5 KiB
TypeScript
Raw Normal View History

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,
};
}
}
}