diff --git a/src/lib/utils/element.ts b/src/lib/utils/element.ts index 6c81e222..3dcec7cf 100644 --- a/src/lib/utils/element.ts +++ b/src/lib/utils/element.ts @@ -1,3 +1,20 @@ +interface ElementData { + en: string + ja: string + opposite_id: number +} + +export const ELEMENTS: Record = { + 0: { en: 'Null', ja: '無', opposite_id: 0 }, + 1: { en: 'Wind', ja: '風', opposite_id: 4 }, + 2: { en: 'Fire', ja: '火', opposite_id: 3 }, + 3: { en: 'Water', ja: '水', opposite_id: 2 }, + 4: { en: 'Earth', ja: '土', opposite_id: 1 }, + 5: { en: 'Dark', ja: '闇', opposite_id: 6 }, + 6: { en: 'Light', ja: '光', opposite_id: 5 } +} + +// Legacy support - still used in many places export const ELEMENT_LABELS: Record = { 0: 'Null', 1: 'Wind', @@ -32,4 +49,17 @@ export function getElementOptions() { value: Number(value), label })) +} + +export function getElementName(element?: number, locale: 'en' | 'ja' = 'en'): string { + if (element === undefined || element === null) return '—' + const elementData = ELEMENTS[element] + if (!elementData) return '—' + return elementData[locale] +} + +export function getOppositeElement(element?: number): number | undefined { + if (element === undefined || element === null) return undefined + const elementData = ELEMENTS[element] + return elementData?.opposite_id } \ No newline at end of file diff --git a/src/lib/utils/modificationDetector.ts b/src/lib/utils/modificationDetector.ts index e9be37c8..9a6ad3ca 100644 --- a/src/lib/utils/modificationDetector.ts +++ b/src/lib/utils/modificationDetector.ts @@ -1,98 +1,96 @@ import type { GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party' export interface ModificationStatus { - hasModifications: boolean - hasAwakening: boolean - hasWeaponKeys: boolean - hasAxSkills: boolean - hasRings: boolean - hasEarring: boolean - hasPerpetuity: boolean - hasTranscendence: boolean - hasUncapLevel: boolean - hasElement: boolean - hasQuickSummon: boolean - hasFriendSummon: boolean + hasModifications: boolean + hasAwakening: boolean + hasWeaponKeys: boolean + hasAxSkills: boolean + hasRings: boolean + hasEarring: boolean + hasPerpetuity: boolean + hasTranscendence: boolean + hasUncapLevel: boolean + hasElement: boolean + hasQuickSummon: boolean + hasFriendSummon: boolean } export function detectModifications( - type: 'character' | 'weapon' | 'summon', - item: GridCharacter | GridWeapon | GridSummon | undefined + type: 'character' | 'weapon' | 'summon', + item: GridCharacter | GridWeapon | GridSummon | undefined ): ModificationStatus { - const status: ModificationStatus = { - hasModifications: false, - hasAwakening: false, - hasWeaponKeys: false, - hasAxSkills: false, - hasRings: false, - hasEarring: false, - hasPerpetuity: false, - hasTranscendence: false, - hasUncapLevel: false, - hasElement: false, - hasQuickSummon: false, - hasFriendSummon: false - } + const status: ModificationStatus = { + hasModifications: false, + hasAwakening: false, + hasWeaponKeys: false, + hasAxSkills: false, + hasRings: false, + hasEarring: false, + hasPerpetuity: false, + hasTranscendence: false, + hasUncapLevel: false, + hasElement: false, + hasQuickSummon: false, + hasFriendSummon: false + } - if (!item) return status + if (!item) return status - if (type === 'character') { - const char = item as GridCharacter + if (type === 'character') { + const char = item as GridCharacter - status.hasAwakening = !!char.awakening - status.hasRings = !!(char.over_mastery && char.over_mastery.length > 0) - status.hasEarring = !!char.aetherial_mastery - status.hasPerpetuity = !!char.perpetuity - status.hasTranscendence = !!(char.transcendenceStep && char.transcendenceStep > 0) - status.hasUncapLevel = char.uncapLevel !== undefined && char.uncapLevel !== null + status.hasAwakening = !!char.awakening + status.hasRings = !!(char.overMastery && char.overMastery.length > 0) + status.hasEarring = !!char.aetherialMastery + status.hasPerpetuity = !!char.perpetuity + status.hasTranscendence = !!(char.transcendenceStep && char.transcendenceStep > 0) + status.hasUncapLevel = char.uncapLevel !== undefined && char.uncapLevel !== null - status.hasModifications = - status.hasAwakening || - status.hasRings || - status.hasEarring || - status.hasPerpetuity || - status.hasTranscendence || - status.hasUncapLevel + status.hasModifications = + status.hasAwakening || + status.hasRings || + status.hasEarring || + status.hasPerpetuity || + status.hasTranscendence || + status.hasUncapLevel + } else if (type === 'weapon') { + const weapon = item as GridWeapon - } else if (type === 'weapon') { - const weapon = item as GridWeapon + status.hasAwakening = !!weapon.awakening + status.hasWeaponKeys = !!(weapon.weaponKeys && weapon.weaponKeys.length > 0) + status.hasAxSkills = !!(weapon.ax && weapon.ax.length > 0) + status.hasTranscendence = !!(weapon.transcendenceStep && weapon.transcendenceStep > 0) + status.hasUncapLevel = weapon.uncapLevel !== undefined && weapon.uncapLevel !== null + status.hasElement = !!(weapon.element && weapon.weapon?.element === 0) - status.hasAwakening = !!weapon.awakening - status.hasWeaponKeys = !!(weapon.weaponKeys && weapon.weaponKeys.length > 0) - status.hasAxSkills = !!(weapon.ax && weapon.ax.length > 0) - status.hasTranscendence = !!(weapon.transcendenceStep && weapon.transcendenceStep > 0) - status.hasUncapLevel = weapon.uncapLevel !== undefined && weapon.uncapLevel !== null - status.hasElement = !!(weapon.element && weapon.weapon?.element === 0) + status.hasModifications = + status.hasAwakening || + status.hasWeaponKeys || + status.hasAxSkills || + status.hasTranscendence || + status.hasUncapLevel || + status.hasElement + } else if (type === 'summon') { + const summon = item as GridSummon - status.hasModifications = - status.hasAwakening || - status.hasWeaponKeys || - status.hasAxSkills || - status.hasTranscendence || - status.hasUncapLevel || - status.hasElement + status.hasTranscendence = !!(summon.transcendenceStep && summon.transcendenceStep > 0) + status.hasUncapLevel = summon.uncapLevel !== undefined && summon.uncapLevel !== null + status.hasQuickSummon = !!summon.quickSummon + status.hasFriendSummon = !!summon.friend - } else if (type === 'summon') { - const summon = item as GridSummon + status.hasModifications = + status.hasTranscendence || + status.hasUncapLevel || + status.hasQuickSummon || + status.hasFriendSummon + } - status.hasTranscendence = !!(summon.transcendenceStep && summon.transcendenceStep > 0) - status.hasUncapLevel = summon.uncapLevel !== undefined && summon.uncapLevel !== null - status.hasQuickSummon = !!summon.quickSummon - status.hasFriendSummon = !!summon.friend - - status.hasModifications = - status.hasTranscendence || - status.hasUncapLevel || - status.hasQuickSummon || - status.hasFriendSummon - } - - return status + return status } export function hasAnyModification( - type: 'character' | 'weapon' | 'summon', - item: GridCharacter | GridWeapon | GridSummon | undefined + type: 'character' | 'weapon' | 'summon', + item: GridCharacter | GridWeapon | GridSummon | undefined ): boolean { - return detectModifications(type, item).hasModifications -} \ No newline at end of file + return detectModifications(type, item).hasModifications +} diff --git a/src/lib/utils/modificationFormatters.ts b/src/lib/utils/modificationFormatters.ts index b1453dec..152bd8d8 100644 --- a/src/lib/utils/modificationFormatters.ts +++ b/src/lib/utils/modificationFormatters.ts @@ -1,43 +1,5 @@ import type { SimpleAxSkill } from '$lib/types/api/entities' - -const RING_STAT_NAMES: Record = { - 1: 'HP', - 2: 'Attack', - 3: 'Double Attack', - 4: 'Triple Attack', - 5: 'Elemental Attack', - 6: 'Critical Hit', - 7: 'Skill Damage', - 8: 'Skill DMG Cap', - 9: 'Ougi Damage', - 10: 'Ougi DMG Cap', - 11: 'Chain Burst DMG', - 12: 'Chain Burst Cap', - 13: 'Healing', - 14: 'Healing Cap', - 15: 'Stamina', - 16: 'Enmity', - 17: 'Debuff Success' -} - -const EARRING_STAT_NAMES: Record = { - 1: 'HP', - 2: 'Attack', - 3: 'Defense', - 4: 'Double Attack', - 5: 'Triple Attack', - 6: 'Elemental Attack', - 7: 'Critical Hit', - 8: 'Skill Damage', - 9: 'Skill DMG Cap', - 10: 'Ougi Damage', - 11: 'Ougi DMG Cap', - 12: 'Auto Attack Cap', - 13: 'Chain Burst DMG', - 14: 'Chain Burst Cap', - 15: 'Healing', - 16: 'Healing Cap' -} +import { getRingStat, getEarringStat, getElementalizedEarringStat } from './masteryUtils' const AX_SKILL_NAMES: Record = { 1: 'Attack', @@ -53,16 +15,33 @@ const AX_SKILL_NAMES: Record = { 11: 'Critical Hit' } -export function formatRingStat(modifier: number, strength: number): string { - const statName = RING_STAT_NAMES[modifier] || `Unknown (${modifier})` - const suffix = modifier <= 2 ? '' : '%' - return `${statName} +${strength}${suffix}` +export function formatRingStat( + modifier: number, + strength: number, + locale: 'en' | 'ja' = 'en' +): string { + const stat = getRingStat(modifier) + if (!stat) return `Unknown +${strength}` + + const statName = stat.name[locale] + return `${statName} +${strength}${stat.suffix}` } -export function formatEarringStat(modifier: number, strength: number): string { - const statName = EARRING_STAT_NAMES[modifier] || `Unknown (${modifier})` - const suffix = modifier <= 3 ? '' : '%' - return `${statName} +${strength}${suffix}` +export function formatEarringStat( + modifier: number, + strength: number, + locale: 'en' | 'ja' = 'en', + characterElement?: number +): string { + // Use elementalized version if element is provided and it's an element-specific stat + const stat = characterElement !== undefined && (modifier === 3 || modifier === 4) + ? getElementalizedEarringStat(modifier, characterElement, locale) + : getEarringStat(modifier) + + if (!stat) return `Unknown +${strength}` + + const statName = stat.name[locale] + return `${statName} +${strength}${stat.suffix}` } export function formatAxSkill(ax: SimpleAxSkill): string { diff --git a/src/lib/utils/modifiers.ts b/src/lib/utils/modifiers.ts index ac84234a..c1809a17 100644 --- a/src/lib/utils/modifiers.ts +++ b/src/lib/utils/modifiers.ts @@ -2,14 +2,26 @@ * Utility functions for weapon and character modifiers (awakenings, weapon keys, AX skills) */ -import type { Awakening, WeaponKey, SimpleAxSkill } from '$lib/types' +import type { Awakening } from '$lib/types/Awakening' +import type { WeaponKey } from '$lib/types/WeaponKey' +import type { SimpleAxSkill } from '$lib/types/SimpleAxSkill' /** * Get the image URL for an awakening type */ export function getAwakeningImage(awakening?: { type?: Awakening; level?: number }): string | null { if (!awakening?.type?.slug) return null - return `/images/awakening/${awakening.type.slug}.png` + + const slug = awakening.type.slug + + // No image for Balanced awakening type (character only) + if (slug === 'character-balanced') return null + + // Character awakenings are JPG, weapon awakenings are PNG + const isCharacterAwakening = slug.startsWith('character-') + const extension = isCharacterAwakening ? 'jpg' : 'png' + + return `/images/awakening/${slug}.${extension}` } /** diff --git a/src/lib/utils/proficiency.ts b/src/lib/utils/proficiency.ts index 58084cb9..1e83cc91 100644 --- a/src/lib/utils/proficiency.ts +++ b/src/lib/utils/proficiency.ts @@ -2,8 +2,8 @@ export const PROFICIENCY_LABELS: Record = { 0: 'None', 1: 'Sabre', 2: 'Dagger', - 3: 'Spear', - 4: 'Axe', + 3: 'Axe', + 4: 'Spear', 5: 'Staff', 6: 'Gun', 7: 'Melee', @@ -29,4 +29,4 @@ export function getProficiencyOptions() { value: Number(value), label })) -} \ No newline at end of file +}