utils: update grid helpers and modification utilities
This commit is contained in:
parent
8bfa31d925
commit
c0dc3d0bc1
3 changed files with 123 additions and 62 deletions
|
|
@ -19,7 +19,7 @@ export interface SlotRange {
|
||||||
const GRID_CONFIGS: Record<GridType, SlotRange> = {
|
const GRID_CONFIGS: Record<GridType, SlotRange> = {
|
||||||
[GridType.Weapon]: { start: 0, end: 8, specialSlots: [-1] }, // mainhand + 9 grid slots
|
[GridType.Weapon]: { start: 0, end: 8, specialSlots: [-1] }, // mainhand + 9 grid slots
|
||||||
[GridType.Summon]: { start: 0, end: 5, specialSlots: [-1, 6] }, // main + 6 grid + friend
|
[GridType.Summon]: { start: 0, end: 5, specialSlots: [-1, 6] }, // main + 6 grid + friend
|
||||||
[GridType.Character]: { start: 1, end: 4, specialSlots: [] } // 4 slots (1-4), position 0 is protagonist (not user-selectable)
|
[GridType.Character]: { start: 0, end: 4, specialSlots: [] } // 5 character slots (0-4)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -94,3 +94,55 @@ export function hasAnyModification(
|
||||||
): boolean {
|
): boolean {
|
||||||
return detectModifications(type, item).hasModifications
|
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
|
||||||
|
*/
|
||||||
|
export function canWeaponBeModified(gridWeapon: GridWeapon | undefined): boolean {
|
||||||
|
if (!gridWeapon?.weapon) return false
|
||||||
|
|
||||||
|
const weapon = gridWeapon.weapon
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// AX skills
|
||||||
|
const hasAxSkills = weapon.ax === true
|
||||||
|
|
||||||
|
// Awakening (maxAwakeningLevel > 0 means it can have awakening)
|
||||||
|
const hasAwakening = (weapon.maxAwakeningLevel ?? 0) > 0
|
||||||
|
|
||||||
|
return canChangeElement || hasWeaponKeys || hasAxSkills || hasAwakening
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a character CAN be modified (has modifiable properties)
|
||||||
|
* This is different from hasModifications which checks if it HAS been modified
|
||||||
|
*/
|
||||||
|
export function canCharacterBeModified(gridCharacter: GridCharacter | undefined): boolean {
|
||||||
|
if (!gridCharacter?.character) return false
|
||||||
|
|
||||||
|
const character = gridCharacter.character
|
||||||
|
|
||||||
|
// Awakening (maxAwakeningLevel > 0 means it can have awakening)
|
||||||
|
const hasAwakening = (character.maxAwakeningLevel ?? 0) > 0
|
||||||
|
|
||||||
|
// All characters can have rings (Over Mastery)
|
||||||
|
const canHaveRings = true
|
||||||
|
|
||||||
|
// All characters can have earrings (Aetherial Mastery)
|
||||||
|
const canHaveEarring = true
|
||||||
|
|
||||||
|
// Perpetuity is only for non-MC characters (position > 0)
|
||||||
|
const canHavePerpetuity = gridCharacter.position > 0
|
||||||
|
|
||||||
|
return hasAwakening || canHaveRings || canHaveEarring || canHavePerpetuity
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,93 +2,102 @@ import type { SimpleAxSkill } from '$lib/types/api/entities'
|
||||||
import { getRingStat, getEarringStat, getElementalizedEarringStat } from './masteryUtils'
|
import { getRingStat, getEarringStat, getElementalizedEarringStat } from './masteryUtils'
|
||||||
|
|
||||||
const AX_SKILL_NAMES: Record<number, string> = {
|
const AX_SKILL_NAMES: Record<number, string> = {
|
||||||
1: 'Attack',
|
1: 'Attack',
|
||||||
2: 'HP',
|
2: 'HP',
|
||||||
3: 'Double Attack',
|
3: 'Double Attack',
|
||||||
4: 'Triple Attack',
|
4: 'Triple Attack',
|
||||||
5: 'C.A. DMG',
|
5: 'C.A. DMG',
|
||||||
6: 'C.A. DMG Cap',
|
6: 'C.A. DMG Cap',
|
||||||
7: 'Skill DMG',
|
7: 'Skill DMG',
|
||||||
8: 'Skill DMG Cap',
|
8: 'Skill DMG Cap',
|
||||||
9: 'Stamina',
|
9: 'Stamina',
|
||||||
10: 'Enmity',
|
10: 'Enmity',
|
||||||
11: 'Critical Hit'
|
11: 'Critical Hit'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatRingStat(
|
export function formatRingStat(
|
||||||
modifier: number,
|
modifier: number,
|
||||||
strength: number,
|
strength: number,
|
||||||
locale: 'en' | 'ja' = 'en'
|
locale: 'en' | 'ja' = 'en'
|
||||||
): string {
|
): string {
|
||||||
const stat = getRingStat(modifier)
|
const stat = getRingStat(modifier)
|
||||||
if (!stat) return `Unknown +${strength}`
|
if (!stat) return `Unknown +${strength}`
|
||||||
|
|
||||||
const statName = stat.name[locale]
|
const statName = stat.name[locale]
|
||||||
return `${statName} +${strength}${stat.suffix}`
|
return `${statName} +${strength}${stat.suffix}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatEarringStat(
|
export function formatEarringStat(
|
||||||
modifier: number,
|
modifier: number,
|
||||||
strength: number,
|
strength: number,
|
||||||
locale: 'en' | 'ja' = 'en',
|
locale: 'en' | 'ja' = 'en',
|
||||||
characterElement?: number
|
characterElement?: number
|
||||||
): string {
|
): string {
|
||||||
// Use elementalized version if element is provided and it's an element-specific stat
|
// Use elementalized version if element is provided and it's an element-specific stat
|
||||||
const stat = characterElement !== undefined && (modifier === 3 || modifier === 4)
|
const stat =
|
||||||
? getElementalizedEarringStat(modifier, characterElement, locale)
|
characterElement !== undefined && (modifier === 3 || modifier === 4)
|
||||||
: getEarringStat(modifier)
|
? getElementalizedEarringStat(modifier, characterElement, locale)
|
||||||
|
: getEarringStat(modifier)
|
||||||
|
|
||||||
if (!stat) return `Unknown +${strength}`
|
if (!stat) return `Unknown +${strength}`
|
||||||
|
|
||||||
const statName = stat.name[locale]
|
const statName = stat.name[locale]
|
||||||
return `${statName} +${strength}${stat.suffix}`
|
return `${statName} +${strength}${stat.suffix}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatAxSkill(ax: SimpleAxSkill): string {
|
export function formatAxSkill(ax: SimpleAxSkill): string {
|
||||||
const skillName = AX_SKILL_NAMES[ax.modifier] || `Unknown (${ax.modifier})`
|
const skillName = AX_SKILL_NAMES[ax.modifier] || `Unknown (${ax.modifier})`
|
||||||
const suffix = ax.modifier <= 2 ? '' : '%'
|
const suffix = ax.modifier <= 2 ? '' : '%'
|
||||||
return `${skillName} +${ax.strength}${suffix}`
|
return `${skillName} +${ax.strength}${suffix}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeaponKeyTitle(series?: number): string {
|
export function getWeaponKeyTitle(series?: number): string {
|
||||||
switch (series) {
|
switch (series) {
|
||||||
case 2:
|
case 2:
|
||||||
return 'Opus Pendulums'
|
return 'Pendulums & Chains'
|
||||||
case 3:
|
case 3:
|
||||||
case 34:
|
case 34:
|
||||||
return 'Draconic Telumas'
|
return 'Telumas'
|
||||||
case 17:
|
case 17:
|
||||||
return 'Ultima Keys'
|
return 'Ultima Keys'
|
||||||
case 22:
|
case 22:
|
||||||
return 'Revans Emblems'
|
return 'Emblems'
|
||||||
default:
|
default:
|
||||||
return 'Weapon Keys'
|
return 'Weapon Keys'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatUncapLevel(level?: number | null): string {
|
export function formatUncapLevel(level?: number | null): string {
|
||||||
if (level === undefined || level === null) return '0★'
|
if (level === undefined || level === null) return '0★'
|
||||||
return `${level}★`
|
return `${level}★`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatTranscendenceStep(step?: number | null): string {
|
export function formatTranscendenceStep(step?: number | null): string {
|
||||||
if (!step || step === 0) return ''
|
if (!step || step === 0) return ''
|
||||||
return `Stage ${step}`
|
return `Stage ${step}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatModifierIcon(type: 'ring' | 'earring', modifier: number): string | null {
|
export function getStatModifierIcon(type: 'ring' | 'earring', modifier: number): string | null {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getElementName(element?: number | null): string {
|
export function getElementName(element?: number | null): string {
|
||||||
switch (element) {
|
switch (element) {
|
||||||
case 0: return 'Null'
|
case 0:
|
||||||
case 1: return 'Wind'
|
return 'Null'
|
||||||
case 2: return 'Fire'
|
case 1:
|
||||||
case 3: return 'Water'
|
return 'Wind'
|
||||||
case 4: return 'Earth'
|
case 2:
|
||||||
case 5: return 'Dark'
|
return 'Fire'
|
||||||
case 6: return 'Light'
|
case 3:
|
||||||
default: return 'Unknown'
|
return 'Water'
|
||||||
}
|
case 4:
|
||||||
|
return 'Earth'
|
||||||
|
case 5:
|
||||||
|
return 'Dark'
|
||||||
|
case 6:
|
||||||
|
return 'Light'
|
||||||
|
default:
|
||||||
|
return 'Unknown'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue