update utility functions

This commit is contained in:
Justin Edmund 2025-09-29 23:47:11 -07:00
parent cf34092ccc
commit a00b8a8d18
5 changed files with 149 additions and 130 deletions

View file

@ -1,3 +1,20 @@
interface ElementData {
en: string
ja: string
opposite_id: number
}
export const ELEMENTS: Record<number, ElementData> = {
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<number, string> = {
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
}

View file

@ -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
}
return detectModifications(type, item).hasModifications
}

View file

@ -1,43 +1,5 @@
import type { SimpleAxSkill } from '$lib/types/api/entities'
const RING_STAT_NAMES: Record<number, string> = {
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<number, string> = {
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<number, string> = {
1: 'Attack',
@ -53,16 +15,33 @@ const AX_SKILL_NAMES: Record<number, string> = {
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 {

View file

@ -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}`
}
/**

View file

@ -2,8 +2,8 @@ export const PROFICIENCY_LABELS: Record<number, string> = {
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
}))
}
}