diff --git a/apps/frontend/components/auctions/AuctionsMissingBigResults.svelte b/apps/frontend/components/auctions/AuctionsMissingBigResults.svelte index f6e3842c9..2344b6880 100644 --- a/apps/frontend/components/auctions/AuctionsMissingBigResults.svelte +++ b/apps/frontend/components/auctions/AuctionsMissingBigResults.svelte @@ -13,7 +13,6 @@ import { settingsState } from '@/shared/state/settings.svelte'; import { wowthingData } from '@/shared/stores/data'; import { componentTooltip } from '@/shared/utils/tooltips'; - import { userStore } from '@/stores'; import { auctionState } from '@/stores/local-storage'; import { userState } from '@/user-home/state/user'; import { @@ -49,7 +48,7 @@ userAuctionMissingTransmogStore.search( settingsState.value, $auctionState, - $userStore, + userState.general, slug1.replace('missing-appearance-', '') ); } diff --git a/apps/frontend/components/items/tokens/TokenItem.svelte b/apps/frontend/components/items/tokens/TokenItem.svelte index 031e6731e..5f1b3ce2c 100644 --- a/apps/frontend/components/items/tokens/TokenItem.svelte +++ b/apps/frontend/components/items/tokens/TokenItem.svelte @@ -244,7 +244,7 @@ {/if} - {#if showItemIcon} + {#if showItemIcon || !classId} {:else if classId} - {:else} - {/if} {#if classId && !showItemIcon} diff --git a/apps/frontend/components/items/tokens/Tokens.svelte b/apps/frontend/components/items/tokens/Tokens.svelte index 8d246300d..db46cd6b5 100644 --- a/apps/frontend/components/items/tokens/Tokens.svelte +++ b/apps/frontend/components/items/tokens/Tokens.svelte @@ -15,6 +15,7 @@ let tiers = $derived.by(() => { const lookup = new Set(wowthingData.journal.tokenEncounters); + lookup.add('396'); // Battle for Azeroth // const itemsById = $state.snapshot(userState.general.itemsById); const ret: TierData = []; @@ -59,27 +60,36 @@ } } - if (items.size > 0) { - const itemsArray = Array.from(items); - itemsArray.sort((a, b) => { - const aParts = a.split('|').map((s) => parseInt(s)); - const bParts = b.split('|').map((s) => parseInt(s)); + addItems(instances, instance, items); + } - const aItem = wowthingData.items.items[aParts[0]]; - const bItem = wowthingData.items.items[bParts[0]]; + // Benthic token hack + if (tier.id === 396) { + const items = new Set(); - if (aItem.name !== bItem.name) { - return aItem.name.localeCompare(bItem.name); + for (const itemId of [ + 169477, 169478, 169479, 169480, 169481, 169482, 169483, 169484, 169485, + ]) { + const haveItems = userState.general.itemsById[itemId]; + for (const [, userItems] of haveItems || []) { + for (const userItem of userItems) { + const modifier = getBonusIdModifier(userItem.bonusIds); + items.add(`${itemId}|${modifier}|${userItem.bonusIds.join(',')}`); } - - return ( - (itemModifierOrder[aParts[1]] || 0) - - (itemModifierOrder[bParts[1]] || 0) - ); - }); - - instances.push([instance, itemsArray]); + } } + + addItems( + instances, + { + id: 3960001, + name: 'Benthic Armor', + slug: 'benthic-armor', + encounters: [], + encountersRaw: [], + }, + items + ); } if (instances.length > 0) { @@ -90,6 +100,31 @@ return ret; }); + const addItems = ( + instances: InstanceData, + instance: JournalDataInstance, + items: Set + ) => { + if (items.size > 0) { + const itemsArray = Array.from(items); + itemsArray.sort((a, b) => { + const aParts = a.split('|').map((s) => parseInt(s)); + const bParts = b.split('|').map((s) => parseInt(s)); + + const aItem = wowthingData.items.items[aParts[0]]; + const bItem = wowthingData.items.items[bParts[0]]; + + if (aItem.name !== bItem.name) { + return aItem.name.localeCompare(bItem.name); + } + + return (itemModifierOrder[aParts[1]] || 0) - (itemModifierOrder[bParts[1]] || 0); + }); + + instances.push([instance, itemsArray]); + } + }; + let containerElement = $state(null); let resizeableElement = $state(null); let debouncedResize: () => void = $derived.by(() => { diff --git a/apps/frontend/data/spells.ts b/apps/frontend/data/spells.ts index ca5539af3..ffa6399cc 100644 --- a/apps/frontend/data/spells.ts +++ b/apps/frontend/data/spells.ts @@ -34,8 +34,10 @@ export const durationAuras: [number, string, boolean?][] = [ [471544, 'Mastery of Timeways II'], [1229052, 'Knowledge of Timeways III'], [1229050, 'Mastery of Timeways III'], - [1229052, 'Knowledge of Timeways III'], + [1258529, 'Knowledge of Timeways IV'], [1258528, 'Mastery of Timeways IV'], + [1269517, 'Knowledge of Timeways V'], + [1269518, 'Mastery of Timeways V'], ]; export const staticAuras: [number, string][] = [ diff --git a/apps/frontend/data/tasks/11-midnight/12-0.ts b/apps/frontend/data/tasks/11-midnight/12-0.ts index ff33d9da3..d23522830 100644 --- a/apps/frontend/data/tasks/11-midnight/12-0.ts +++ b/apps/frontend/data/tasks/11-midnight/12-0.ts @@ -284,7 +284,7 @@ export const midChores12_0: Task = { }, { key: 'showdownNormal', - name: 'Showdown: Normal', + name: 'Showdown [N]', icon: 'S:squareN:', minimumLevel: 80, questReset: DbResetType.Weekly, @@ -312,7 +312,7 @@ export const midChores12_0: Task = { }, { key: 'showdownHeroic', - name: 'Showdown: Heroic', + name: 'Showdown [H]', icon: 'S:squareH:', minimumLevel: 90, questReset: DbResetType.Weekly, diff --git a/apps/frontend/data/tasks/events/timewalking.ts b/apps/frontend/data/tasks/events/timewalking.ts index 1d6ade933..a1422fdbf 100644 --- a/apps/frontend/data/tasks/events/timewalking.ts +++ b/apps/frontend/data/tasks/events/timewalking.ts @@ -28,6 +28,7 @@ export const eventTimewalking: Task = { 86564, // A Fel Journey Through Time [Legion not max] 88808, // A Scarred Journey Through Time [BfA not max] 92647, // A Shadowed Journey Through Time [SL not max] + 93495, // A Soaring Journey Through Time [DF not max] ]; } else { return [ @@ -41,6 +42,7 @@ export const eventTimewalking: Task = { 93627, // A Scarred Path Through Time [BfA max] 92649, // A Shadowed Path Through Time [SL max] 93628, // A Shadowed Path Through Time [SL max] + 93497, // A Soaring Path Through Time [DF max] ]; } }, @@ -63,6 +65,7 @@ export const eventTimewalking: Task = { 89222, // BfA [A] 89223, // BfA [H] 92650, // SL + 93852, // DF ], }, { diff --git a/apps/frontend/stores/user-auctions/missing-transmog.ts b/apps/frontend/stores/user-auctions/missing-transmog.ts index af7d7724c..e785f7ecc 100644 --- a/apps/frontend/stores/user-auctions/missing-transmog.ts +++ b/apps/frontend/stores/user-auctions/missing-transmog.ts @@ -15,6 +15,7 @@ import type { Settings } from '@/shared/stores/settings/types'; import type { AuctionState } from '../local-storage'; import type { UserAuctionEntry } from '../user-auctions'; +import type { DataUserGeneral } from '@/user-home/state/user/general.svelte'; export class UserAuctionMissingTransmogDataStore { private static url = '/api/auctions/missing-appearance-'; @@ -23,7 +24,7 @@ export class UserAuctionMissingTransmogDataStore { async search( settings: Settings, auctionState: AuctionState, - userData: UserData, + userData: DataUserGeneral, searchType: string ): Promise<[UserAuctionEntry[], Record]> { let things: UserAuctionEntry[] = []; diff --git a/apps/frontend/user-home/state/user/general.svelte.ts b/apps/frontend/user-home/state/user/general.svelte.ts index 18f9aead2..581d7bd56 100644 --- a/apps/frontend/user-home/state/user/general.svelte.ts +++ b/apps/frontend/user-home/state/user/general.svelte.ts @@ -29,13 +29,20 @@ import { leftPad } from '@/utils/formatting'; import { getNumberKeyedEntries } from '@/utils/get-number-keyed-entries'; import { sharedState } from '@/shared/state/shared.svelte'; import { WarbankItem } from '@/types/items'; -import type { Faction } from '@/enums/faction'; +import { getBonusIdModifier } from '@/utils/items/get-bonus-id-modifier'; import { logErrors } from '@/utils/log-errors'; +import type { Faction } from '@/enums/faction'; +import type { ContainsItems } from '@/types/shared/contains-items'; import type { HasNameAndRealm } from '@/types/shared/has-name-and-realm'; import type { UserItem } from '@/types/shared/user-item'; import type { CharacterQuests } from './types'; type GeneralProcessFunc = (generalState: DataUserGeneral) => void; +type ItemsByStuff = { + byAppearanceId: Record; + byAppearanceSource: Record; + byId: Record; +}; export class DataUserGeneral { public accountById: Record = $state({}); @@ -70,7 +77,9 @@ export class DataUserGeneral { public charactersByConnectedRealmId = $derived.by(() => this._charactersByConnectedRealmId()); public charactersByRealmId = $derived.by(() => this._charactersByRealmId()); public homeLockouts = $derived.by(() => this._homeLockouts()); - public itemsById = $derived.by(() => logErrors(() => this._itemsById())); + public itemsByAppearanceId = $derived.by(() => this._itemsByStuff.byAppearanceId); + public itemsByAppearanceSource = $derived.by(() => this._itemsByStuff.byAppearanceSource); + public itemsById = $derived.by(() => this._itemsByStuff.byId); public visibleCharacters = $derived.by(() => this._visibleCharacters()); private _warbankScannedAt: string; @@ -417,25 +426,86 @@ export class DataUserGeneral { return homeLockouts; } - private _itemsById() { - const ret: Record = {}; + private _itemsByStuff = $derived.by(() => + logErrors(() => { + const ret: ItemsByStuff = { + byAppearanceId: {}, + byAppearanceSource: {}, + byId: {}, + }; + const warbankTemp: { + byAppearanceId: Record; + byAppearanceSource: Record; + } = { + byAppearanceId: {}, + byAppearanceSource: {}, + }; + + for (const character of this.activeCharacters) { + this.setAppearanceData(ret, character); + } - for (const character of this.activeCharacters) { - for (const [itemId, items] of getNumberKeyedEntries(character.itemsById)) { - (ret[itemId] ||= []).push([character, items]); + for (const guild of Object.values(this.guildById)) { + this.setAppearanceData(ret, guild); } - } - for (const [itemId, items] of getNumberKeyedEntries(this.warbankItemsByItemId)) { - (ret[itemId] ||= []).push([null, items]); - } + for (const [itemId, items] of getNumberKeyedEntries(this.warbankItemsByItemId)) { + (ret.byId[itemId] ||= []).push([null, items]); + + for (const warbankItem of items) { + const item = wowthingData.items.items[warbankItem.itemId]; + if (Object.values(item?.appearances || {}).length === 0) { + continue; + } + + let modifier = getBonusIdModifier(warbankItem.bonusIds); + + warbankItem.appearanceId = item.appearances[modifier]?.appearanceId; + if (warbankItem.appearanceId === undefined && modifier > 0) { + modifier = 0; + warbankItem.appearanceId = item.appearances[modifier]?.appearanceId; + } + warbankItem.appearanceModifier = modifier; + warbankItem.appearanceSource = `${warbankItem.itemId}_${modifier}`; + + if (warbankItem.appearanceId !== undefined) { + (warbankTemp.byAppearanceId[warbankItem.appearanceId] ||= []).push( + warbankItem + ); + (warbankTemp.byAppearanceSource[warbankItem.appearanceSource] ||= []).push( + warbankItem + ); + } + } + } - for (const guild of Object.values(this.guildById)) { - for (const [itemId, items] of getNumberKeyedEntries(guild.itemsById)) { - (ret[itemId] ||= []).push([guild, items]); + for (const [appearanceId, warbankItems] of getNumberKeyedEntries( + warbankTemp.byAppearanceId + )) { + (ret.byAppearanceId[appearanceId] ||= []).push([null, warbankItems]); } + + for (const [appearanceSource, warbankItems] of Object.entries( + warbankTemp.byAppearanceSource + )) { + (ret.byAppearanceSource[appearanceSource] ||= []).push([null, warbankItems]); + } + + return ret; + }) + ); + + private setAppearanceData(data: ItemsByStuff, owner: HasNameAndRealm & ContainsItems): void { + for (const [itemId, items] of getNumberKeyedEntries(owner.itemsById)) { + (data.byId[itemId] ||= []).push([owner, items]); } - return ret; + for (const [appearanceId, items] of getNumberKeyedEntries(owner.itemsByAppearanceId)) { + (data.byAppearanceId[appearanceId] ||= []).push([owner, items]); + } + + for (const [appearanceSource, items] of Object.entries(owner.itemsByAppearanceSource)) { + (data.byAppearanceSource[appearanceSource] ||= []).push([owner, items]); + } } }