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]);
+ }
}
}