UNPKG

osrs-tools

Version:

A comprehensive TypeScript library for Old School RuneScape (OSRS) data and utilities, including quest data, skill requirements, and game item information

125 lines (124 loc) 5.73 kB
import { COLLECTION_LOG_CATEGORIES, CollectionLogCategory, } from "./CollectionLog.model"; const COLLECTION_LOG_SOURCE = "https://oldschool.runescape.wiki/w/Collection_log"; const item = (id, name) => ({ id, name, wikiUrl: COLLECTION_LOG_SOURCE, }); const entry = (id, name, category, activity, items) => ({ id, name, category, activity, items, }); export const COLLECTION_LOG_DATASET = { source: COLLECTION_LOG_SOURCE, entries: [ entry("cl-zulrah", "Zulrah", CollectionLogCategory.Bosses, "Zulrah", [ item("cl-zulrah-magic-fang", "Magic fang"), item("cl-zulrah-serp-visage", "Serpentine visage"), item("cl-zulrah-tanz-fang", "Tanzanite fang"), item("cl-zulrah-pet", "Pet snakeling"), ]), entry("cl-vorkath", "Vorkath", CollectionLogCategory.Bosses, "Vorkath", [ item("cl-vorkath-draconic-visage", "Draconic visage"), item("cl-vorkath-skeletal-visage", "Skeletal visage"), item("cl-vorkath-dragonbone-necklace", "Dragonbone necklace"), item("cl-vorkath-head", "Vorkath's head"), item("cl-vorkath-pet", "Vorki"), ]), entry("cl-barrows", "Barrows Chests", CollectionLogCategory.Bosses, "Barrows", [ item("cl-barrows-dharok-helm", "Dharok's helm"), item("cl-barrows-karil-top", "Karil's leathertop"), item("cl-barrows-ahrim-top", "Ahrim's robetop"), item("cl-barrows-guthan-spear", "Guthan's warspear"), ]), entry("cl-cox", "Chambers of Xeric", CollectionLogCategory.Raids, "Chambers of Xeric", [ item("cl-cox-twisted-bow", "Twisted bow"), item("cl-cox-ancestral-top", "Ancestral robe top"), item("cl-cox-dex-scroll", "Dexterous prayer scroll"), item("cl-cox-kodai-insignia", "Kodai insignia"), item("cl-cox-olmlet", "Olmlet"), ]), entry("cl-tob", "Theatre of Blood", CollectionLogCategory.Raids, "Theatre of Blood", [ item("cl-tob-scythe", "Scythe of vitur"), item("cl-tob-rapier", "Ghrazi rapier"), item("cl-tob-sanguinesti", "Sanguinesti staff"), item("cl-tob-lil-zik", "Lil' zik"), ]), entry("cl-toa", "Tombs of Amascut", CollectionLogCategory.Raids, "Tombs of Amascut", [ item("cl-toa-shadow", "Tumeken's shadow"), item("cl-toa-fang", "Osmumten's fang"), item("cl-toa-ward", "Elidinis' ward"), item("cl-toa-ics", "Icthlarin's shroud"), item("cl-toa-pet", "Tumeken's guardian"), ]), ], }; function normalizeIdSet(itemIds) { return new Set(itemIds.map((itemId) => itemId.trim().toLowerCase())); } function percent(obtained, total) { if (total === 0) return 0; return Number(((obtained / total) * 100).toFixed(2)); } export function getCollectionLogEntries(dataset = COLLECTION_LOG_DATASET) { return [...dataset.entries]; } export function getCollectionLogEntryById(entryId, dataset = COLLECTION_LOG_DATASET) { const normalizedEntryId = entryId.trim().toLowerCase(); return dataset.entries.find((logEntry) => logEntry.id.toLowerCase() === normalizedEntryId); } export function getCollectionLogEntriesByCategory(category, dataset = COLLECTION_LOG_DATASET) { return dataset.entries.filter((logEntry) => logEntry.category === category); } export function getMissingCollectionLogItems(obtainedItemIds, dataset = COLLECTION_LOG_DATASET) { const obtainedIds = normalizeIdSet(obtainedItemIds); return dataset.entries .flatMap((logEntry) => logEntry.items) .filter((logItem) => !obtainedIds.has(logItem.id.toLowerCase())); } function entryProgress(logEntry, obtainedIds) { const obtained = logEntry.items.filter((logItem) => obtainedIds.has(logItem.id.toLowerCase())).length; const missingItemIds = logEntry.items .filter((logItem) => !obtainedIds.has(logItem.id.toLowerCase())) .map((logItem) => logItem.id); return { entryId: logEntry.id, entryName: logEntry.name, category: logEntry.category, total: logEntry.items.length, obtained, completionPercent: percent(obtained, logEntry.items.length), missingItemIds, }; } function categoryProgress(category, entrySummaries) { const categoryEntries = entrySummaries.filter((entrySummary) => entrySummary.category === category); const total = categoryEntries.reduce((runningTotal, entrySummary) => runningTotal + entrySummary.total, 0); const obtained = categoryEntries.reduce((runningTotal, entrySummary) => runningTotal + entrySummary.obtained, 0); return { category, total, obtained, completionPercent: percent(obtained, total), missingItemIds: categoryEntries.flatMap((entrySummary) => entrySummary.missingItemIds), }; } export function calculateCollectionLogProgress(obtainedItemIds, dataset = COLLECTION_LOG_DATASET) { const obtainedIds = normalizeIdSet(obtainedItemIds); const byEntry = dataset.entries.map((logEntry) => entryProgress(logEntry, obtainedIds)); const byCategory = COLLECTION_LOG_CATEGORIES.map((category) => categoryProgress(category, byEntry)); const total = byEntry.reduce((runningTotal, entrySummary) => runningTotal + entrySummary.total, 0); const obtained = byEntry.reduce((runningTotal, entrySummary) => runningTotal + entrySummary.obtained, 0); return { total, obtained, completionPercent: percent(obtained, total), byEntry, byCategory, missingItemIds: byEntry.flatMap((entrySummary) => entrySummary.missingItemIds), }; }