From cc126e25bb8693862f2149f83ba0945d34199f26 Mon Sep 17 00:00:00 2001 From: Freddie Date: Sun, 22 Mar 2026 12:15:22 -0700 Subject: [PATCH 1/4] Icon scaling fun --- .../home/table/head/HomeTableHeadTasks.svelte | 3 ++- apps/frontend/data/tasks/11-midnight/prey.ts | 8 ++++---- .../components/images/IconifyWrapper.svelte | 19 +++++++++++-------- apps/frontend/shared/icons/library.ts | 6 ++++++ apps/frontend/shared/icons/scale.ts | 6 ++++++ apps/frontend/types/icons.ts | 1 - 6 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 apps/frontend/shared/icons/scale.ts diff --git a/apps/frontend/components/home/table/head/HomeTableHeadTasks.svelte b/apps/frontend/components/home/table/head/HomeTableHeadTasks.svelte index 00ce731d0..352c75263 100644 --- a/apps/frontend/components/home/table/head/HomeTableHeadTasks.svelte +++ b/apps/frontend/components/home/table/head/HomeTableHeadTasks.svelte @@ -48,6 +48,7 @@ setSortState(fullTaskName)} use:componentTooltip={{ component: Tooltip, @@ -60,7 +61,7 @@ > {#if chore} {#if chore.icon} - + {/if} {:else} diff --git a/apps/frontend/data/tasks/11-midnight/prey.ts b/apps/frontend/data/tasks/11-midnight/prey.ts index 76d21f85d..fff8bad81 100644 --- a/apps/frontend/data/tasks/11-midnight/prey.ts +++ b/apps/frontend/data/tasks/11-midnight/prey.ts @@ -40,7 +40,7 @@ export const midPrey: Task = { { key: 'preyNormal', name: 'Normal - {item:257023}', - icon: iconLibrary.notoClownFace, + icon: iconLibrary.mdiDog, alwaysStarted: true, questCount: 2, questReset: DbResetType.Weekly, @@ -53,7 +53,7 @@ export const midPrey: Task = { { key: 'preyHard', name: 'Hard - {item:257026}', - icon: iconLibrary.notoCowboyHatFace, + icon: iconLibrary.gameBearFace, minimumLevel: 90, alwaysStarted: true, questCount: 2, @@ -68,7 +68,7 @@ export const midPrey: Task = { { key: 'preyNightmare', name: 'Nightmare - {item:262346}', - icon: iconLibrary.notoAngryFaceWithHorns, + icon: iconLibrary.gameCrownedSkull, minimumLevel: 90, alwaysStarted: true, questCount: 2, @@ -83,7 +83,7 @@ export const midPrey: Task = { { key: 'preyNightmarishTask', name: 'A Nightmarish Task', - icon: iconLibrary.notoV1AngryFaceWithHorns, + icon: iconLibrary.fluentAngryFaceWithHorns, minimumLevel: 90, questReset: DbResetType.Weekly, questIds: [94446], diff --git a/apps/frontend/shared/components/images/IconifyWrapper.svelte b/apps/frontend/shared/components/images/IconifyWrapper.svelte index cc576d648..871dfb8ba 100644 --- a/apps/frontend/shared/components/images/IconifyWrapper.svelte +++ b/apps/frontend/shared/components/images/IconifyWrapper.svelte @@ -1,17 +1,26 @@ diff --git a/apps/frontend/shared/icons/library.ts b/apps/frontend/shared/icons/library.ts index 729e20a95..0d6c0a9df 100644 --- a/apps/frontend/shared/icons/library.ts +++ b/apps/frontend/shared/icons/library.ts @@ -6,8 +6,11 @@ export { default as emojiZzz } from '~icons/emojione-monotone/zzz'; export { default as faDungeon } from '~icons/fa-solid/dungeon'; +export { default as fluentAngryFaceWithHorns } from '~icons/fluent-emoji-high-contrast/angry-face-with-horns'; + export { default as gameAnimalHide } from '~icons/game-icons/animal-hide'; export { default as gameAnvil } from '~icons/game-icons/anvil'; +export { default as gameBabyFace } from '~icons/game-icons/baby-face'; export { default as gameBackpack } from '~icons/game-icons/backpack'; export { default as gameBarbecue } from '~icons/game-icons/barbecue'; export { default as gameBarbute } from '~icons/game-icons/barbute'; @@ -17,6 +20,7 @@ export { default as gameBeamsAura } from '~icons/game-icons/beams-aura'; export { default as gameBearFace } from '~icons/game-icons/bear-face'; export { default as gameBeltArmor } from '~icons/game-icons/belt-armor'; export { default as gameBigDiamondRing } from '~icons/game-icons/big-diamond-ring'; +export { default as gameBladeBite } from '~icons/game-icons/blade-bite'; export { default as gameBlunderbuss } from '~icons/game-icons/blunderbuss'; export { default as gameBracer } from '~icons/game-icons/bracer'; export { default as gameBrassKnuckles } from '~icons/game-icons/brass-knuckles'; @@ -53,6 +57,7 @@ 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 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'; export { default as gameMetalBoot } from '~icons/game-icons/metal-boot'; export { default as gameNightSky } from '~icons/game-icons/night-sky'; @@ -124,6 +129,7 @@ export { default as mdiCloud } from '~icons/mdi/cloud'; export { default as mdiCogOutline } from '~icons/mdi/cog-outline'; export { default as mdiCurrencyUsd } from '~icons/mdi/currency-usd'; export { default as mdiDiceMultiple } from '~icons/mdi/dice-multiple'; +export { default as mdiDog } from '~icons/mdi/dog'; export { default as mdiDuck } from '~icons/mdi/duck'; export { default as mdiEmoticonDevilOutline } from '~icons/mdi/emoticon-devil-outline'; export { default as mdiExclamationThick } from '~icons/mdi/exclamation-thick'; diff --git a/apps/frontend/shared/icons/scale.ts b/apps/frontend/shared/icons/scale.ts new file mode 100644 index 000000000..dec552fc3 --- /dev/null +++ b/apps/frontend/shared/icons/scale.ts @@ -0,0 +1,6 @@ +// icon path => scale value +export const iconScale: Record = { + '~icons/mdi/dog.svelte': '1.4', + '~icons/game-icons/bear-face.svelte': '1.2', + '~icons/game-icons/crowned-skull.svelte': '1.2', +}; diff --git a/apps/frontend/types/icons.ts b/apps/frontend/types/icons.ts index 886083511..dcb6081b5 100644 --- a/apps/frontend/types/icons.ts +++ b/apps/frontend/types/icons.ts @@ -1,4 +1,3 @@ -import type { IconifyIcon } from '@iconify/types'; import type { Component } from 'svelte'; import type { SvelteHTMLElements } from 'svelte/elements'; From debb59d14a6f1b297f7451511522cff558255666 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 23 Mar 2026 08:38:41 -0700 Subject: [PATCH 2/4] Add vault activities storage/processing and display it in world tooltips --- .../Helpers/UserUploadCharacterProcessor.cs | 40 ++++++++++++- .../backend/Models/Uploads/UploadCharacter.cs | 3 + .../Models/Uploads/UploadCharacterVault.cs | 6 ++ .../vault-world/TooltipVaultWorld.svelte | 60 +++++++++++++------ .../frontend/types/character/weekly.svelte.ts | 29 ++++++++- .../ApiUserCharacterWeeklyConverter.cs | 24 ++++++++ .../Models/Player/PlayerCharacterWeekly.cs | 21 ++++++- 7 files changed, 160 insertions(+), 23 deletions(-) diff --git a/apps/backend/Helpers/UserUploadCharacterProcessor.cs b/apps/backend/Helpers/UserUploadCharacterProcessor.cs index 65ddab49a..f7bc3261d 100644 --- a/apps/backend/Helpers/UserUploadCharacterProcessor.cs +++ b/apps/backend/Helpers/UserUploadCharacterProcessor.cs @@ -1455,7 +1455,27 @@ private void HandleWeekly() _character.Weekly.Vault.RaidProgress = null; _character.Weekly.Vault.WorldProgress = null; - if (_characterData.Vault != null) + if (_characterData.VaultV2 != null) + { + if (_characterData.VaultV2.TryGetValue("t1", out var activityVault)) + { + _character.Weekly.Vault.MythicPlusActivities = ConvertVaultActivities(activityVault.Activities); + _character.Weekly.Vault.MythicPlusProgress = ConvertVault(activityVault.Tiers); + } + + if (_characterData.VaultV2.TryGetValue("t3", out var raidVault)) + { + _character.Weekly.Vault.RaidActivities = ConvertVaultActivities(raidVault.Activities); + _character.Weekly.Vault.RaidProgress = ConvertVault(raidVault.Tiers); + } + + if (_characterData.VaultV2.TryGetValue("t6", out var worldVault)) + { + _character.Weekly.Vault.WorldActivities = ConvertVaultActivities(worldVault.Activities); + _character.Weekly.Vault.WorldProgress = ConvertVault(worldVault.Tiers); + } + } + else if (_characterData.Vault != null) { if (_characterData.Vault.TryGetValue("t1", out var activityVault)) { @@ -1508,6 +1528,24 @@ private static List ConvertVault(UploadChara return ret; } + private List ConvertVaultActivities(string[] activityStrings) + { + var ret = new List(); + + foreach (string activityString in activityStrings.EmptyIfNull()) + { + string[] parts = activityString.Split(':'); + if (parts.Length == 3 && + int.TryParse(parts[0], out int tierId) && + int.TryParse(parts[1], out int difficulty) && + int.TryParse(parts[2], out int progress)) + { + ret.Add(new PlayerCharacterWeeklyVaultActivity(tierId, difficulty, progress)); + } + } + + return ret; + } } public record struct WorldQuestReportKey(short Expansion, int ZoneId, int QuestId, short Faction, short Class); diff --git a/apps/backend/Models/Uploads/UploadCharacter.cs b/apps/backend/Models/Uploads/UploadCharacter.cs index ad3fb78f7..46d2a1451 100644 --- a/apps/backend/Models/Uploads/UploadCharacter.cs +++ b/apps/backend/Models/Uploads/UploadCharacter.cs @@ -70,6 +70,9 @@ public class UploadCharacter [JsonConverter(typeof(DefaultOnErrorConverter>))] public Dictionary Vault { get; set; } + + [JsonConverter(typeof(DefaultOnErrorConverter>))] + public Dictionary VaultV2 { get; set; } } public class UploadCharacterAchievement diff --git a/apps/backend/Models/Uploads/UploadCharacterVault.cs b/apps/backend/Models/Uploads/UploadCharacterVault.cs index 645cfa193..2fd007eff 100644 --- a/apps/backend/Models/Uploads/UploadCharacterVault.cs +++ b/apps/backend/Models/Uploads/UploadCharacterVault.cs @@ -11,3 +11,9 @@ public class UploadCharacterVault public List Rewards { get; set; } } + +public class UploadCharacterVaultV2 +{ + public string[] Activities { get; set; } + public UploadCharacterVault[] Tiers { get; set; } +} diff --git a/apps/frontend/components/tooltips/vault-world/TooltipVaultWorld.svelte b/apps/frontend/components/tooltips/vault-world/TooltipVaultWorld.svelte index a3adb5f38..3d9f90001 100644 --- a/apps/frontend/components/tooltips/vault-world/TooltipVaultWorld.svelte +++ b/apps/frontend/components/tooltips/vault-world/TooltipVaultWorld.svelte @@ -6,22 +6,22 @@ import { leftPad } from '@/utils/formatting'; import { getNextWeeklyResetFromTime } from '@/utils/get-next-reset'; import { getWorldTier } from '@/utils/vault/get-world-tier'; - import type { Character } from '@/types'; + import type { CharacterProps } from '@/types/props'; import Progress from './Progress.svelte'; import Rewards from './Rewards.svelte'; - export let character: Character; + let { character }: CharacterProps = $props(); - $: progress = character.weekly?.vault?.worldProgress || []; + let progress = $derived(character.weekly?.vault?.worldProgress || []); + + let improve = $derived.by(() => { + const ret: [string, number, number][] = []; - let improve: [string, number, number][]; - $: { const [currentItemLevel] = getWorldTier(progress[0].level); const betterOptions = worldVaultItemLevel.filter( - ([, itemLevel]) => itemLevel > currentItemLevel, + ([, itemLevel]) => itemLevel > currentItemLevel ); - improve = []; for (let i = betterOptions.length - 1; i >= 0; i--) { const [betterTier, betterItemLevel, quality] = betterOptions[i]; let tierRange = betterTier.toString(); @@ -29,30 +29,52 @@ tierRange = `${betterTier} - ${betterOptions[i - 1][0] - 1}`; } - improve.push([tierRange, betterItemLevel, quality]); - if (improve.length === 3) { + ret.push([tierRange, betterItemLevel, quality]); + if (ret.length === 3) { break; } } - } - let runs: [number, string][]; - $: { - runs = []; - if (character.weekly?.delves) { + return ret; + }); + + let runs = $derived.by(() => { + let ret: [number, string][] = []; + + if (character.weekly?.vault?.worldActivities?.length > 0) { + for (const activity of character.weekly.vault.worldActivities) { + for (let i = 0; i < activity.amount; i++) { + ret.push([ + activity.level, + activityTier[activity.tierId] || `Tier ${activity.tierId}`, + ]); + } + } + } else if (character.weekly?.delves) { const nextReset = getNextWeeklyResetFromTime( $timeStore, - character.realm.region, + character.realm.region ).toUnixInteger(); + if (Math.abs(character.weekly.delveWeek - nextReset) < 5) { - runs = sortBy(character.weekly.delves, ([level]) => leftPad(11 - level, 2, '0')); + ret = sortBy(character.weekly.delves, ([level]) => leftPad(11 - level, 2, '0')); } - for (let i = runs.length; i < progress[2].progress; i++) { - runs.push([1, 'Activities/Delves']); + for (let i = ret.length; i < progress[2].progress; i++) { + ret.push([1, 'Activities/Delves']); } } - } + + return ret; + }); + + const activityTier: Record = { + 104: 'World Activity', + 105: 'Delve', + 112: 'Normal Prey', + 115: 'Hard Prey', + 116: 'Nightmare Prey', + }; function getRunCount(index: number): number { if (progress[index]) { diff --git a/apps/frontend/types/character/weekly.svelte.ts b/apps/frontend/types/character/weekly.svelte.ts index 1b3e4990d..88d0ab958 100644 --- a/apps/frontend/types/character/weekly.svelte.ts +++ b/apps/frontend/types/character/weekly.svelte.ts @@ -31,7 +31,10 @@ export class CharacterWeekly { vaultGeneratedRewards?: boolean, dungeonProgress?: CharacterWeeklyProgressArray[], raidProgress?: CharacterWeeklyProgressArray[], - worldProgress?: CharacterWeeklyProgressArray[] + worldProgress?: CharacterWeeklyProgressArray[], + dungeonActivities?: CharacterWeeklyActivitiesArray[], + raidActivities?: CharacterWeeklyActivitiesArray[], + worldActivities?: CharacterWeeklyActivitiesArray[] ) { this.delveWeek = delveWeek; this.delveGilded = delveGilded; @@ -48,6 +51,7 @@ export class CharacterWeekly { this.vaultScannedAt = vaultScannedAt; this.vault.availableRewards = vaultAvailableRewards; this.vault.generatedRewards = vaultGeneratedRewards; + this.vault.dungeonProgress = (dungeonProgress || []).map( (array) => new CharacterWeeklyProgress(...array) ); @@ -57,6 +61,17 @@ export class CharacterWeekly { this.vault.worldProgress = (worldProgress || []).map( (array) => new CharacterWeeklyProgress(...array) ); + + this.vault.dungeonActivities = (dungeonActivities || []).map( + (array) => new CharacterWeeklyActivities(...array) + ); + this.vault.raidActivities = (raidActivities || []).map( + (array) => new CharacterWeeklyActivities(...array) + ); + this.vault.worldActivities = (worldActivities || []).map( + (array) => new CharacterWeeklyActivities(...array) + ); + this.vault.anyThreshold = [ ...this.vault.dungeonProgress, ...this.vault.raidProgress, @@ -76,6 +91,9 @@ export interface CharacterWeeklyVault { dungeonProgress: CharacterWeeklyProgress[]; raidProgress: CharacterWeeklyProgress[]; worldProgress: CharacterWeeklyProgress[]; + dungeonActivities: CharacterWeeklyActivities[]; + raidActivities: CharacterWeeklyActivities[]; + worldActivities: CharacterWeeklyActivities[]; } export class CharacterWeeklyProgress { @@ -96,3 +114,12 @@ export class CharacterWeeklyProgress { } } type CharacterWeeklyProgressArray = ConstructorParameters; + +export class CharacterWeeklyActivities { + constructor( + public tierId: number, + public level: number, + public amount: number + ) {} +} +type CharacterWeeklyActivitiesArray = ConstructorParameters; diff --git a/apps/web/Converters/ApiUserCharacterWeeklyConverter.cs b/apps/web/Converters/ApiUserCharacterWeeklyConverter.cs index 75f8956e1..d1e1e562d 100644 --- a/apps/web/Converters/ApiUserCharacterWeeklyConverter.cs +++ b/apps/web/Converters/ApiUserCharacterWeeklyConverter.cs @@ -33,6 +33,10 @@ public override void Write(Utf8JsonWriter writer, ApiUserCharacterWeekly weekly, WriteVaultProgress(writer, weekly.Vault.MythicPlusProgress, options); WriteVaultProgress(writer, weekly.Vault.RaidProgress, options); WriteVaultProgress(writer, weekly.Vault.WorldProgress, options); + + WriteVaultActivities(writer, weekly.Vault.MythicPlusActivities, options); + WriteVaultActivities(writer, weekly.Vault.RaidActivities, options); + WriteVaultActivities(writer, weekly.Vault.WorldActivities, options); } writer.WriteEndArray(); @@ -74,4 +78,24 @@ JsonSerializerOptions options writer.WriteEndArray(); } + + private void WriteVaultActivities( + Utf8JsonWriter writer, + List activities, + JsonSerializerOptions options + ) + { + writer.WriteStartArray(); + + foreach (var activity in activities.EmptyIfNull()) + { + writer.WriteStartArray(); + writer.WriteNumberValue(activity.Id); + writer.WriteNumberValue(activity.Level); + writer.WriteNumberValue(activity.Amount); + writer.WriteEndArray(); + } + + writer.WriteEndArray(); + } } diff --git a/packages/csharp-lib/Models/Player/PlayerCharacterWeekly.cs b/packages/csharp-lib/Models/Player/PlayerCharacterWeekly.cs index f980b8fd0..0c48de5e7 100644 --- a/packages/csharp-lib/Models/Player/PlayerCharacterWeekly.cs +++ b/packages/csharp-lib/Models/Player/PlayerCharacterWeekly.cs @@ -43,7 +43,10 @@ public class PlayerCharacterWeeklyVault public List MythicPlusProgress { get; set; } public List RaidProgress { get; set; } public List WorldProgress { get; set; } - // public List RankedPvpProgress { get; set; } + + public List MythicPlusActivities { get; set; } + public List RaidActivities { get; set; } + public List WorldActivities { get; set; } } public class PlayerCharacterWeeklyUghQuest @@ -64,5 +67,19 @@ public class PlayerCharacterWeeklyVaultProgress public int? ItemLevel { get; set; } public int? UpgradeItemLevel { get; set; } - public List Rewards { get; set; } = new(); + public List Rewards { get; set; } = []; +} + +public class PlayerCharacterWeeklyVaultActivity +{ + public PlayerCharacterWeeklyVaultActivity(int id, int level, int amount) + { + Id = id; + Level = level; + Amount = amount; + } + + public int Id { get; set; } + public int Level { get; set; } + public int Amount { get; set; } } From 2b5d2d5848836bfc31a374c25062dc72f4fb5b20 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 23 Mar 2026 08:38:52 -0700 Subject: [PATCH 3/4] Fix convertible upgrade costs --- apps/frontend/components/items/convertible/data.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/frontend/components/items/convertible/data.ts b/apps/frontend/components/items/convertible/data.ts index 869f58f39..2c1d9cdaf 100644 --- a/apps/frontend/components/items/convertible/data.ts +++ b/apps/frontend/components/items/convertible/data.ts @@ -13,7 +13,7 @@ export const modifierToTier: Record = { export const currentUpgrade1: ConvertibleCategoryUpgrade[] = [ { upgradeId: 3341, - upgradeCost: 15, + upgradeCost: 20, achievementId: 42767, // Veteran of the Dawn achievementUpgradeCost: 10, }, @@ -21,7 +21,7 @@ export const currentUpgrade1: ConvertibleCategoryUpgrade[] = [ export const currentUpgrade2: ConvertibleCategoryUpgrade[] = [ { upgradeId: 3343, - upgradeCost: 15, + upgradeCost: 20, achievementId: 42768, // Champion of the Dawn achievementUpgradeCost: 10, }, @@ -29,7 +29,7 @@ export const currentUpgrade2: ConvertibleCategoryUpgrade[] = [ export const currentUpgrade3: ConvertibleCategoryUpgrade[] = [ { upgradeId: 3345, - upgradeCost: 15, + upgradeCost: 20, achievementId: 42769, // Hero of the Dawn achievementUpgradeCost: 10, }, @@ -37,7 +37,7 @@ export const currentUpgrade3: ConvertibleCategoryUpgrade[] = [ export const currentUpgrade4: ConvertibleCategoryUpgrade[] = [ { upgradeId: 3347, - upgradeCost: 15, + upgradeCost: 20, achievementId: 42770, // Myth of the Dawn achievementUpgradeCost: 10, }, From 0086318f5eba86cb726f5d8013ec275e3394f3a9 Mon Sep 17 00:00:00 2001 From: Freddie Date: Mon, 23 Mar 2026 08:46:54 -0700 Subject: [PATCH 4/4] Fix lint issues --- apps/frontend/types/character/weekly.svelte.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/frontend/types/character/weekly.svelte.ts b/apps/frontend/types/character/weekly.svelte.ts index 88d0ab958..7be8a5a5c 100644 --- a/apps/frontend/types/character/weekly.svelte.ts +++ b/apps/frontend/types/character/weekly.svelte.ts @@ -15,6 +15,9 @@ export class CharacterWeekly { dungeonProgress: [], raidProgress: [], worldProgress: [], + dungeonActivities: [], + raidActivities: [], + worldActivities: [], }); public vaultScannedAt: string = $state(null);