remove legacy integer series fallbacks from utils

This commit is contained in:
Justin Edmund 2025-12-03 11:59:02 -08:00
parent a8d97479ff
commit 745c162529
4 changed files with 132 additions and 88 deletions

View file

@ -1,4 +1,5 @@
import type { GridCharacter, GridWeapon, GridSummon } from '$lib/types/api/party'
import { seriesHasWeaponKeys } from '$lib/utils/weaponSeries'
export interface ModificationStatus {
hasModifications: boolean
@ -95,10 +96,6 @@ export function hasAnyModification(
return detectModifications(type, item).hasModifications
}
// Weapon series that support weapon keys
// 2 = Dark Opus, 3 = Draconic, 17 = Ultima, 24 = Astral, 34 = Superlative
const WEAPON_KEY_SERIES = [2, 3, 17, 24, 34]
/**
* Check if a weapon CAN be modified (has modifiable properties)
* This is different from hasModifications which checks if it HAS been modified
@ -111,8 +108,8 @@ export function canWeaponBeModified(gridWeapon: GridWeapon | undefined): boolean
// Element can be changed (element = 0 means "any element")
const canChangeElement = weapon.element === 0
// Weapon keys (series-specific)
const hasWeaponKeys = WEAPON_KEY_SERIES.includes(weapon.series)
// Weapon keys (series-specific) - use utility function that handles both formats
const hasWeaponKeys = seriesHasWeaponKeys(weapon.series)
// AX skills
const hasAxSkills = weapon.ax === true

View file

@ -1,5 +1,6 @@
import type { SimpleAxSkill } from '$lib/types/api/entities'
import { getRingStat, getEarringStat, getElementalizedEarringStat } from './masteryUtils'
import { isWeaponSeriesRef, type WeaponSeriesRef } from '$lib/types/api/weaponSeries'
const AX_SKILL_NAMES: Record<number, string> = {
1: 'Attack',
@ -51,16 +52,21 @@ export function formatAxSkill(ax: SimpleAxSkill): string {
return `${skillName} +${ax.strength}${suffix}`
}
export function getWeaponKeyTitle(series?: number): string {
switch (series) {
case 2:
export function getWeaponKeyTitle(series?: WeaponSeriesRef | null): string {
if (!isWeaponSeriesRef(series)) {
return 'Weapon Keys'
}
switch (series.slug) {
case 'dark-opus':
return 'Pendulums & Chains'
case 3:
case 34:
case 'draconic':
case 'draconic-providence':
case 'superlative':
return 'Telumas'
case 17:
case 'ultima':
return 'Ultima Keys'
case 22:
case 'astral':
return 'Emblems'
default:
return 'Weapon Keys'

View file

@ -4,6 +4,7 @@
import type { Awakening, WeaponKey } from '$lib/types/api/entities'
import type { SimpleAxSkill } from '$lib/types/SimpleAxSkill'
import { isWeaponSeriesRef, type WeaponSeriesRef } from '$lib/types/api/weaponSeries'
import { getBasePath } from '$lib/utils/images'
/**
@ -24,6 +25,16 @@ export function getAwakeningImage(awakening?: { type?: Awakening; level?: number
return `${getBasePath()}/awakening/${slug}.${extension}`
}
/**
* Helper to get series slug from WeaponSeriesRef
*/
function getSeriesSlug(series?: WeaponSeriesRef | null): string | undefined {
if (!isWeaponSeriesRef(series)) {
return undefined
}
return series.slug
}
/**
* Get the image URL for a weapon key with proper element/proficiency/mod variants
*/
@ -31,7 +42,7 @@ export function getWeaponKeyImage(
key: WeaponKey,
weaponElement?: number,
weaponProficiency?: number,
weaponSeries?: number,
weaponSeries?: WeaponSeriesRef | null,
weaponName?: { en?: string }
): string {
if (!key.slug) return ''
@ -39,21 +50,24 @@ export function getWeaponKeyImage(
const baseUrl = `${getBasePath()}/weapon-keys/`
let filename = key.slug
// Get series slug for comparison
const seriesSlug = getSeriesSlug(weaponSeries)
// Handle element-specific telumas (Draconic weapons)
const elementalTelumas = [15008, 16001, 16002]
const granblueId = parseInt(key.granblue_id || '0')
const granblueId = key.granblue_id ?? 0
if (elementalTelumas.includes(granblueId) && weaponElement) {
filename += `-${weaponElement}`
}
// Handle proficiency-specific ultima keys (slot 0)
if (key.slot === 0 && weaponSeries === 17 && weaponProficiency) {
if (key.slot === 0 && seriesSlug === 'ultima' && weaponProficiency) {
filename += `-${weaponProficiency}`
}
// Handle element-specific opus pendulums (slot 1)
if (weaponSeries === 2 && key.slot === 1 && weaponElement) {
if (seriesSlug === 'dark-opus' && key.slot === 1 && weaponElement) {
const mod = weaponName?.en?.includes('Repudiation') ? 'primal' : 'magna'
const suffixes = [
'pendulum-strength',
@ -78,16 +92,19 @@ export function getWeaponKeyImage(
export function getWeaponKeyImages(
keys?: WeaponKey[],
weaponElement?: number,
weaponProficiency?: number,
weaponSeries?: number,
weaponProficiency?: number | number[],
weaponSeries?: WeaponSeriesRef | null,
weaponName?: { en?: string }
): Array<{ url: string; alt: string }> {
if (!keys || keys.length === 0) return []
// Handle proficiency being an array (take first element)
const proficiency = Array.isArray(weaponProficiency) ? weaponProficiency[0] : weaponProficiency
return keys
.filter(key => key.slug)
.map(key => ({
url: getWeaponKeyImage(key, weaponElement, weaponProficiency, weaponSeries, weaponName),
url: getWeaponKeyImage(key, weaponElement, proficiency, weaponSeries, weaponName),
alt: key.name?.en || key.slug || 'Weapon Key'
}))
}

View file

@ -2,90 +2,114 @@
* Weapon Series Utilities
*
* Provides helpers for weapon series identification and conflict messaging.
* Works with the API-driven WeaponSeriesRef type.
*
* @module utils/weaponSeries
*/
export interface WeaponSeries {
id: number
slug: string
}
import type { WeaponSeriesRef } from '$lib/types/api/weaponSeries'
import { isWeaponSeriesRef } from '$lib/types/api/weaponSeries'
/**
* All weapon series with their IDs and slugs.
* The slug is used for i18n message keys.
*/
export const weaponSeries: WeaponSeries[] = [
{ id: 0, slug: 'seraphic' },
{ id: 1, slug: 'grand' },
{ id: 2, slug: 'opus' },
{ id: 3, slug: 'draconic' },
{ id: 4, slug: 'revenant' },
{ id: 6, slug: 'primal' },
{ id: 7, slug: 'beast' },
{ id: 8, slug: 'regalia' },
{ id: 9, slug: 'omega' },
{ id: 10, slug: 'olden_primal' },
{ id: 11, slug: 'militis' },
{ id: 12, slug: 'hollowsky' },
{ id: 13, slug: 'xeno' },
{ id: 14, slug: 'astral' },
{ id: 15, slug: 'rose' },
{ id: 16, slug: 'bahamut' },
{ id: 17, slug: 'ultima' },
{ id: 18, slug: 'epic' },
{ id: 19, slug: 'ennead' },
{ id: 20, slug: 'cosmic' },
{ id: 21, slug: 'ancestral' },
{ id: 22, slug: 'superlative' },
{ id: 23, slug: 'vintage' },
{ id: 24, slug: 'class_champion' },
{ id: 25, slug: 'proving' },
{ id: 28, slug: 'sephira' },
{ id: 29, slug: 'new_world' },
{ id: 30, slug: 'disaster' },
{ id: 31, slug: 'illustrious' },
{ id: 32, slug: 'world' },
{ id: 34, slug: 'draconic_providence' }
]
/**
* Series IDs that share the Opus/Draconic conflict rule.
* Slugs for series that share the Opus/Draconic conflict rule.
* Only one weapon from these series can be in a party at a time.
*/
export const OPUS_DRACONIC_SERIES = [2, 3, 34]
export const OPUS_DRACONIC_SLUGS = ['dark-opus', 'draconic', 'draconic-providence']
/**
* Get the slug for a weapon series by ID.
* Check if a series belongs to the Opus/Draconic conflict group.
*
* @param id - The series ID
* @returns The series slug or undefined if not found
*/
export function getWeaponSeriesSlug(id: number): string | undefined {
return weaponSeries.find((s) => s.id === id)?.slug
}
/**
* Check if a series ID belongs to the Opus/Draconic conflict group.
*
* @param seriesId - The series ID to check
* @param series - The series to check (WeaponSeriesRef or null)
* @returns True if the series is Opus, Draconic, or Draconic Providence
*/
export function isOpusDraconicSeries(seriesId: number): boolean {
return OPUS_DRACONIC_SERIES.includes(seriesId)
export function isOpusDraconicSeries(series: WeaponSeriesRef | null | undefined): boolean {
if (!isWeaponSeriesRef(series)) {
return false
}
return OPUS_DRACONIC_SLUGS.includes(series.slug)
}
/**
* Get all weapon series as options for a select/dropdown.
* Get the display name for a weapon series.
*
* @returns Array of { value, label } options
* @param series - The weapon series reference
* @param locale - The locale to use ('en' or 'ja')
* @returns The localized series name, or 'Unknown' if not available
*/
export function getWeaponSeriesOptions() {
return weaponSeries.map((series) => ({
value: series.id,
label: series.slug
.split('_')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
}))
export function getSeriesDisplayName(
series: WeaponSeriesRef | null | undefined,
locale: 'en' | 'ja' = 'en'
): string {
if (!isWeaponSeriesRef(series)) {
return 'Unknown'
}
return series.name[locale] || series.name.en || 'Unknown'
}
/**
* Get the slug for a weapon series.
*
* @param series - The weapon series
* @returns The series slug or undefined
*/
export function getSeriesSlug(series: WeaponSeriesRef | null | undefined): string | undefined {
if (!isWeaponSeriesRef(series)) {
return undefined
}
return series.slug
}
/**
* Check if a weapon series supports weapon keys.
*
* @param series - The weapon series
* @returns True if the series supports weapon keys
*/
export function seriesHasWeaponKeys(series: WeaponSeriesRef | null | undefined): boolean {
if (!isWeaponSeriesRef(series)) {
return false
}
return series.hasWeaponKeys
}
/**
* Check if a weapon series supports awakening.
*
* @param series - The weapon series
* @returns True if the series supports awakening
*/
export function seriesHasAwakening(series: WeaponSeriesRef | null | undefined): boolean {
if (!isWeaponSeriesRef(series)) {
return false
}
return series.hasAwakening
}
/**
* Check if a weapon series allows element changes.
*
* @param series - The weapon series
* @returns True if weapons in this series can have their element changed
*/
export function seriesIsElementChangeable(series: WeaponSeriesRef | null | undefined): boolean {
if (!isWeaponSeriesRef(series)) {
return false
}
return series.elementChangeable
}
/**
* Check if a weapon series can be placed in extra grid slots.
*
* @param series - The weapon series
* @returns True if weapons in this series can be in extra slots
*/
export function seriesIsExtra(series: WeaponSeriesRef | null | undefined): boolean {
if (!isWeaponSeriesRef(series)) {
return false
}
return series.extra
}
// Re-export the type guard for convenience
export { isWeaponSeriesRef } from '$lib/types/api/weaponSeries'