re-add achievemnets fix

This commit is contained in:
Olivier Gagnon 2022-01-08 14:54:21 -05:00
parent af50560a47
commit fe2270dc27

@ -20,11 +20,11 @@ import { SpecialServers } from "../Server/data/SpecialServers";
import { Server } from "../Server/Server"; import { Server } from "../Server/Server";
import { Router } from "../ui/GameRoot"; import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router"; import { Page } from "../ui/Router";
import { IMap } from '../types'; import { IMap } from "../types";
import * as data from "./AchievementData.json"; import * as data from "./AchievementData.json";
// Unable to correctly cast the JSON data into AchievementDataJson type otherwise... // Unable to correctly cast the JSON data into AchievementDataJson type otherwise...
const achievementData = (<AchievementDataJson><unknown>data).achievements; const achievementData = (<AchievementDataJson>(<unknown>data)).achievements;
export interface Achievement { export interface Achievement {
ID: string; ID: string;
@ -63,7 +63,7 @@ function hasAccessToSF(player: PlayerObject, bn: number): boolean {
} }
function knowsAboutBitverse(player: PlayerObject): boolean { function knowsAboutBitverse(player: PlayerObject): boolean {
return player.sourceFiles.some((a) => a.n === 1) return player.sourceFiles.some((a) => a.n === 1);
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -81,198 +81,199 @@ function sfAchievement(): Achievement[] {
} }
export const achievements: IMap<Achievement> = { export const achievements: IMap<Achievement> = {
"CYBERSEC": { CYBERSEC: {
...achievementData['CYBERSEC'], ...achievementData["CYBERSEC"],
Icon: "CSEC", Icon: "CSEC",
Condition: () => Player.factions.includes("CyberSec"), Condition: () => Player.factions.includes("CyberSec"),
}, },
"NITESEC": { NITESEC: {
...achievementData['NITESEC'], ...achievementData["NITESEC"],
Icon: "NiteSec", Icon: "NiteSec",
Condition: () => Player.factions.includes("NiteSec"), Condition: () => Player.factions.includes("NiteSec"),
}, },
"THE_BLACK_HAND": { THE_BLACK_HAND: {
...achievementData['THE_BLACK_HAND'], ...achievementData["THE_BLACK_HAND"],
Icon: "TBH", Icon: "TBH",
Condition: () => Player.factions.includes("The Black Hand"), Condition: () => Player.factions.includes("The Black Hand"),
}, },
"BITRUNNERS": { BITRUNNERS: {
...achievementData['BITRUNNERS'], ...achievementData["BITRUNNERS"],
Icon: 'bitrunners', Icon: "bitrunners",
Condition: () => Player.factions.includes("BitRunners"), Condition: () => Player.factions.includes("BitRunners"),
}, },
"DAEDALUS": { DAEDALUS: {
...achievementData['DAEDALUS'], ...achievementData["DAEDALUS"],
Icon: "daedalus", Icon: "daedalus",
Condition: () => Player.factions.includes("Daedalus"), Condition: () => Player.factions.includes("Daedalus"),
}, },
"THE_COVENANT": { THE_COVENANT: {
...achievementData['THE_COVENANT'], ...achievementData["THE_COVENANT"],
Icon: "thecovenant", Icon: "thecovenant",
Condition: () => Player.factions.includes("The Covenant"), Condition: () => Player.factions.includes("The Covenant"),
}, },
"ILLUMINATI": { ILLUMINATI: {
...achievementData['ILLUMINATI'], ...achievementData["ILLUMINATI"],
Icon: 'illuminati', Icon: "illuminati",
Condition: () => Player.factions.includes("Illuminati"), Condition: () => Player.factions.includes("Illuminati"),
}, },
"BRUTESSH.EXE": { "BRUTESSH.EXE": {
...achievementData['BRUTESSH.EXE'], ...achievementData["BRUTESSH.EXE"],
Icon: 'p0', Icon: "p0",
Condition: () => Player.getHomeComputer().programs.includes(Programs.BruteSSHProgram.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.BruteSSHProgram.name),
}, },
"FTPCRACK.EXE": { "FTPCRACK.EXE": {
...achievementData['FTPCRACK.EXE'], ...achievementData["FTPCRACK.EXE"],
Icon: 'p1', Icon: "p1",
Condition: () => Player.getHomeComputer().programs.includes(Programs.FTPCrackProgram.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.FTPCrackProgram.name),
}, },
//----------------------------------------------------- //-----------------------------------------------------
"RELAYSMTP.EXE": { "RELAYSMTP.EXE": {
...achievementData['RELAYSMTP.EXE'], ...achievementData["RELAYSMTP.EXE"],
Icon: 'p2', Icon: "p2",
Condition: () => Player.getHomeComputer().programs.includes(Programs.RelaySMTPProgram.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.RelaySMTPProgram.name),
}, },
"HTTPWORM.EXE": { "HTTPWORM.EXE": {
...achievementData['HTTPWORM.EXE'], ...achievementData["HTTPWORM.EXE"],
Icon: 'p3', Icon: "p3",
Condition: () => Player.getHomeComputer().programs.includes(Programs.HTTPWormProgram.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.HTTPWormProgram.name),
}, },
"SQLINJECT.EXE": { "SQLINJECT.EXE": {
...achievementData['SQLINJECT.EXE'], ...achievementData["SQLINJECT.EXE"],
Icon: 'p4', Icon: "p4",
Condition: () => Player.getHomeComputer().programs.includes(Programs.SQLInjectProgram.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.SQLInjectProgram.name),
}, },
"FORMULAS.EXE": { "FORMULAS.EXE": {
...achievementData['FORMULAS.EXE'], ...achievementData["FORMULAS.EXE"],
Icon: 'formulas', Icon: "formulas",
Condition: () => Player.getHomeComputer().programs.includes(Programs.Formulas.name), Condition: () => Player.getHomeComputer().programs.includes(Programs.Formulas.name),
}, },
"SF1.1": { "SF1.1": {
...achievementData['SF1.1'], ...achievementData["SF1.1"],
Icon: 'SF1.1', Icon: "SF1.1",
Visible: () => hasAccessToSF(Player, 1), Visible: () => hasAccessToSF(Player, 1),
Condition: () => Player.sourceFileLvl(1) >= 1 Condition: () => Player.sourceFileLvl(1) >= 1,
}, },
"SF2.1": { "SF2.1": {
...achievementData['SF2.1'], ...achievementData["SF2.1"],
Icon: "SF2.1", Icon: "SF2.1",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Player.sourceFileLvl(2) >= 1, Condition: () => Player.sourceFileLvl(2) >= 1,
}, },
"SF3.1": { "SF3.1": {
...achievementData['SF3.1'], ...achievementData["SF3.1"],
Icon: "SF3.1", Icon: "SF3.1",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.sourceFileLvl(3) >= 1, Condition: () => Player.sourceFileLvl(3) >= 1,
}, },
"SF4.1": { "SF4.1": {
...achievementData['SF4.1'], ...achievementData["SF4.1"],
Icon: "SF4.1", Icon: "SF4.1",
Visible: () => hasAccessToSF(Player, 4), Visible: () => hasAccessToSF(Player, 4),
Condition: () => Player.sourceFileLvl(4) >= 1, Condition: () => Player.sourceFileLvl(4) >= 1,
}, },
"SF5.1": { "SF5.1": {
...achievementData['SF5.1'], ...achievementData["SF5.1"],
Icon: "SF5.1", Icon: "SF5.1",
Visible: () => hasAccessToSF(Player, 5), Visible: () => hasAccessToSF(Player, 5),
Condition: () => Player.sourceFileLvl(5) >= 1, Condition: () => Player.sourceFileLvl(5) >= 1,
}, },
"SF6.1": { "SF6.1": {
...achievementData['SF6.1'], ...achievementData["SF6.1"],
Icon: "SF6.1", Icon: "SF6.1",
Visible: () => hasAccessToSF(Player, 6), Visible: () => hasAccessToSF(Player, 6),
Condition: () => Player.sourceFileLvl(6) >= 1, Condition: () => Player.sourceFileLvl(6) >= 1,
}, },
"SF7.1": { "SF7.1": {
...achievementData['SF7.1'], ...achievementData["SF7.1"],
Icon: "SF7.1", Icon: "SF7.1",
Visible: () => hasAccessToSF(Player, 7), Visible: () => hasAccessToSF(Player, 7),
Condition: () => Player.sourceFileLvl(7) >= 1, Condition: () => Player.sourceFileLvl(7) >= 1,
}, },
"SF8.1": { "SF8.1": {
...achievementData['SF8.1'], ...achievementData["SF8.1"],
Icon: "SF8.1", Icon: "SF8.1",
Visible: () => hasAccessToSF(Player, 8), Visible: () => hasAccessToSF(Player, 8),
Condition: () => Player.sourceFileLvl(8) >= 1, Condition: () => Player.sourceFileLvl(8) >= 1,
}, },
"SF9.1": { "SF9.1": {
...achievementData['SF9.1'], ...achievementData["SF9.1"],
Icon: "SF9.1", Icon: "SF9.1",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => Player.sourceFileLvl(9) >= 1, Condition: () => Player.sourceFileLvl(9) >= 1,
}, },
"SF10.1": { "SF10.1": {
...achievementData['SF10.1'], ...achievementData["SF10.1"],
Icon: "SF10.1", Icon: "SF10.1",
Visible: () => hasAccessToSF(Player, 10), Visible: () => hasAccessToSF(Player, 10),
Condition: () => Player.sourceFileLvl(10) >= 1 Condition: () => Player.sourceFileLvl(10) >= 1,
}, },
"SF11.1": { "SF11.1": {
...achievementData['SF11.1'], ...achievementData["SF11.1"],
Icon: "SF11.1", Icon: "SF11.1",
Visible: () => hasAccessToSF(Player, 11), Visible: () => hasAccessToSF(Player, 11),
Condition: () => Player.sourceFileLvl(11) >= 1 Condition: () => Player.sourceFileLvl(11) >= 1,
}, },
"SF12.1": { "SF12.1": {
...achievementData['SF12.1'], ...achievementData["SF12.1"],
Icon: "SF12.1", Icon: "SF12.1",
Visible: () => hasAccessToSF(Player, 12), Visible: () => hasAccessToSF(Player, 12),
Condition: () => Player.sourceFileLvl(12) >= 1 Condition: () => Player.sourceFileLvl(12) >= 1,
}, },
"MONEY_1Q": { MONEY_1Q: {
...achievementData['MONEY_1Q'], ...achievementData["MONEY_1Q"],
Icon: "$1Q", Icon: "$1Q",
Condition: () => Player.money >= 1e18, Condition: () => Player.money >= 1e18,
}, },
"MONEY_M1B": { MONEY_M1B: {
...achievementData['MONEY_M1B'], ...achievementData["MONEY_M1B"],
Icon: "-1b", Icon: "-1b",
Secret: true, Secret: true,
Condition: () => Player.money <= -1e9, Condition: () => Player.money <= -1e9,
}, },
"INSTALL_1": { INSTALL_1: {
...achievementData['INSTALL_1'], ...achievementData["INSTALL_1"],
Icon: "install", Icon: "install",
Condition: () => Player.augmentations.length >= 1, Condition: () => Player.augmentations.length >= 1,
}, },
"INSTALL_100": { INSTALL_100: {
...achievementData['INSTALL_100'], ...achievementData["INSTALL_100"],
Icon: "install_100", Icon: "install_100",
Condition: () => Player.augmentations.length >= 100, Condition: () => Player.augmentations.length >= 100,
}, },
"QUEUE_40": { QUEUE_40: {
...achievementData['QUEUE_40'], ...achievementData["QUEUE_40"],
Icon: "queue40", Icon: "queue40",
Condition: () => Player.queuedAugmentations.length >= 40, Condition: () => Player.queuedAugmentations.length >= 40,
}, },
"HACKING_100000": { HACKING_100000: {
...achievementData['HACKING_100000'], ...achievementData["HACKING_100000"],
Icon: "hack100000", Icon: "hack100000",
Condition: () => Player.hacking >= 100000, Condition: () => Player.hacking >= 100000,
}, },
"COMBAT_3000": { COMBAT_3000: {
...achievementData['COMBAT_3000'], ...achievementData["COMBAT_3000"],
Icon: "combat3000", Icon: "combat3000",
Condition: () => Condition: () =>
Player.strength >= 3000 && Player.defense >= 3000 && Player.dexterity >= 3000 && Player.agility >= 3000, Player.strength >= 3000 && Player.defense >= 3000 && Player.dexterity >= 3000 && Player.agility >= 3000,
}, },
"NEUROFLUX_255": { NEUROFLUX_255: {
...achievementData['NEUROFLUX_255'], ...achievementData["NEUROFLUX_255"],
Icon: "nf255", Icon: "nf255",
Condition: () => Player.augmentations.some((a) => a.name === AugmentationNames.NeuroFluxGovernor && a.level >= 255), Condition: () => Player.augmentations.some((a) => a.name === AugmentationNames.NeuroFluxGovernor && a.level >= 255),
}, },
"NS2": { NS2: {
...achievementData['NS2'], ...achievementData["NS2"],
Icon: "ns2", Icon: "ns2",
Condition: () => Player.getHomeComputer().scripts.some((s) => s.filename.endsWith(".js") || s.filename.endsWith(".ns")), Condition: () =>
Player.getHomeComputer().scripts.some((s) => s.filename.endsWith(".js") || s.filename.endsWith(".ns")),
}, },
"FROZE": { FROZE: {
...achievementData['FROZE'], ...achievementData["FROZE"],
Icon: "forze", Icon: "forze",
Condition: () => location.href.includes("noScripts") Condition: () => location.href.includes("noScripts"),
}, },
"RUNNING_SCRIPTS_1000": { RUNNING_SCRIPTS_1000: {
...achievementData['RUNNING_SCRIPTS_1000'], ...achievementData["RUNNING_SCRIPTS_1000"],
Icon: "run1000", Icon: "run1000",
Condition: (): boolean => { Condition: (): boolean => {
let running = 0; let running = 0;
@ -282,8 +283,8 @@ export const achievements: IMap<Achievement> = {
return running >= 1000; return running >= 1000;
}, },
}, },
"DRAIN_SERVER": { DRAIN_SERVER: {
...achievementData['DRAIN_SERVER'], ...achievementData["DRAIN_SERVER"],
Icon: "drain", Icon: "drain",
Condition: (): boolean => { Condition: (): boolean => {
for (const s of GetAllServers()) { for (const s of GetAllServers()) {
@ -294,34 +295,34 @@ export const achievements: IMap<Achievement> = {
return false; return false;
}, },
}, },
"MAX_RAM": { MAX_RAM: {
...achievementData['MAX_RAM'], ...achievementData["MAX_RAM"],
Icon: "maxram", Icon: "maxram",
Condition: () => Player.getHomeComputer().maxRam === CONSTANTS.HomeComputerMaxRam Condition: () => Player.getHomeComputer().maxRam === CONSTANTS.HomeComputerMaxRam,
}, },
"MAX_CORES": { MAX_CORES: {
...achievementData['MAX_CORES'], ...achievementData["MAX_CORES"],
Icon: "maxcores", Icon: "maxcores",
Condition: () => Player.getHomeComputer().cpuCores === 8 Condition: () => Player.getHomeComputer().cpuCores === 8,
}, },
"SCRIPTS_30": { SCRIPTS_30: {
...achievementData['SCRIPTS_30'], ...achievementData["SCRIPTS_30"],
Icon: "folders", Icon: "folders",
Condition: () => Player.getHomeComputer().scripts.length >= 30 Condition: () => Player.getHomeComputer().scripts.length >= 30,
}, },
"KARMA_1000000": { KARMA_1000000: {
...achievementData['KARMA_1000000'], ...achievementData["KARMA_1000000"],
Icon: "karma", Icon: "karma",
Secret: true, Secret: true,
Condition: () => Player.karma <= -1e6 Condition: () => Player.karma <= -1e6,
}, },
"STOCK_1q": { STOCK_1q: {
...achievementData['STOCK_1q'], ...achievementData["STOCK_1q"],
Icon: "$1Q", Icon: "$1Q",
Condition: () => Player.moneySourceB.stock >= 1e15 Condition: () => Player.moneySourceB.stock >= 1e15,
}, },
"DISCOUNT": { DISCOUNT: {
...achievementData['DISCOUNT'], ...achievementData["DISCOUNT"],
Icon: "discount", Icon: "discount",
Condition: (): boolean => { Condition: (): boolean => {
const p = GetServer("powerhouse-fitness"); const p = GetServer("powerhouse-fitness");
@ -329,22 +330,22 @@ export const achievements: IMap<Achievement> = {
return p.backdoorInstalled; return p.backdoorInstalled;
}, },
}, },
"SCRIPT_32GB": { SCRIPT_32GB: {
...achievementData['SCRIPT_32GB'], ...achievementData["SCRIPT_32GB"],
Icon: "bigcost", Icon: "bigcost",
Condition: () => Player.getHomeComputer().scripts.some((s) => s.ramUsage >= 32), Condition: () => Player.getHomeComputer().scripts.some((s) => s.ramUsage >= 32),
}, },
"FIRST_HACKNET_NODE": { FIRST_HACKNET_NODE: {
...achievementData['FIRST_HACKNET_NODE'], ...achievementData["FIRST_HACKNET_NODE"],
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length > 0, Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
}, },
"30_HACKNET_NODE": { "30_HACKNET_NODE": {
...achievementData['30_HACKNET_NODE'], ...achievementData["30_HACKNET_NODE"],
Icon: "hacknet-all", Icon: "hacknet-all",
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length >= 30, Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length >= 30,
}, },
"MAX_HACKNET_NODE": { MAX_HACKNET_NODE: {
...achievementData['MAX_HACKNET_NODE'], ...achievementData["MAX_HACKNET_NODE"],
Icon: "hacknet-max", Icon: "hacknet-max",
Condition: (): boolean => { Condition: (): boolean => {
if (hasHacknetServers(Player)) return false; if (hasHacknetServers(Player)) return false;
@ -360,28 +361,28 @@ export const achievements: IMap<Achievement> = {
return false; return false;
}, },
}, },
"HACKNET_NODE_10M": { HACKNET_NODE_10M: {
...achievementData['HACKNET_NODE_10M'], ...achievementData["HACKNET_NODE_10M"],
Icon: "hacknet-10m", Icon: "hacknet-10m",
Condition: () => !hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 10e6, Condition: () => !hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 10e6,
}, },
"REPUTATION_10M": { REPUTATION_10M: {
...achievementData['REPUTATION_10M'], ...achievementData["REPUTATION_10M"],
Icon: "reputation", Icon: "reputation",
Condition: () => Object.values(Factions).some((f) => f.playerReputation >= 10e6), Condition: () => Object.values(Factions).some((f) => f.playerReputation >= 10e6),
}, },
"DONATION": { DONATION: {
...achievementData['DONATION'], ...achievementData["DONATION"],
Icon: "donation", Icon: "donation",
Condition: () => Object.values(Factions).some((f) => f.favor >= 150), Condition: () => Object.values(Factions).some((f) => f.favor >= 150),
}, },
"TRAVEL": { TRAVEL: {
...achievementData['TRAVEL'], ...achievementData["TRAVEL"],
Icon: "travel", Icon: "travel",
Condition: () => Player.city !== CityName.Sector12, Condition: () => Player.city !== CityName.Sector12,
}, },
"WORKOUT": { WORKOUT: {
...achievementData['WORKOUT'], ...achievementData["WORKOUT"],
Icon: "WORKOUT", Icon: "WORKOUT",
Condition: () => Condition: () =>
[ [
@ -391,62 +392,65 @@ export const achievements: IMap<Achievement> = {
CONSTANTS.ClassGymAgility, CONSTANTS.ClassGymAgility,
].includes(Player.className), ].includes(Player.className),
}, },
"TOR": { TOR: {
...achievementData['TOR'], ...achievementData["TOR"],
Icon: "TOR", Icon: "TOR",
Condition: () => Player.hasTorRouter(), Condition: () => Player.hasTorRouter(),
}, },
"HOSPITALIZED": { HOSPITALIZED: {
...achievementData['HOSPITALIZED'], ...achievementData["HOSPITALIZED"],
Icon: "OUCH", Icon: "OUCH",
Condition: () => Player.moneySourceB.hospitalization !== 0, Condition: () => Player.moneySourceB.hospitalization !== 0,
}, },
"GANG": { GANG: {
...achievementData['GANG'], ...achievementData["GANG"],
Icon: "GANG", Icon: "GANG",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Player.gang !== null, Condition: () => Player.gang !== null,
}, },
"FULL_GANG": { FULL_GANG: {
...achievementData['FULL_GANG'], ...achievementData["FULL_GANG"],
Icon: "GANGMAX", Icon: "GANGMAX",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Player.gang !== null && Player.gang.members.length === GangConstants.MaximumGangMembers, Condition: () => Player.gang !== null && Player.gang.members.length === GangConstants.MaximumGangMembers,
}, },
"GANG_TERRITORY": { GANG_TERRITORY: {
...achievementData['GANG_TERRITORY'], ...achievementData["GANG_TERRITORY"],
Icon: "GANG100%", Icon: "GANG100%",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Player.gang !== null && AllGangs[Player.gang.facName].territory >= 0.999, Condition: () => Player.gang !== null && AllGangs[Player.gang.facName].territory >= 0.999,
}, },
"GANG_MEMBER_POWER": { GANG_MEMBER_POWER: {
...achievementData['GANG_MEMBER_POWER'], ...achievementData["GANG_MEMBER_POWER"],
Icon: "GANG10000", Icon: "GANG10000",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Condition: () =>
Player.gang !== null && Player.gang !== null &&
Player.gang.members.some((m) => m.hack >= 10000 || m.str >= 10000 || m.def >= 10000 || m.dex >= 10000 || m.agi >= 10000 || m.cha >= 10000), Player.gang.members.some(
(m) =>
m.hack >= 10000 || m.str >= 10000 || m.def >= 10000 || m.dex >= 10000 || m.agi >= 10000 || m.cha >= 10000,
),
}, },
"CORPORATION": { CORPORATION: {
...achievementData['CORPORATION'], ...achievementData["CORPORATION"],
Icon: "CORP", Icon: "CORP",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.corporation !== null, Condition: () => Player.corporation !== null,
}, },
"CORPORATION_BRIBE": { CORPORATION_BRIBE: {
...achievementData['CORPORATION_BRIBE'], ...achievementData["CORPORATION_BRIBE"],
Icon: "CORPLOBBY", Icon: "CORPLOBBY",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.corporation !== null && Player.corporation.unlockUpgrades[6] === 1, Condition: () => Player.corporation !== null && Player.corporation.unlockUpgrades[6] === 1,
}, },
"CORPORATION_PROD_1000": { CORPORATION_PROD_1000: {
...achievementData['CORPORATION_PROD_1000'], ...achievementData["CORPORATION_PROD_1000"],
Icon: "CORP1000", Icon: "CORP1000",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.corporation !== null && Player.corporation.divisions.some((d) => d.prodMult >= 1000), Condition: () => Player.corporation !== null && Player.corporation.divisions.some((d) => d.prodMult >= 1000),
}, },
"CORPORATION_EMPLOYEE_3000": { CORPORATION_EMPLOYEE_3000: {
...achievementData['CORPORATION_EMPLOYEE_3000'], ...achievementData["CORPORATION_EMPLOYEE_3000"],
Icon: "CORPCITY", Icon: "CORPCITY",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: (): boolean => { Condition: (): boolean => {
@ -454,65 +458,66 @@ export const achievements: IMap<Achievement> = {
for (const d of Player.corporation.divisions) { for (const d of Player.corporation.divisions) {
for (const o of Object.values(d.offices)) { for (const o of Object.values(d.offices)) {
if (o === 0) continue; if (o === 0) continue;
if (o.employees.length > 3000) return true; if (o.employees.length >= 3000) return true;
} }
} }
return false; return false;
}, },
}, },
"CORPORATION_REAL_ESTATE": { CORPORATION_REAL_ESTATE: {
...achievementData['CORPORATION_REAL_ESTATE'], ...achievementData["CORPORATION_REAL_ESTATE"],
Icon: "CORPRE", Icon: "CORPRE",
Name: "Own the land", Name: "Own the land",
Description: "Expand to the Real Estate division.", Description: "Expand to the Real Estate division.",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.corporation !== null && Player.corporation.divisions.some((d) => d.type === Industries.RealEstate), Condition: () =>
Player.corporation !== null && Player.corporation.divisions.some((d) => d.type === Industries.RealEstate),
}, },
"INTELLIGENCE_255": { INTELLIGENCE_255: {
...achievementData['INTELLIGENCE_255'], ...achievementData["INTELLIGENCE_255"],
Icon: "INT255", Icon: "INT255",
Visible: () => hasAccessToSF(Player, 5), Visible: () => hasAccessToSF(Player, 5),
Condition: () => Player.intelligence >= 255, Condition: () => Player.intelligence >= 255,
}, },
"BLADEBURNER_DIVISION": { BLADEBURNER_DIVISION: {
...achievementData['BLADEBURNER_DIVISION'], ...achievementData["BLADEBURNER_DIVISION"],
Icon: "BLADE", Icon: "BLADE",
Visible: () => hasAccessToSF(Player, 6), Visible: () => hasAccessToSF(Player, 6),
Condition: () => Player.bladeburner !== null, Condition: () => Player.bladeburner !== null,
}, },
"BLADEBURNER_OVERCLOCK": { BLADEBURNER_OVERCLOCK: {
...achievementData['BLADEBURNER_OVERCLOCK'], ...achievementData["BLADEBURNER_OVERCLOCK"],
Icon: "BLADEOVERCLOCK", Icon: "BLADEOVERCLOCK",
Visible: () => hasAccessToSF(Player, 6), Visible: () => hasAccessToSF(Player, 6),
Condition: () => Condition: () =>
Player.bladeburner !== null && Player.bladeburner !== null &&
Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock].maxLvl, Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock].maxLvl,
}, },
"BLADEBURNER_UNSPENT_100000": { BLADEBURNER_UNSPENT_100000: {
...achievementData['BLADEBURNER_UNSPENT_100000'], ...achievementData["BLADEBURNER_UNSPENT_100000"],
Icon: "BLADE100K", Icon: "BLADE100K",
Visible: () => hasAccessToSF(Player, 6), Visible: () => hasAccessToSF(Player, 6),
Condition: () => Player.bladeburner !== null && Player.bladeburner.skillPoints >= 100000, Condition: () => Player.bladeburner !== null && Player.bladeburner.skillPoints >= 100000,
}, },
"4S": { "4S": {
...achievementData['4S'], ...achievementData["4S"],
Icon: "4S", Icon: "4S",
Condition: () => Player.has4SData Condition: () => Player.has4SData,
}, },
"FIRST_HACKNET_SERVER": { FIRST_HACKNET_SERVER: {
...achievementData['FIRST_HACKNET_SERVER'], ...achievementData["FIRST_HACKNET_SERVER"],
Icon: "HASHNET", Icon: "HASHNET",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length > 0, Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
}, },
"ALL_HACKNET_SERVER": { ALL_HACKNET_SERVER: {
...achievementData['ALL_HACKNET_SERVER'], ...achievementData["ALL_HACKNET_SERVER"],
Icon: "HASHNETALL", Icon: "HASHNETALL",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length === HacknetServerConstants.MaxServers, Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
}, },
"MAX_HACKNET_SERVER": { MAX_HACKNET_SERVER: {
...achievementData['MAX_HACKNET_SERVER'], ...achievementData["MAX_HACKNET_SERVER"],
Icon: "HASHNETALL", Icon: "HASHNETALL",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: (): boolean => { Condition: (): boolean => {
@ -532,26 +537,26 @@ export const achievements: IMap<Achievement> = {
return false; return false;
}, },
}, },
"HACKNET_SERVER_1B": { HACKNET_SERVER_1B: {
...achievementData['HACKNET_SERVER_1B'], ...achievementData["HACKNET_SERVER_1B"],
Icon: "HASHNETMONEY", Icon: "HASHNETMONEY",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 1e9, Condition: () => hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 1e9,
}, },
"MAX_CACHE": { MAX_CACHE: {
...achievementData['MAX_CACHE'], ...achievementData["MAX_CACHE"],
Icon: "HASHNETCAP", Icon: "HASHNETCAP",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.hashManager.hashes === Player.hashManager.capacity, Condition: () => hasHacknetServers(Player) && Player.hashManager.hashes === Player.hashManager.capacity,
}, },
"SLEEVE_8": { SLEEVE_8: {
...achievementData['SLEEVE_8'], ...achievementData["SLEEVE_8"],
Icon: "SLEEVE8", Icon: "SLEEVE8",
Visible: () => hasAccessToSF(Player, 10), Visible: () => hasAccessToSF(Player, 10),
Condition: () => Player.sleeves.length === 8, Condition: () => Player.sleeves.length === 8,
}, },
"INDECISIVE": { INDECISIVE: {
...achievementData['INDECISIVE'], ...achievementData["INDECISIVE"],
Icon: "1H", Icon: "1H",
Visible: () => knowsAboutBitverse(Player), Visible: () => knowsAboutBitverse(Player),
Condition: (function () { Condition: (function () {
@ -566,14 +571,14 @@ export const achievements: IMap<Achievement> = {
return () => c > 60; return () => c > 60;
})(), })(),
}, },
"FAST_BN": { FAST_BN: {
...achievementData['FAST_BN'], ...achievementData["FAST_BN"],
Icon: "2DAYS", Icon: "2DAYS",
Visible: () => knowsAboutBitverse(Player), Visible: () => knowsAboutBitverse(Player),
Condition: () => bitNodeFinishedState() && Player.playtimeSinceLastBitnode < 1000 * 60 * 60 * 24 * 2, Condition: () => bitNodeFinishedState() && Player.playtimeSinceLastBitnode < 1000 * 60 * 60 * 24 * 2,
}, },
"CHALLENGE_BN1": { CHALLENGE_BN1: {
...achievementData['CHALLENGE_BN1'], ...achievementData["CHALLENGE_BN1"],
Icon: "BN1+", Icon: "BN1+",
Visible: () => knowsAboutBitverse(Player), Visible: () => knowsAboutBitverse(Player),
Condition: () => Condition: () =>
@ -582,38 +587,38 @@ export const achievements: IMap<Achievement> = {
Player.getHomeComputer().maxRam <= 128 && Player.getHomeComputer().maxRam <= 128 &&
Player.getHomeComputer().cpuCores === 1, Player.getHomeComputer().cpuCores === 1,
}, },
"CHALLENGE_BN2": { CHALLENGE_BN2: {
...achievementData['CHALLENGE_BN2'], ...achievementData["CHALLENGE_BN2"],
Icon: "BN2+", Icon: "BN2+",
Visible: () => hasAccessToSF(Player, 2), Visible: () => hasAccessToSF(Player, 2),
Condition: () => Player.bitNodeN === 2 && bitNodeFinishedState() && Player.gang === null, Condition: () => Player.bitNodeN === 2 && bitNodeFinishedState() && Player.gang === null,
}, },
"CHALLENGE_BN3": { CHALLENGE_BN3: {
...achievementData['CHALLENGE_BN3'], ...achievementData["CHALLENGE_BN3"],
Icon: "BN3+", Icon: "BN3+",
Visible: () => hasAccessToSF(Player, 3), Visible: () => hasAccessToSF(Player, 3),
Condition: () => Player.bitNodeN === 3 && bitNodeFinishedState() && Player.corporation === null, Condition: () => Player.bitNodeN === 3 && bitNodeFinishedState() && Player.corporation === null,
}, },
"CHALLENGE_BN6": { CHALLENGE_BN6: {
...achievementData['CHALLENGE_BN6'], ...achievementData["CHALLENGE_BN6"],
Icon: "BN6+", Icon: "BN6+",
Visible: () => hasAccessToSF(Player, 6), Visible: () => hasAccessToSF(Player, 6),
Condition: () => Player.bitNodeN === 6 && bitNodeFinishedState() && Player.bladeburner === null, Condition: () => Player.bitNodeN === 6 && bitNodeFinishedState() && Player.bladeburner === null,
}, },
"CHALLENGE_BN7": { CHALLENGE_BN7: {
...achievementData['CHALLENGE_BN7'], ...achievementData["CHALLENGE_BN7"],
Icon: "BN7+", Icon: "BN7+",
Visible: () => hasAccessToSF(Player, 7), Visible: () => hasAccessToSF(Player, 7),
Condition: () => Player.bitNodeN === 7 && bitNodeFinishedState() && Player.bladeburner === null, Condition: () => Player.bitNodeN === 7 && bitNodeFinishedState() && Player.bladeburner === null,
}, },
"CHALLENGE_BN8": { CHALLENGE_BN8: {
...achievementData['CHALLENGE_BN8'], ...achievementData["CHALLENGE_BN8"],
Icon: "BN8+", Icon: "BN8+",
Visible: () => hasAccessToSF(Player, 8), Visible: () => hasAccessToSF(Player, 8),
Condition: () => Player.bitNodeN === 8 && bitNodeFinishedState() && !Player.has4SData && !Player.has4SDataTixApi, Condition: () => Player.bitNodeN === 8 && bitNodeFinishedState() && !Player.has4SData && !Player.has4SDataTixApi,
}, },
"CHALLENGE_BN9": { CHALLENGE_BN9: {
...achievementData['CHALLENGE_BN9'], ...achievementData["CHALLENGE_BN9"],
Icon: "BN9+", Icon: "BN9+",
Visible: () => hasAccessToSF(Player, 9), Visible: () => hasAccessToSF(Player, 9),
Condition: () => Condition: () =>
@ -622,8 +627,8 @@ export const achievements: IMap<Achievement> = {
Player.moneySourceB.hacknet === 0 && Player.moneySourceB.hacknet === 0 &&
Player.moneySourceB.hacknet_expenses === 0, Player.moneySourceB.hacknet_expenses === 0,
}, },
"CHALLENGE_BN10": { CHALLENGE_BN10: {
...achievementData['CHALLENGE_BN10'], ...achievementData["CHALLENGE_BN10"],
Icon: "BN10+", Icon: "BN10+",
Visible: () => hasAccessToSF(Player, 10), Visible: () => hasAccessToSF(Player, 10),
Condition: () => Condition: () =>
@ -640,69 +645,69 @@ export const achievements: IMap<Achievement> = {
s.charisma_exp > 0, s.charisma_exp > 0,
), ),
}, },
"CHALLENGE_BN12": { CHALLENGE_BN12: {
...achievementData['CHALLENGE_BN12'], ...achievementData["CHALLENGE_BN12"],
Icon: "BN12+", Icon: "BN12+",
Visible: () => hasAccessToSF(Player, 12), Visible: () => hasAccessToSF(Player, 12),
Condition: () => Player.sourceFileLvl(12) >= 50 Condition: () => Player.sourceFileLvl(12) >= 50,
}, },
"BYPASS": { BYPASS: {
...achievementData['BYPASS'], ...achievementData["BYPASS"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.Bypass) Condition: () => Player.exploits.includes(Exploit.Bypass),
}, },
"PROTOTYPETAMPERING": { PROTOTYPETAMPERING: {
...achievementData['PROTOTYPETAMPERING'], ...achievementData["PROTOTYPETAMPERING"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.PrototypeTampering) Condition: () => Player.exploits.includes(Exploit.PrototypeTampering),
}, },
"UNCLICKABLE": { UNCLICKABLE: {
...achievementData['UNCLICKABLE'], ...achievementData["UNCLICKABLE"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.Unclickable) Condition: () => Player.exploits.includes(Exploit.Unclickable),
}, },
"UNDOCUMENTEDFUNCTIONCALL": { UNDOCUMENTEDFUNCTIONCALL: {
...achievementData['UNDOCUMENTEDFUNCTIONCALL'], ...achievementData["UNDOCUMENTEDFUNCTIONCALL"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.UndocumentedFunctionCall) Condition: () => Player.exploits.includes(Exploit.UndocumentedFunctionCall),
}, },
"TIMECOMPRESSION": { TIMECOMPRESSION: {
...achievementData['TIMECOMPRESSION'], ...achievementData["TIMECOMPRESSION"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.TimeCompression) Condition: () => Player.exploits.includes(Exploit.TimeCompression),
}, },
"REALITYALTERATION": { REALITYALTERATION: {
...achievementData['REALITYALTERATION'], ...achievementData["REALITYALTERATION"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.RealityAlteration) Condition: () => Player.exploits.includes(Exploit.RealityAlteration),
}, },
"N00DLES": { N00DLES: {
...achievementData['N00DLES'], ...achievementData["N00DLES"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.N00dles) Condition: () => Player.exploits.includes(Exploit.N00dles),
}, },
"EDITSAVEFILE": { EDITSAVEFILE: {
...achievementData['EDITSAVEFILE'], ...achievementData["EDITSAVEFILE"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
Condition: () => Player.exploits.includes(Exploit.EditSaveFile) Condition: () => Player.exploits.includes(Exploit.EditSaveFile),
}, },
"UNACHIEVABLE": { UNACHIEVABLE: {
...achievementData['UNACHIEVABLE'], ...achievementData["UNACHIEVABLE"],
Icon: "SF-1", Icon: "SF-1",
Secret: true, Secret: true,
// Hey Players! Yes, you're supposed to modify this to get the achievement! // Hey Players! Yes, you're supposed to modify this to get the achievement!
Condition: () => false, Condition: () => false,
}, },
"CHALLENGE_BN13": { CHALLENGE_BN13: {
...achievementData['CHALLENGE_BN13'], ...achievementData["CHALLENGE_BN13"],
Icon: "BN13+", Icon: "BN13+",
Visible: () => hasAccessToSF(Player, 13), Visible: () => hasAccessToSF(Player, 13),
Condition: () => Condition: () =>
@ -710,12 +715,12 @@ export const achievements: IMap<Achievement> = {
bitNodeFinishedState() && bitNodeFinishedState() &&
!Player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1), !Player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1),
}, },
"DEVMENU": { DEVMENU: {
...achievementData['DEVMENU'], ...achievementData["DEVMENU"],
Icon: "SF-1", Icon: "SF-1",
Condition: () => Player.exploits.includes(Exploit.YoureNotMeantToAccessThis) Condition: () => Player.exploits.includes(Exploit.YoureNotMeantToAccessThis),
} },
} };
// Steam has a limit of 100 achievement. So these were planned but commented for now. // Steam has a limit of 100 achievement. So these were planned but commented for now.
// { ID: "ECORP", Condition: () => Player.factions.includes("ECorp") }, // { ID: "ECORP", Condition: () => Player.factions.includes("ECorp") },
@ -753,9 +758,11 @@ export const achievements: IMap<Achievement> = {
// { ID: "FLIGHT.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.Flight.name) }, // { ID: "FLIGHT.EXE", Condition: () => Player.getHomeComputer().programs.includes(Programs.Flight.name) },
export function calculateAchievements(): void { export function calculateAchievements(): void {
const availableAchievements = Object.values(achievements).filter((a) => a.Condition()).map((a) => a.ID); const availableAchievements = Object.values(achievements)
.filter((a) => a.Condition())
.map((a) => a.ID);
const playerAchievements = Player.achievements.map((a) => a.ID); const playerAchievements = Player.achievements.map((a) => a.ID);
const newAchievements = availableAchievements.filter(a => !playerAchievements.includes(a)); const newAchievements = availableAchievements.filter((a) => !playerAchievements.includes(a));
for (const id of newAchievements) { for (const id of newAchievements) {
Player.giveAchievement(id); Player.giveAchievement(id);
@ -764,5 +771,5 @@ export function calculateAchievements(): void {
// Write all player's achievements to document for Steam/Electron // Write all player's achievements to document for Steam/Electron
// This could be replaced by "availableAchievements" // This could be replaced by "availableAchievements"
// if we don't want to grant the save game achievements to steam but only currently available // if we don't want to grant the save game achievements to steam but only currently available
(document as any).achievements = [...Player.achievements.map(a => a.ID)]; (document as any).achievements = [...Player.achievements.map((a) => a.ID)];
} }