2022-01-06 13:04:03 +01:00
|
|
|
import { PlayerObject } from "src/PersonObjects/Player/PlayerObject";
|
|
|
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
|
|
|
import { SkillNames } from "../Bladeburner/data/SkillNames";
|
|
|
|
import { Skills } from "../Bladeburner/Skills";
|
|
|
|
import { CONSTANTS } from "../Constants";
|
|
|
|
import { Industries } from "../Corporation/IndustryData";
|
|
|
|
import { Exploit } from "../Exploits/Exploit";
|
|
|
|
import { Factions } from "../Faction/Factions";
|
|
|
|
import { AllGangs } from "../Gang/AllGangs";
|
|
|
|
import { GangConstants } from "../Gang/data/Constants";
|
|
|
|
import { HacknetNodeConstants, HacknetServerConstants } from "../Hacknet/data/Constants";
|
|
|
|
import { hasHacknetServers } from "../Hacknet/HacknetHelpers";
|
|
|
|
import { HacknetNode } from "../Hacknet/HacknetNode";
|
|
|
|
import { HacknetServer } from "../Hacknet/HacknetServer";
|
|
|
|
import { CityName } from "../Locations/data/CityNames";
|
|
|
|
import { Player } from "../Player";
|
|
|
|
import { Programs } from "../Programs/Programs";
|
|
|
|
import { GetAllServers, GetServer } from "../Server/AllServers";
|
|
|
|
import { SpecialServers } from "../Server/data/SpecialServers";
|
|
|
|
import { Server } from "../Server/Server";
|
|
|
|
import { Router } from "../ui/GameRoot";
|
|
|
|
import { Page } from "../ui/Router";
|
2022-01-08 20:54:21 +01:00
|
|
|
import { IMap } from "../types";
|
2022-01-06 13:04:03 +01:00
|
|
|
import * as data from "./AchievementData.json";
|
2022-03-19 09:09:59 +01:00
|
|
|
import { FactionNames } from "../Faction/data/FactionNames";
|
|
|
|
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
|
2022-07-07 23:28:23 +02:00
|
|
|
import { isClassWork } from "../Work/ClassWork";
|
2022-01-06 13:04:03 +01:00
|
|
|
|
|
|
|
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
|
2022-01-08 20:54:21 +01:00
|
|
|
const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
|
2022-01-06 13:04:03 +01:00
|
|
|
|
|
|
|
export interface Achievement {
|
|
|
|
ID: string;
|
|
|
|
Icon?: string;
|
|
|
|
Name?: string;
|
|
|
|
Description?: string;
|
|
|
|
Secret?: boolean;
|
|
|
|
Condition: () => boolean;
|
|
|
|
Visible?: () => boolean;
|
2022-01-11 19:41:08 +01:00
|
|
|
AdditionalUnlock?: string[]; // IDs of achievements that should be awarded when awarding this one
|
2022-01-06 13:04:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface PlayerAchievement {
|
|
|
|
ID: string;
|
|
|
|
unlockedOn?: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface AchievementDataJson {
|
|
|
|
achievements: IMap<AchievementData>;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface AchievementData {
|
|
|
|
ID: string;
|
|
|
|
Name: string;
|
|
|
|
Description: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
function bitNodeFinishedState(): boolean {
|
|
|
|
const wd = GetServer(SpecialServers.WorldDaemon);
|
|
|
|
if (!(wd instanceof Server)) return false;
|
|
|
|
if (wd.backdoorInstalled) return true;
|
2022-03-21 04:27:53 +01:00
|
|
|
return (
|
|
|
|
Player.bladeburner !== null && Player.bladeburner.blackops.hasOwnProperty(BlackOperationNames.OperationDaedalus)
|
|
|
|
);
|
2022-01-06 13:04:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function hasAccessToSF(player: PlayerObject, bn: number): boolean {
|
|
|
|
return player.bitNodeN === bn || player.sourceFiles.some((a) => a.n === bn);
|
|
|
|
}
|
|
|
|
|
|
|
|
function knowsAboutBitverse(player: PlayerObject): boolean {
|
2022-01-08 20:54:21 +01:00
|
|
|
return player.sourceFiles.some((a) => a.n === 1);
|
2022-01-06 13:04:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
|
function sfAchievement(): Achievement[] {
|
|
|
|
const achs: Achievement[] = [];
|
|
|
|
for (let i = 0; i <= 11; i++) {
|
|
|
|
for (let j = 1; j <= 3; j++) {
|
|
|
|
achs.push({
|
|
|
|
ID: `SF${i}.${j}`,
|
|
|
|
Condition: () => Player.sourceFileLvl(i) >= j,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return achs;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const achievements: IMap<Achievement> = {
|
2022-03-19 09:09:59 +01:00
|
|
|
[FactionNames.CyberSec.toUpperCase()]: {
|
|
|
|
...achievementData[FactionNames.CyberSec.toUpperCase()],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CSEC",
|
2022-03-19 09:09:59 +01:00
|
|
|
Condition: () => Player.factions.includes(FactionNames.CyberSec),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-03-19 09:09:59 +01:00
|
|
|
[FactionNames.NiteSec.toUpperCase()]: {
|
|
|
|
...achievementData[FactionNames.NiteSec.toUpperCase()],
|
|
|
|
Icon: FactionNames.NiteSec,
|
|
|
|
Condition: () => Player.factions.includes(FactionNames.NiteSec),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
THE_BLACK_HAND: {
|
|
|
|
...achievementData["THE_BLACK_HAND"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "TBH",
|
2022-03-19 09:09:59 +01:00
|
|
|
Condition: () => Player.factions.includes(FactionNames.TheBlackHand),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-03-19 09:09:59 +01:00
|
|
|
[FactionNames.BitRunners.toUpperCase()]: {
|
|
|
|
...achievementData[FactionNames.BitRunners.toUpperCase()],
|
|
|
|
Icon: FactionNames.BitRunners.toLowerCase(),
|
|
|
|
Condition: () => Player.factions.includes(FactionNames.BitRunners),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-03-19 09:09:59 +01:00
|
|
|
[FactionNames.Daedalus.toUpperCase()]: {
|
|
|
|
...achievementData[FactionNames.Daedalus.toUpperCase()],
|
|
|
|
Icon: FactionNames.Daedalus.toLowerCase(),
|
|
|
|
Condition: () => Player.factions.includes(FactionNames.Daedalus),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
THE_COVENANT: {
|
|
|
|
...achievementData["THE_COVENANT"],
|
2022-04-19 15:03:20 +02:00
|
|
|
Icon: FactionNames.TheCovenant.toLowerCase().replace(/ /g, ""),
|
2022-03-19 09:09:59 +01:00
|
|
|
Condition: () => Player.factions.includes(FactionNames.TheCovenant),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-03-19 09:09:59 +01:00
|
|
|
[FactionNames.Illuminati.toUpperCase()]: {
|
|
|
|
...achievementData[FactionNames.Illuminati.toUpperCase()],
|
|
|
|
Icon: FactionNames.Illuminati.toLowerCase(),
|
|
|
|
Condition: () => Player.factions.includes(FactionNames.Illuminati),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"BRUTESSH.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["BRUTESSH.EXE"],
|
|
|
|
Icon: "p0",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.BruteSSHProgram.name),
|
|
|
|
},
|
|
|
|
"FTPCRACK.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["FTPCRACK.EXE"],
|
|
|
|
Icon: "p1",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.FTPCrackProgram.name),
|
|
|
|
},
|
|
|
|
//-----------------------------------------------------
|
|
|
|
"RELAYSMTP.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["RELAYSMTP.EXE"],
|
|
|
|
Icon: "p2",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.RelaySMTPProgram.name),
|
|
|
|
},
|
|
|
|
"HTTPWORM.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["HTTPWORM.EXE"],
|
|
|
|
Icon: "p3",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.HTTPWormProgram.name),
|
|
|
|
},
|
|
|
|
"SQLINJECT.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SQLINJECT.EXE"],
|
|
|
|
Icon: "p4",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.SQLInjectProgram.name),
|
|
|
|
},
|
|
|
|
"FORMULAS.EXE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["FORMULAS.EXE"],
|
|
|
|
Icon: "formulas",
|
|
|
|
Condition: () => Player.getHomeComputer().programs.includes(Programs.Formulas.name),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF1.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF1.1"],
|
|
|
|
Icon: "SF1.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 1),
|
|
|
|
Condition: () => Player.sourceFileLvl(1) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF2.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF2.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF2.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () => Player.sourceFileLvl(2) >= 1,
|
|
|
|
},
|
|
|
|
"SF3.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF3.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF3.1",
|
2022-01-08 20:54:21 +01:00
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: () => Player.sourceFileLvl(3) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF4.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF4.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF4.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 4),
|
|
|
|
Condition: () => Player.sourceFileLvl(4) >= 1,
|
|
|
|
},
|
|
|
|
"SF5.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF5.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF5.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 5),
|
|
|
|
Condition: () => Player.sourceFileLvl(5) >= 1,
|
|
|
|
},
|
|
|
|
"SF6.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF6.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF6.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 6),
|
|
|
|
Condition: () => Player.sourceFileLvl(6) >= 1,
|
|
|
|
},
|
|
|
|
"SF7.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF7.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF7.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 7),
|
|
|
|
Condition: () => Player.sourceFileLvl(7) >= 1,
|
|
|
|
},
|
|
|
|
"SF8.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF8.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF8.1",
|
2022-01-08 20:54:21 +01:00
|
|
|
Visible: () => hasAccessToSF(Player, 8),
|
|
|
|
Condition: () => Player.sourceFileLvl(8) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF9.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF9.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF9.1",
|
2022-01-08 20:54:21 +01:00
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: () => Player.sourceFileLvl(9) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF10.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF10.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF10.1",
|
2022-01-08 20:54:21 +01:00
|
|
|
Visible: () => hasAccessToSF(Player, 10),
|
|
|
|
Condition: () => Player.sourceFileLvl(10) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF11.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF11.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF11.1",
|
|
|
|
Visible: () => hasAccessToSF(Player, 11),
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.sourceFileLvl(11) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
|
|
|
"SF12.1": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["SF12.1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF12.1",
|
2022-01-08 20:54:21 +01:00
|
|
|
Visible: () => hasAccessToSF(Player, 12),
|
|
|
|
Condition: () => Player.sourceFileLvl(12) >= 1,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MONEY_1Q: {
|
|
|
|
...achievementData["MONEY_1Q"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "$1Q",
|
|
|
|
Condition: () => Player.money >= 1e18,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MONEY_M1B: {
|
|
|
|
...achievementData["MONEY_M1B"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "-1b",
|
2022-01-08 20:54:21 +01:00
|
|
|
Secret: true,
|
|
|
|
Condition: () => Player.money <= -1e9,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
INSTALL_1: {
|
|
|
|
...achievementData["INSTALL_1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "install",
|
|
|
|
Condition: () => Player.augmentations.length >= 1,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
INSTALL_100: {
|
|
|
|
...achievementData["INSTALL_100"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "install_100",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.augmentations.length >= 100,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
QUEUE_40: {
|
|
|
|
...achievementData["QUEUE_40"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "queue40",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.queuedAugmentations.length >= 40,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
HACKING_100000: {
|
|
|
|
...achievementData["HACKING_100000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "hack100000",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.hacking >= 100000,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
COMBAT_3000: {
|
|
|
|
...achievementData["COMBAT_3000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "combat3000",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () =>
|
|
|
|
Player.strength >= 3000 && Player.defense >= 3000 && Player.dexterity >= 3000 && Player.agility >= 3000,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
NEUROFLUX_255: {
|
|
|
|
...achievementData["NEUROFLUX_255"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "nf255",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.augmentations.some((a) => a.name === AugmentationNames.NeuroFluxGovernor && a.level >= 255),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
NS2: {
|
|
|
|
...achievementData["NS2"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "ns2",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () =>
|
|
|
|
Player.getHomeComputer().scripts.some((s) => s.filename.endsWith(".js") || s.filename.endsWith(".ns")),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
FROZE: {
|
|
|
|
...achievementData["FROZE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "forze",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => location.href.includes("noScripts"),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
RUNNING_SCRIPTS_1000: {
|
|
|
|
...achievementData["RUNNING_SCRIPTS_1000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "run1000",
|
|
|
|
Condition: (): boolean => {
|
|
|
|
let running = 0;
|
|
|
|
for (const s of GetAllServers()) {
|
|
|
|
running += s.runningScripts.length;
|
|
|
|
}
|
|
|
|
return running >= 1000;
|
|
|
|
},
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
DRAIN_SERVER: {
|
|
|
|
...achievementData["DRAIN_SERVER"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "drain",
|
|
|
|
Condition: (): boolean => {
|
|
|
|
for (const s of GetAllServers()) {
|
|
|
|
if (s instanceof Server) {
|
|
|
|
if (s.moneyMax > 0 && s.moneyAvailable === 0) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MAX_RAM: {
|
|
|
|
...achievementData["MAX_RAM"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "maxram",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.getHomeComputer().maxRam === CONSTANTS.HomeComputerMaxRam,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MAX_CORES: {
|
|
|
|
...achievementData["MAX_CORES"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "maxcores",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.getHomeComputer().cpuCores === 8,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
SCRIPTS_30: {
|
|
|
|
...achievementData["SCRIPTS_30"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "folders",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.getHomeComputer().scripts.length >= 30,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
KARMA_1000000: {
|
|
|
|
...achievementData["KARMA_1000000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "karma",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.karma <= -1e6,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
STOCK_1q: {
|
|
|
|
...achievementData["STOCK_1q"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "$1Q",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.moneySourceB.stock >= 1e15,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
DISCOUNT: {
|
|
|
|
...achievementData["DISCOUNT"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "discount",
|
|
|
|
Condition: (): boolean => {
|
|
|
|
const p = GetServer("powerhouse-fitness");
|
|
|
|
if (!(p instanceof Server)) return false;
|
|
|
|
return p.backdoorInstalled;
|
|
|
|
},
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
SCRIPT_32GB: {
|
|
|
|
...achievementData["SCRIPT_32GB"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "bigcost",
|
|
|
|
Condition: () => Player.getHomeComputer().scripts.some((s) => s.ramUsage >= 32),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
FIRST_HACKNET_NODE: {
|
|
|
|
...achievementData["FIRST_HACKNET_NODE"],
|
2022-01-10 00:03:00 +01:00
|
|
|
Icon: "node",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
|
|
|
|
},
|
|
|
|
"30_HACKNET_NODE": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["30_HACKNET_NODE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "hacknet-all",
|
|
|
|
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length >= 30,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MAX_HACKNET_NODE: {
|
|
|
|
...achievementData["MAX_HACKNET_NODE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "hacknet-max",
|
|
|
|
Condition: (): boolean => {
|
|
|
|
if (hasHacknetServers(Player)) return false;
|
|
|
|
for (const h of Player.hacknetNodes) {
|
|
|
|
if (!(h instanceof HacknetNode)) return false;
|
|
|
|
if (
|
|
|
|
h.ram === HacknetNodeConstants.MaxRam &&
|
|
|
|
h.cores === HacknetNodeConstants.MaxCores &&
|
|
|
|
h.level === HacknetNodeConstants.MaxLevel
|
|
|
|
)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
HACKNET_NODE_10M: {
|
|
|
|
...achievementData["HACKNET_NODE_10M"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "hacknet-10m",
|
|
|
|
Condition: () => !hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 10e6,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
REPUTATION_10M: {
|
|
|
|
...achievementData["REPUTATION_10M"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "reputation",
|
|
|
|
Condition: () => Object.values(Factions).some((f) => f.playerReputation >= 10e6),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
DONATION: {
|
|
|
|
...achievementData["DONATION"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "donation",
|
|
|
|
Condition: () => Object.values(Factions).some((f) => f.favor >= 150),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
TRAVEL: {
|
|
|
|
...achievementData["TRAVEL"],
|
2022-01-16 03:27:27 +01:00
|
|
|
Icon: "TRAVEL",
|
2022-01-06 13:04:03 +01:00
|
|
|
Condition: () => Player.city !== CityName.Sector12,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
WORKOUT: {
|
|
|
|
...achievementData["WORKOUT"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "WORKOUT",
|
2022-07-07 23:28:23 +02:00
|
|
|
Condition: () => isClassWork(Player.currentWork),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
TOR: {
|
|
|
|
...achievementData["TOR"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "TOR",
|
|
|
|
Condition: () => Player.hasTorRouter(),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
HOSPITALIZED: {
|
|
|
|
...achievementData["HOSPITALIZED"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "OUCH",
|
|
|
|
Condition: () => Player.moneySourceB.hospitalization !== 0,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
GANG: {
|
|
|
|
...achievementData["GANG"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "GANG",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () => Player.gang !== null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
FULL_GANG: {
|
|
|
|
...achievementData["FULL_GANG"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "GANGMAX",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () => Player.gang !== null && Player.gang.members.length === GangConstants.MaximumGangMembers,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
GANG_TERRITORY: {
|
|
|
|
...achievementData["GANG_TERRITORY"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "GANG100%",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () => Player.gang !== null && AllGangs[Player.gang.facName].territory >= 0.999,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
GANG_MEMBER_POWER: {
|
|
|
|
...achievementData["GANG_MEMBER_POWER"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "GANG10000",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () =>
|
|
|
|
Player.gang !== null &&
|
2022-01-08 20:54:21 +01:00
|
|
|
Player.gang.members.some(
|
|
|
|
(m) =>
|
|
|
|
m.hack >= 10000 || m.str >= 10000 || m.def >= 10000 || m.dex >= 10000 || m.agi >= 10000 || m.cha >= 10000,
|
|
|
|
),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CORPORATION: {
|
|
|
|
...achievementData["CORPORATION"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CORP",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: () => Player.corporation !== null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CORPORATION_BRIBE: {
|
|
|
|
...achievementData["CORPORATION_BRIBE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CORPLOBBY",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: () => Player.corporation !== null && Player.corporation.unlockUpgrades[6] === 1,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CORPORATION_PROD_1000: {
|
|
|
|
...achievementData["CORPORATION_PROD_1000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CORP1000",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: () => Player.corporation !== null && Player.corporation.divisions.some((d) => d.prodMult >= 1000),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CORPORATION_EMPLOYEE_3000: {
|
|
|
|
...achievementData["CORPORATION_EMPLOYEE_3000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CORPCITY",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: (): boolean => {
|
|
|
|
if (Player.corporation === null) return false;
|
|
|
|
for (const d of Player.corporation.divisions) {
|
|
|
|
for (const o of Object.values(d.offices)) {
|
|
|
|
if (o === 0) continue;
|
2022-03-20 19:16:03 +01:00
|
|
|
if (o.employees.length >= 3000) return true;
|
2022-01-06 13:04:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CORPORATION_REAL_ESTATE: {
|
|
|
|
...achievementData["CORPORATION_REAL_ESTATE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "CORPRE",
|
|
|
|
Name: "Own the land",
|
|
|
|
Description: "Expand to the Real Estate division.",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () =>
|
|
|
|
Player.corporation !== null && Player.corporation.divisions.some((d) => d.type === Industries.RealEstate),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
INTELLIGENCE_255: {
|
|
|
|
...achievementData["INTELLIGENCE_255"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "INT255",
|
|
|
|
Visible: () => hasAccessToSF(Player, 5),
|
|
|
|
Condition: () => Player.intelligence >= 255,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
BLADEBURNER_DIVISION: {
|
|
|
|
...achievementData["BLADEBURNER_DIVISION"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BLADE",
|
|
|
|
Visible: () => hasAccessToSF(Player, 6),
|
|
|
|
Condition: () => Player.bladeburner !== null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
BLADEBURNER_OVERCLOCK: {
|
|
|
|
...achievementData["BLADEBURNER_OVERCLOCK"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BLADEOVERCLOCK",
|
|
|
|
Visible: () => hasAccessToSF(Player, 6),
|
|
|
|
Condition: () =>
|
|
|
|
Player.bladeburner !== null &&
|
|
|
|
Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock].maxLvl,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
BLADEBURNER_UNSPENT_100000: {
|
|
|
|
...achievementData["BLADEBURNER_UNSPENT_100000"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BLADE100K",
|
|
|
|
Visible: () => hasAccessToSF(Player, 6),
|
|
|
|
Condition: () => Player.bladeburner !== null && Player.bladeburner.skillPoints >= 100000,
|
|
|
|
},
|
|
|
|
"4S": {
|
2022-01-08 20:54:21 +01:00
|
|
|
...achievementData["4S"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "4S",
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.has4SData,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
FIRST_HACKNET_SERVER: {
|
|
|
|
...achievementData["FIRST_HACKNET_SERVER"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "HASHNET",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
|
2022-01-11 19:41:08 +01:00
|
|
|
AdditionalUnlock: [achievementData.FIRST_HACKNET_NODE.ID],
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
ALL_HACKNET_SERVER: {
|
|
|
|
...achievementData["ALL_HACKNET_SERVER"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "HASHNETALL",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
|
2022-01-11 19:41:08 +01:00
|
|
|
AdditionalUnlock: [achievementData["30_HACKNET_NODE"].ID],
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MAX_HACKNET_SERVER: {
|
|
|
|
...achievementData["MAX_HACKNET_SERVER"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "HASHNETALL",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: (): boolean => {
|
|
|
|
if (!hasHacknetServers(Player)) return false;
|
|
|
|
for (const h of Player.hacknetNodes) {
|
|
|
|
if (typeof h !== "string") return false;
|
|
|
|
const hs = GetServer(h);
|
|
|
|
if (!(hs instanceof HacknetServer)) return false;
|
|
|
|
if (
|
|
|
|
hs.maxRam === HacknetServerConstants.MaxRam &&
|
|
|
|
hs.cores === HacknetServerConstants.MaxCores &&
|
|
|
|
hs.level === HacknetServerConstants.MaxLevel &&
|
|
|
|
hs.cache === HacknetServerConstants.MaxCache
|
|
|
|
)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
2022-01-11 19:41:08 +01:00
|
|
|
AdditionalUnlock: [achievementData.MAX_HACKNET_NODE.ID],
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
HACKNET_SERVER_1B: {
|
|
|
|
...achievementData["HACKNET_SERVER_1B"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "HASHNETMONEY",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: () => hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 1e9,
|
2022-01-11 19:41:08 +01:00
|
|
|
AdditionalUnlock: [achievementData.HACKNET_NODE_10M.ID],
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
MAX_CACHE: {
|
|
|
|
...achievementData["MAX_CACHE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "HASHNETCAP",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
2022-03-16 19:39:23 +01:00
|
|
|
Condition: () =>
|
|
|
|
hasHacknetServers(Player) &&
|
2022-01-16 17:20:15 +01:00
|
|
|
Player.hashManager.hashes === Player.hashManager.capacity &&
|
|
|
|
Player.hashManager.capacity > 0,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
SLEEVE_8: {
|
|
|
|
...achievementData["SLEEVE_8"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SLEEVE8",
|
|
|
|
Visible: () => hasAccessToSF(Player, 10),
|
2022-03-21 04:27:53 +01:00
|
|
|
Condition: () => Player.sleeves.length === 8 && Player.sourceFileLvl(10) === 3,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
INDECISIVE: {
|
|
|
|
...achievementData["INDECISIVE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "1H",
|
|
|
|
Visible: () => knowsAboutBitverse(Player),
|
|
|
|
Condition: (function () {
|
|
|
|
let c = 0;
|
|
|
|
setInterval(() => {
|
|
|
|
if (Router.page() === Page.BitVerse) {
|
|
|
|
c++;
|
|
|
|
} else {
|
|
|
|
c = 0;
|
|
|
|
}
|
|
|
|
}, 60 * 1000);
|
|
|
|
return () => c > 60;
|
|
|
|
})(),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
FAST_BN: {
|
|
|
|
...achievementData["FAST_BN"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "2DAYS",
|
|
|
|
Visible: () => knowsAboutBitverse(Player),
|
|
|
|
Condition: () => bitNodeFinishedState() && Player.playtimeSinceLastBitnode < 1000 * 60 * 60 * 24 * 2,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN1: {
|
|
|
|
...achievementData["CHALLENGE_BN1"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN1+",
|
|
|
|
Visible: () => knowsAboutBitverse(Player),
|
|
|
|
Condition: () =>
|
|
|
|
Player.bitNodeN === 1 &&
|
|
|
|
bitNodeFinishedState() &&
|
|
|
|
Player.getHomeComputer().maxRam <= 128 &&
|
|
|
|
Player.getHomeComputer().cpuCores === 1,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN2: {
|
|
|
|
...achievementData["CHALLENGE_BN2"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN2+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 2),
|
|
|
|
Condition: () => Player.bitNodeN === 2 && bitNodeFinishedState() && Player.gang === null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN3: {
|
|
|
|
...achievementData["CHALLENGE_BN3"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN3+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 3),
|
|
|
|
Condition: () => Player.bitNodeN === 3 && bitNodeFinishedState() && Player.corporation === null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN6: {
|
|
|
|
...achievementData["CHALLENGE_BN6"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN6+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 6),
|
|
|
|
Condition: () => Player.bitNodeN === 6 && bitNodeFinishedState() && Player.bladeburner === null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN7: {
|
|
|
|
...achievementData["CHALLENGE_BN7"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN7+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 7),
|
|
|
|
Condition: () => Player.bitNodeN === 7 && bitNodeFinishedState() && Player.bladeburner === null,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN8: {
|
|
|
|
...achievementData["CHALLENGE_BN8"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN8+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 8),
|
|
|
|
Condition: () => Player.bitNodeN === 8 && bitNodeFinishedState() && !Player.has4SData && !Player.has4SDataTixApi,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN9: {
|
|
|
|
...achievementData["CHALLENGE_BN9"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN9+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 9),
|
|
|
|
Condition: () =>
|
|
|
|
Player.bitNodeN === 9 &&
|
|
|
|
bitNodeFinishedState() &&
|
|
|
|
Player.moneySourceB.hacknet === 0 &&
|
|
|
|
Player.moneySourceB.hacknet_expenses === 0,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN10: {
|
|
|
|
...achievementData["CHALLENGE_BN10"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN10+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 10),
|
|
|
|
Condition: () =>
|
|
|
|
Player.bitNodeN === 10 &&
|
|
|
|
bitNodeFinishedState() &&
|
|
|
|
!Player.sleeves.some(
|
|
|
|
(s) =>
|
|
|
|
s.augmentations.length > 0 ||
|
|
|
|
s.hacking_exp > 0 ||
|
|
|
|
s.strength_exp > 0 ||
|
|
|
|
s.defense_exp > 0 ||
|
|
|
|
s.agility_exp > 0 ||
|
|
|
|
s.dexterity_exp > 0 ||
|
|
|
|
s.charisma_exp > 0,
|
|
|
|
),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN12: {
|
|
|
|
...achievementData["CHALLENGE_BN12"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN12+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 12),
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.sourceFileLvl(12) >= 50,
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
BYPASS: {
|
|
|
|
...achievementData["BYPASS"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.Bypass),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
PROTOTYPETAMPERING: {
|
|
|
|
...achievementData["PROTOTYPETAMPERING"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.PrototypeTampering),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
UNCLICKABLE: {
|
|
|
|
...achievementData["UNCLICKABLE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.Unclickable),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
UNDOCUMENTEDFUNCTIONCALL: {
|
|
|
|
...achievementData["UNDOCUMENTEDFUNCTIONCALL"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.UndocumentedFunctionCall),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
TIMECOMPRESSION: {
|
|
|
|
...achievementData["TIMECOMPRESSION"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.TimeCompression),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
REALITYALTERATION: {
|
|
|
|
...achievementData["REALITYALTERATION"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.RealityAlteration),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
N00DLES: {
|
|
|
|
...achievementData["N00DLES"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.N00dles),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
EDITSAVEFILE: {
|
|
|
|
...achievementData["EDITSAVEFILE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.EditSaveFile),
|
2022-01-06 13:04:03 +01:00
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
UNACHIEVABLE: {
|
|
|
|
...achievementData["UNACHIEVABLE"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
|
|
|
// Hey Players! Yes, you're supposed to modify this to get the achievement!
|
|
|
|
Condition: () => false,
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
CHALLENGE_BN13: {
|
|
|
|
...achievementData["CHALLENGE_BN13"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "BN13+",
|
|
|
|
Visible: () => hasAccessToSF(Player, 13),
|
|
|
|
Condition: () =>
|
|
|
|
Player.bitNodeN === 13 &&
|
|
|
|
bitNodeFinishedState() &&
|
|
|
|
!Player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
DEVMENU: {
|
|
|
|
...achievementData["DEVMENU"],
|
2022-01-06 13:04:03 +01:00
|
|
|
Icon: "SF-1",
|
2022-01-13 18:22:43 +01:00
|
|
|
Secret: true,
|
2022-01-08 20:54:21 +01:00
|
|
|
Condition: () => Player.exploits.includes(Exploit.YoureNotMeantToAccessThis),
|
|
|
|
},
|
2022-03-16 19:39:23 +01:00
|
|
|
RAINBOW: {
|
|
|
|
...achievementData["RAINBOW"],
|
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
|
|
|
Condition: () => Player.exploits.includes(Exploit.INeedARainbow),
|
|
|
|
},
|
|
|
|
TRUE_RECURSION: {
|
|
|
|
...achievementData["TRUE_RECURSION"],
|
|
|
|
Icon: "SF-1",
|
|
|
|
Secret: true,
|
|
|
|
Condition: () => Player.exploits.includes(Exploit.TrueRecursion),
|
|
|
|
},
|
2022-01-08 20:54:21 +01:00
|
|
|
};
|
2022-01-06 13:04:03 +01:00
|
|
|
|
2022-01-08 20:54:21 +01:00
|
|
|
// Steam has a limit of 100 achievement. So these were planned but commented for now.
|
2022-03-19 09:09:59 +01:00
|
|
|
// { ID: FactionNames.ECorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.ECorp) },
|
|
|
|
// { ID: FactionNames.MegaCorp.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.MegaCorp) },
|
|
|
|
// { ID: "BACHMAN_&_ASSOCIATES", Condition: () => Player.factions.includes(FactionNames.BachmanAssociates) },
|
|
|
|
// { ID: "BLADE_INDUSTRIES", Condition: () => Player.factions.includes(FactionNames.BladeIndustries) },
|
|
|
|
// { ID: FactionNames.NWO.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.NWO) },
|
|
|
|
// { ID: "CLARKE_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.ClarkeIncorporated) },
|
|
|
|
// { ID: "OMNITEK_INCORPORATED", Condition: () => Player.factions.includes(FactionNames.OmniTekIncorporated) },
|
|
|
|
// { ID: "FOUR_SIGMA", Condition: () => Player.factions.includes(FactionNames.FourSigma) },
|
|
|
|
// { ID: "KUAIGONG_INTERNATIONAL", Condition: () => Player.factions.includes(FactionNames.KuaiGongInternational) },
|
|
|
|
// { ID: "FULCRUM_SECRET_TECHNOLOGIES", Condition: () => Player.factions.includes(FactionNames.FulcrumSecretTechnologies) },
|
|
|
|
// { ID: FactionNames.Aevum.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Aevum) },
|
|
|
|
// { ID: FactionNames.Chongqing.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Chongqing) },
|
|
|
|
// { ID: FactionNames.Ishima.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Ishima) },
|
|
|
|
// { ID: "NEW_TOKYO", Condition: () => Player.factions.includes(FactionNames.NewTokyo) },
|
|
|
|
// { ID: "SECTOR-12", Condition: () => Player.factions.includes(FactionNames.Sector12) },
|
|
|
|
// { ID: FactionNames.Volhaven.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Volhaven) },
|
|
|
|
// { ID: "SPEAKERS_FOR_THE_DEAD", Condition: () => Player.factions.includes(FactionNames.SpeakersForTheDead) },
|
|
|
|
// { ID: "THE_DARK_ARMY", Condition: () => Player.factions.includes(FactionNames.TheDarkArmy) },
|
|
|
|
// { ID: "THE_SYNDICATE", Condition: () => Player.factions.includes(FactionNames.TheSyndicate) },
|
|
|
|
// { ID: FactionNames.Silhouette.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Silhouette) },
|
|
|
|
// { ID: FactionNames.Tetrads.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Tetrads) },
|
|
|
|
// { ID: "SLUM_SNAKES", Condition: () => Player.factions.includes(FactionNames.SlumSnakes) },
|
|
|
|
// { ID: FactionNames.Netburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Netburners) },
|
|
|
|
// { ID: "TIAN_DI_HUI", Condition: () => Player.factions.includes(FactionNames.TianDiHui) },
|
|
|
|
// { ID: FactionNames.Bladeburners.toUpperCase(), Condition: () => Player.factions.includes(FactionNames.Bladeburners) },
|
2022-01-08 20:54:21 +01:00
|
|
|
// { ID: "DEEPSCANV1.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV1.name) },
|
|
|
|
// { ID: "DEEPSCANV2.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.DeepscanV2.name) },
|
2022-03-29 16:43:28 +02:00
|
|
|
// { ID: "INFILTRATORS", Condition: () => Player.factions.includes(FactionNames.Infiltrators) },
|
2022-01-08 20:54:21 +01:00
|
|
|
// {
|
|
|
|
// ID: "SERVERPROFILER.EXE",
|
|
|
|
// Condition: () => Player.getHomeComputer().programs.includes(Programs.ServerProfiler.name),
|
|
|
|
// },
|
|
|
|
// { ID: "AUTOLINK.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.AutoLink.name) },
|
|
|
|
// { ID: "FLIGHT.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.Flight.name) },
|
2022-01-06 13:04:03 +01:00
|
|
|
|
|
|
|
export function calculateAchievements(): void {
|
|
|
|
const playerAchievements = Player.achievements.map((a) => a.ID);
|
|
|
|
|
2022-01-11 18:42:20 +01:00
|
|
|
const missingAchievements = Object.values(achievements)
|
|
|
|
.filter((a) => !playerAchievements.includes(a.ID) && a.Condition())
|
2022-01-11 19:41:08 +01:00
|
|
|
// callback returns array of achievement id and id of any in the additional list, flatmap means we have only a 1D array
|
|
|
|
.flatMap((a) => [a.ID, ...(a.AdditionalUnlock || [])]);
|
2022-01-11 18:42:20 +01:00
|
|
|
|
|
|
|
for (const id of missingAchievements) {
|
2022-01-06 13:04:03 +01:00
|
|
|
Player.giveAchievement(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write all player's achievements to document for Steam/Electron
|
|
|
|
// This could be replaced by "availableAchievements"
|
|
|
|
// if we don't want to grant the save game achievements to steam but only currently available
|
2022-04-19 02:47:33 +02:00
|
|
|
document.achievements = [...Player.achievements.map((a) => a.ID)];
|
2022-01-06 13:04:03 +01:00
|
|
|
}
|