diff --git a/apps/frontend/components/home/table/paragon/Tooltip.svelte b/apps/frontend/components/home/table/paragon/Tooltip.svelte index 4e8dde22b..4ace6669c 100644 --- a/apps/frontend/components/home/table/paragon/Tooltip.svelte +++ b/apps/frontend/components/home/table/paragon/Tooltip.svelte @@ -15,13 +15,14 @@ getNumberKeyedEntries( groupBy( getNumberKeyedEntries(paragonQuests), - ([repId]) => wowthingData.static.reputationById.get(repId)?.expansion || 0 + ([repId]) => + wowthingData.static.reputationByParagonId.get(repId)?.expansion || 0 ) ).map(([expansion, reputations]) => [ expansion, sortBy( reputations, - ([repId]) => wowthingData.static.reputationById.get(repId)?.name || 'ZZZ' + ([repId]) => wowthingData.static.reputationByParagonId.get(repId)?.name || 'ZZZ' ), ]), ([expansion]) => expansion @@ -54,7 +55,8 @@ {#each reputations as [reputationId, characterIds]} - {@const reputation = wowthingData.static.reputationById.get(reputationId)} + {@const reputation = + wowthingData.static.reputationByParagonId.get(reputationId)} {@const characters = sortBy( characterIds .map((id) => userState.general.characterById[id]) diff --git a/apps/frontend/components/items/convertible/data.ts b/apps/frontend/components/items/convertible/data.ts index 4fcb5ccb9..9da61d6f6 100644 --- a/apps/frontend/components/items/convertible/data.ts +++ b/apps/frontend/components/items/convertible/data.ts @@ -1,3 +1,4 @@ +import { ItemLevels } from '@/data/constants'; import { AppearanceModifier } from '@/enums/appearance-modifier'; import { ArmorType } from '@/enums/armor-type'; import { InventoryType } from '@/enums/inventory-type'; @@ -53,22 +54,22 @@ export const convertibleCategories: ConvertibleCategory[] = [ conversionCurrencyId: 3465, // Venomblight Manaflux tiers: [ { - itemLevel: 318, + itemLevel: ItemLevels.Myth[1], highUpgrade: currentUpgrade4, lowUpgrade: currentUpgrade3, }, { - itemLevel: 305, + itemLevel: ItemLevels.Hero[1], highUpgrade: currentUpgrade3, lowUpgrade: currentUpgrade2, }, { - itemLevel: 292, + itemLevel: ItemLevels.Champion[1], highUpgrade: currentUpgrade2, lowUpgrade: currentUpgrade1, }, { - itemLevel: 279, + itemLevel: ItemLevels.Veteran[1], highUpgrade: currentUpgrade1, }, ], diff --git a/apps/frontend/components/tooltips/reputation/TooltipReputation.svelte b/apps/frontend/components/tooltips/reputation/TooltipReputation.svelte index 873d2899a..ee80b84f6 100644 --- a/apps/frontend/components/tooltips/reputation/TooltipReputation.svelte +++ b/apps/frontend/components/tooltips/reputation/TooltipReputation.svelte @@ -2,10 +2,7 @@ import { Constants } from '@/data/constants'; import { wowthingData } from '@/shared/stores/data'; import { toNiceNumber } from '@/utils/formatting'; - import type { - StaticDataReputation, - StaticDataReputationTier, - } from '@/shared/stores/static/types'; + import type { StaticDataReputation } from '@/shared/stores/static/types'; import type { Character, CharacterReputationParagon } from '@/types'; import type { ManualDataReputationSet } from '@/types/data/manual'; import { brannHack, nazjatarHack, valeeraHack } from './hacks'; @@ -13,27 +10,30 @@ import RenownTooltip from './TooltipReputationRenown.svelte'; import WowthingImage from '@/shared/components/images/sources/WowthingImage.svelte'; - export let bottom: string = undefined; - export let character: Character = undefined; - export let characterRep: number; - export let dataRep: StaticDataReputation; - export let paragon: CharacterReputationParagon = undefined; - export let reputation: ManualDataReputationSet = undefined; - - let reps: { - cls: string; - maxValue: number; - minValue: number; - name: string; - thisOne: boolean; - }[]; - - $: { - const tiers: StaticDataReputationTier = - wowthingData.static.reputationTierById.get(dataRep.tierId) || - wowthingData.static.reputationTierById.get(0); - - reps = []; + type Props = { + characterRep: number; + dataRep: StaticDataReputation; + bottom?: string; + character?: Character; + paragon?: CharacterReputationParagon; + reputation?: ManualDataReputationSet; + }; + let { characterRep, dataRep, bottom, character, paragon, reputation }: Props = $props(); + + let tiers = $derived( + wowthingData.static.reputationTierById.get(dataRep.tierId) || + wowthingData.static.reputationTierById.get(0) + ); + + let reps = $derived.by(() => { + const ret: { + cls: string; + maxValue: number; + minValue: number; + name: string; + thisOne: boolean; + }[] = []; + let foundIndex = -1; for (let i = 0; i < tiers.names.length; i++) { let minValue = tiers.minValues[i]; @@ -73,7 +73,7 @@ } } - reps.push({ + ret.push({ cls: 'quality0', maxValue, minValue, @@ -83,44 +83,44 @@ } // Apply quality colours to the bottom 5 tiers - const start = Math.max(0, reps.length - 1); + const start = Math.max(0, ret.length - 1); const setClass = Math.max(0, start - 5); let seenThisOne = false; let badCount = 0; for (let i = start; i >= 0; i--) { - if (reps[i].maxValue <= 0) { - reps[i].cls = ['status-shrug', 'status-warn', 'status-fail'][Math.min(2, badCount)]; + if (ret[i].maxValue <= 0) { + ret[i].cls = ['status-shrug', 'status-warn', 'status-fail'][Math.min(2, badCount)]; badCount++; } else if ( dataRep.id === Constants.reputations.delveBrann || dataRep.id === Constants.reputations.delveValeera || Constants.reputations.nazjatarFriends.includes(dataRep.id) ) { - const levelMatch = reps[i].name.match(/ (\d{1,3})/); + const levelMatch = ret[i].name.match(/ (\d{1,3})/); if (levelMatch) { if (dataRep.id === Constants.reputations.delveBrann) { - reps[i].cls = `reputation${brannHack(levelMatch[1])}`; + ret[i].cls = `reputation${brannHack(levelMatch[1])}`; } else if (dataRep.id === Constants.reputations.delveValeera) { - reps[i].cls = `reputation${valeeraHack(levelMatch[1])}`; + ret[i].cls = `reputation${valeeraHack(levelMatch[1])}`; } else { - reps[i].cls = `reputation${nazjatarHack(reps[i].name)}`; + ret[i].cls = `reputation${nazjatarHack(ret[i].name)}`; } } } else if (i >= setClass) { - reps[i].cls = `reputation${start - i + 1}`; + ret[i].cls = `reputation${start - i + 1}`; } - if (reps[i].thisOne) { + if (ret[i].thisOne) { if (!seenThisOne) { seenThisOne = true; } else { - reps[i].thisOne = false; + ret[i].thisOne = false; } } } if (paragon) { - reps.push({ + ret.push({ cls: 'quality6', maxValue: 10000, minValue: 0, @@ -128,7 +128,9 @@ thisOne: false, }); } - } + + return ret; + }); - diff --git a/apps/frontend/shared/icons/library.ts b/apps/frontend/shared/icons/library.ts index 51bf62918..1f3d3a451 100644 --- a/apps/frontend/shared/icons/library.ts +++ b/apps/frontend/shared/icons/library.ts @@ -60,6 +60,7 @@ export { default as gameHeartNecklace } from '~icons/game-icons/heart-necklace'; export { default as gameHeartPlus } from '~icons/game-icons/heart-plus'; export { default as gameHouse } from '~icons/game-icons/house'; export { default as gameJigsawBox } from '~icons/game-icons/jigsaw-box'; +export { default as gameKey } from '~icons/game-icons/key'; export { default as gameKnapsack } from '~icons/game-icons/knapsack'; export { default as gameLabradorHead } from '~icons/game-icons/labrador-head'; export { default as gameLockedFortress } from '~icons/game-icons/locked-fortress'; diff --git a/apps/frontend/shared/stores/data/static/process.ts b/apps/frontend/shared/stores/data/static/process.ts index cf0ff2368..4fa22ccfd 100644 --- a/apps/frontend/shared/stores/data/static/process.ts +++ b/apps/frontend/shared/stores/data/static/process.ts @@ -163,6 +163,13 @@ export function processStaticData(rawData: RawStatic): DataStatic { data.keystoneAffixBySlug.set(keystoneAffix.slug, keystoneAffix); } + data.reputationByParagonId = new Map(); + for (const reputation of data.reputationById.values()) { + if (reputation.paragonId) { + data.reputationByParagonId.set(reputation.paragonId, reputation); + } + } + for (const mount of data.mountById.values()) { for (const itemId of mount.itemIds) { data.mountByItemId.set(itemId, mount); diff --git a/apps/frontend/shared/stores/data/static/types.ts b/apps/frontend/shared/stores/data/static/types.ts index 4e5db2a8f..c11f4e80f 100644 --- a/apps/frontend/shared/stores/data/static/types.ts +++ b/apps/frontend/shared/stores/data/static/types.ts @@ -134,6 +134,7 @@ export class DataStatic { public questLineById: Map; public realmById: Map; public reputationById: Map; + public reputationByParagonId: Map; public toyById: Map; public transmogSetById: Map; public worldQuestById: Map; diff --git a/apps/frontend/user-home/components/reputations/AccountWide.svelte b/apps/frontend/user-home/components/reputations/AccountWide.svelte index f93779d26..faa34c10a 100644 --- a/apps/frontend/user-home/components/reputations/AccountWide.svelte +++ b/apps/frontend/user-home/components/reputations/AccountWide.svelte @@ -91,13 +91,10 @@ class="account-rep {cls} flex-wrapper" use:componentTooltip={{ component: TooltipReputation, - props: { + propsFunc: () => ({ characterRep: characterRep.value, - // character, dataRep, - // paragon, - // reputation, - }, + }), }} >
diff --git a/apps/frontend/user-home/components/reputations/get-renown-data.ts b/apps/frontend/user-home/components/reputations/get-renown-data.ts index a37155493..92a69730d 100644 --- a/apps/frontend/user-home/components/reputations/get-renown-data.ts +++ b/apps/frontend/user-home/components/reputations/get-renown-data.ts @@ -50,7 +50,7 @@ export function getRenownData({ ret.dataRep = wowthingData.static.reputationById.get(ret.characterRep.reputationId); const actualCharacter = ret.dataRep.accountWide - ? userState.general.characterById[userState.reputations[ret.dataRep.id]?.[1]] + ? userState.general.characterById[userState.reputations[ret.dataRep.id]?.characterId] : character; ret.characterRep = diff --git a/apps/frontend/user-home/state/user/derived.svelte.ts b/apps/frontend/user-home/state/user/derived.svelte.ts index 6340938cc..6685f7b87 100644 --- a/apps/frontend/user-home/state/user/derived.svelte.ts +++ b/apps/frontend/user-home/state/user/derived.svelte.ts @@ -297,22 +297,44 @@ export class DataUserDerived { public doReputations(allCharacters: Character[]) { console.time('doReputations'); - const maxReps: Record = {}; + const maxReps: Record< + number, + { value: number; characterId: number; characterScanned: number } + > = {}; const hasParagons = new Set(); for (const character of allCharacters) { for (const expansion of Object.values(character.reputationData)) { for (const reputationSet of expansion.sets) { for (const { reputationId, value } of reputationSet) { - const maxRep = maxReps[reputationId]?.[0] || -99999; + const currentMax = maxReps[reputationId]; + if ( + currentMax && + character.lastSeenAddonUnix < currentMax.characterScanned + ) { + continue; + } + + const maxRep = currentMax?.value || -99999; + let setMax = false; if (value > maxRep) { - maxReps[reputationId] = [value, character.id]; + if (!currentMax || character.lastSeenAddonUnix) { + setMax = true; + } } else if ( value === maxRep && !hasParagons.has(reputationId) && character.paragons?.[reputationId] ) { hasParagons.add(reputationId); - maxReps[reputationId] = [value, character.id]; + setMax = true; + } + + if (setMax) { + maxReps[reputationId] = { + value, + characterId: character.id, + characterScanned: character.lastSeenAddonUnix, + }; } } } @@ -523,6 +545,23 @@ export class DataUserDerived { const choreReset = chore.questReset || parent?.questReset; const resetForced = chore.questResetForced === true || parent?.questResetForced === true; + let expiresAt: DateTime; + if (choreReset === DbResetType.Weekly) { + expiresAt = getNextWeeklyResetFromTime( + charScanned, + character.realm?.region || Region.US, + character + ); + } else if (choreReset === DbResetType.Never) { + expiresAt = timeState.slowTime.plus({ days: 30 }); + } else { + expiresAt = getNextDailyResetFromTime( + charScanned, + character.realm?.region || Region.US, + character + ); + } + let completedCount = 0; let questIds: number[] = []; if (chore.questIds) { @@ -531,23 +570,8 @@ export class DataUserDerived { ? chore.questIds(character, chore) : chore.questIds; - let expiresAt: DateTime; - if (choreReset === DbResetType.Weekly) { - expiresAt = getNextWeeklyResetFromTime( - charScanned, - character.realm?.region || Region.US, - character - ); - } else if (choreReset === DbResetType.Custom) { + if (choreReset === DbResetType.Custom) { expiresAt = chore.customExpiryFunc(character, charScanned, questIds); - } else if (choreReset === DbResetType.Never) { - expiresAt = timeState.slowTime.plus({ days: 30 }); - } else { - expiresAt = getNextDailyResetFromTime( - charScanned, - character.realm?.region || Region.US, - character - ); } for (const questId of questIds) { @@ -649,7 +673,10 @@ export class DataUserDerived { } } else if (chore.progressFunc) { const { have, need } = chore.progressFunc(character); - charChore.progressCurrent = have; + + if (!resetForced || expiresAt > timeState.slowTime) { + charChore.progressCurrent = have; + } charChore.progressTotal = need; if (charChore.progressCurrent === charChore.progressTotal) { diff --git a/apps/frontend/utils/mythic-plus/get-vault-item-level.ts b/apps/frontend/utils/mythic-plus/get-vault-item-level.ts index 91993d9b2..d0377b27d 100644 --- a/apps/frontend/utils/mythic-plus/get-vault-item-level.ts +++ b/apps/frontend/utils/mythic-plus/get-vault-item-level.ts @@ -1,7 +1,7 @@ -import { keyVaultItemLevel } from '@/data/vault'; +import { dungeonVaultItemLevel } from '@/data/vault'; export function getVaultItemLevel(keyLevel: number): number[] { - for (const [tierKeyLevel, tierItemLevel, tierQuality] of keyVaultItemLevel) { + for (const [tierKeyLevel, tierItemLevel, tierQuality] of dungeonVaultItemLevel) { if (keyLevel >= tierKeyLevel) { return [tierItemLevel, tierQuality]; } diff --git a/apps/frontend/utils/mythic-plus/get-vault-quality-by-item-level.ts b/apps/frontend/utils/mythic-plus/get-vault-quality-by-item-level.ts index 7fab39311..d942e4d4a 100644 --- a/apps/frontend/utils/mythic-plus/get-vault-quality-by-item-level.ts +++ b/apps/frontend/utils/mythic-plus/get-vault-quality-by-item-level.ts @@ -1,7 +1,7 @@ -import { keyVaultItemLevel } from '@/data/vault'; +import { dungeonVaultItemLevel } from '@/data/vault'; export function getVaultQualityByItemLevel(itemLevel: number) { - for (const [, tierItemLevel, tierQuality] of keyVaultItemLevel) { + for (const [, tierItemLevel, tierQuality] of dungeonVaultItemLevel) { if (itemLevel >= tierItemLevel) { return tierQuality; }