diff --git a/src/lib/components/collection/CollectionWeaponPane.svelte b/src/lib/components/collection/CollectionWeaponPane.svelte index b71bf30c..59ca3b2f 100644 --- a/src/lib/components/collection/CollectionWeaponPane.svelte +++ b/src/lib/components/collection/CollectionWeaponPane.svelte @@ -10,7 +10,7 @@ */ import { onMount } from 'svelte' import type { CollectionWeapon } from '$lib/types/api/collection' - import type { AugmentSkill } from '$lib/types/api/weaponStatModifier' + import type { AugmentSkill, Befoulment } from '$lib/types/api/weaponStatModifier' import { useUpdateCollectionWeapon, useRemoveWeaponFromCollection @@ -89,7 +89,8 @@ level: weapon.awakening.level } : null, - axSkills: (weapon.ax as AugmentSkill[]) ?? [] + axSkills: (weapon.ax as AugmentSkill[]) ?? [], + befoulment: (weapon.befoulment as Befoulment) ?? null }) // Element name for theming @@ -143,15 +144,22 @@ } // AX skills - if (updates.axModifier1 !== undefined) { - input.axModifier1 = updates.axModifier1 + if (updates.axModifier1Id !== undefined) { + input.axModifier1Id = updates.axModifier1Id input.axStrength1 = updates.axStrength1 } - if (updates.axModifier2 !== undefined) { - input.axModifier2 = updates.axModifier2 + if (updates.axModifier2Id !== undefined) { + input.axModifier2Id = updates.axModifier2Id input.axStrength2 = updates.axStrength2 } + // Befoulment + if (updates.befoulmentModifierId !== undefined) { + input.befoulmentModifierId = updates.befoulmentModifierId + input.befoulmentStrength = updates.befoulmentStrength + input.exorcismLevel = updates.exorcismLevel + } + const updatedWeapon = await updateMutation.mutateAsync({ id: weapon.id, input diff --git a/src/lib/components/collection/WeaponEditPane.svelte b/src/lib/components/collection/WeaponEditPane.svelte index 3a20ee4f..0ffa714c 100644 --- a/src/lib/components/collection/WeaponEditPane.svelte +++ b/src/lib/components/collection/WeaponEditPane.svelte @@ -11,12 +11,13 @@ * - Awakening (for weapons with awakening support) */ import type { Weapon, Awakening } from '$lib/types/api/entities' - import type { AugmentSkill } from '$lib/types/api/weaponStatModifier' + import type { AugmentSkill, Befoulment } from '$lib/types/api/weaponStatModifier' import DetailsSection from '$lib/components/sidebar/details/DetailsSection.svelte' import Select from '$lib/components/ui/Select.svelte' import WeaponKeySelect from '$lib/components/sidebar/edit/WeaponKeySelect.svelte' import AwakeningSelect from '$lib/components/sidebar/edit/AwakeningSelect.svelte' import AxSkillSelect from '$lib/components/sidebar/edit/AxSkillSelect.svelte' + import BefoulmentSelect from '$lib/components/sidebar/edit/BefoulmentSelect.svelte' import UncapIndicator from '$lib/components/uncap/UncapIndicator.svelte' import { getElementIcon } from '$lib/utils/images' import { seriesHasWeaponKeys, getSeriesSlug } from '$lib/utils/weaponSeries' @@ -33,6 +34,7 @@ level: number } | null axSkills: AugmentSkill[] + befoulment?: Befoulment | null } export interface WeaponEditUpdates { @@ -51,6 +53,9 @@ axStrength1?: number axModifier2Id?: string axStrength2?: number + befoulmentModifierId?: string + befoulmentStrength?: number + exorcismLevel?: number } interface Props { @@ -74,6 +79,7 @@ let selectedAwakening = $state(currentValues.awakening?.type) let awakeningLevel = $state(currentValues.awakening?.level ?? 1) let axSkills = $state(currentValues.axSkills ?? []) + let befoulment = $state(currentValues.befoulment ?? null) // Re-initialize when currentValues changes $effect(() => { @@ -86,6 +92,7 @@ selectedAwakening = currentValues.awakening?.type awakeningLevel = currentValues.awakening?.level ?? 1 axSkills = currentValues.axSkills ?? [] + befoulment = currentValues.befoulment ?? null }) // Derived conditions @@ -106,8 +113,10 @@ const hasWeaponKeys = $derived(seriesHasWeaponKeys(series)) const keySlotCount = $derived(seriesSlug ? (WEAPON_KEY_SLOTS[seriesSlug] ?? 2) : 0) - const hasAxSkills = $derived(weaponData?.ax === true) - const axType = $derived(weaponData?.axType ?? 1) + // Augment type from series determines AX skills vs befoulment + const augmentType = $derived(series?.augmentType ?? 'none') + const hasAxSkills = $derived(augmentType === 'ax') + const hasBefoulment = $derived(augmentType === 'befoulment') const hasAwakening = $derived((weaponData?.maxAwakeningLevel ?? 0) > 0) const availableAwakenings = $derived(weaponData?.awakenings ?? []) @@ -195,6 +204,15 @@ } } + // Befoulment + if (hasBefoulment) { + if (befoulment?.modifier?.id) { + updates.befoulmentModifierId = befoulment.modifier.id + updates.befoulmentStrength = befoulment.strength + updates.exorcismLevel = befoulment.exorcismLevel + } + } + onSave?.(updates) } @@ -267,7 +285,6 @@
{ axSkills = skills @@ -277,6 +294,19 @@ {/if} + {#if hasBefoulment} + +
+ { + befoulment = bef + }} + /> +
+
+ {/if} + {#if hasAwakening && availableAwakenings.length > 0}
diff --git a/src/lib/components/sidebar/EditWeaponSidebar.svelte b/src/lib/components/sidebar/EditWeaponSidebar.svelte index 2ed840a8..08b9b351 100644 --- a/src/lib/components/sidebar/EditWeaponSidebar.svelte +++ b/src/lib/components/sidebar/EditWeaponSidebar.svelte @@ -2,13 +2,14 @@ import type { GridWeapon } from '$lib/types/api/party' import type { WeaponKey } from '$lib/api/adapters/entity.adapter' import type { Awakening } from '$lib/types/api/entities' - import type { AugmentSkill } from '$lib/types/api/weaponStatModifier' + import type { AugmentSkill, Befoulment } from '$lib/types/api/weaponStatModifier' import DetailsSection from './details/DetailsSection.svelte' import ItemHeader from './details/ItemHeader.svelte' import Select from '$lib/components/ui/Select.svelte' import WeaponKeySelect from './edit/WeaponKeySelect.svelte' import AwakeningSelect from './edit/AwakeningSelect.svelte' import AxSkillSelect from './edit/AxSkillSelect.svelte' + import BefoulmentSelect from './edit/BefoulmentSelect.svelte' import Button from '$lib/components/ui/Button.svelte' import Icon from '$lib/components/Icon.svelte' import { getElementIcon } from '$lib/utils/images' @@ -55,6 +56,9 @@ // AX skill state - initialize from existing AX skills let axSkills = $state(weapon.ax ?? []) + // Befoulment state - initialize from existing befoulment + let befoulment = $state(weapon.befoulment ?? null) + // Weapon data shortcuts const weaponData = $derived(weapon.weapon) const canChangeElement = $derived(weaponData?.element === 0) @@ -77,8 +81,10 @@ const hasWeaponKeys = $derived(seriesHasWeaponKeys(series)) const keySlotCount = $derived(seriesSlug ? (WEAPON_KEY_SLOTS[seriesSlug] ?? 2) : 0) - const hasAxSkills = $derived(weaponData?.ax === true) - const axType = $derived(weaponData?.axType ?? 1) + // Augment type from series determines AX skills vs befoulment + const augmentType = $derived(series?.augmentType ?? 'none') + const hasAxSkills = $derived(augmentType === 'ax') + const hasBefoulment = $derived(augmentType === 'befoulment') const hasAwakening = $derived((weaponData?.maxAwakeningLevel ?? 0) > 0) const availableAwakenings = $derived(weaponData?.awakenings ?? []) @@ -125,6 +131,9 @@ axStrength1?: number | null axModifier2Id?: string | null axStrength2?: number | null + befoulmentModifierId?: string | null + befoulmentStrength?: number | null + exorcismLevel?: number | null } function handleSave() { @@ -188,6 +197,21 @@ } } + // Befoulment - send modifier ID, strength, and exorcism level + if (hasBefoulment) { + const originalBef = weapon.befoulment + + if (befoulment?.modifier?.id !== originalBef?.modifier?.id) { + updates.befoulmentModifierId = befoulment?.modifier?.id ?? null + } + if (befoulment?.strength !== originalBef?.strength) { + updates.befoulmentStrength = befoulment?.strength ?? null + } + if (befoulment?.exorcismLevel !== originalBef?.exorcismLevel) { + updates.exorcismLevel = befoulment?.exorcismLevel ?? null + } + } + // Only call onSave if there are actual updates if (Object.keys(updates).length > 0) { onSave?.(updates as Partial) @@ -206,6 +230,7 @@ selectedAwakening = weapon.awakening?.type awakeningLevel = weapon.awakening?.level ?? 1 axSkills = weapon.ax ?? [] + befoulment = weapon.befoulment ?? null onCancel?.() } @@ -286,7 +311,6 @@
{ axSkills = skills @@ -296,6 +320,19 @@ {/if} + {#if hasBefoulment} + +
+ { + befoulment = bef + }} + /> +
+
+ {/if} + {#if hasAwakening && availableAwakenings.length > 0}
@@ -428,7 +465,8 @@ padding: spacing.$unit; } - .ax-skills-wrapper { + .ax-skills-wrapper, + .befoulment-wrapper { padding: spacing.$unit; } diff --git a/src/lib/components/sidebar/details/TeamView.svelte b/src/lib/components/sidebar/details/TeamView.svelte index d10dfb1c..f23aecd2 100644 --- a/src/lib/components/sidebar/details/TeamView.svelte +++ b/src/lib/components/sidebar/details/TeamView.svelte @@ -105,17 +105,32 @@ {/if} - {#if modificationStatus.hasAxSkills && weapon.ax} + {#if modificationStatus.hasAxSkills && weapon.ax?.length} {#each weapon.ax as axSkill} - + {#if axSkill.modifier?.id} + + {/if} {/each} {/if} + {#if modificationStatus.hasBefoulment && weapon.befoulment?.modifier} + + + + + {/if} + {#if modificationStatus.hasElement && weapon.element} diff --git a/src/lib/utils/modificationDetector.ts b/src/lib/utils/modificationDetector.ts index 0354d32e..975fbee5 100644 --- a/src/lib/utils/modificationDetector.ts +++ b/src/lib/utils/modificationDetector.ts @@ -6,6 +6,7 @@ export interface ModificationStatus { hasAwakening: boolean hasWeaponKeys: boolean hasAxSkills: boolean + hasBefoulment: boolean hasRings: boolean hasEarring: boolean hasPerpetuity: boolean @@ -25,6 +26,7 @@ export function detectModifications( hasAwakening: false, hasWeaponKeys: false, hasAxSkills: false, + hasBefoulment: false, hasRings: false, hasEarring: false, hasPerpetuity: false, @@ -60,6 +62,7 @@ export function detectModifications( status.hasAwakening = !!weapon.awakening status.hasWeaponKeys = !!(weapon.weaponKeys && weapon.weaponKeys.length > 0) status.hasAxSkills = !!(weapon.ax && weapon.ax.length > 0) + status.hasBefoulment = !!weapon.befoulment?.modifier status.hasTranscendence = !!(weapon.transcendenceStep && weapon.transcendenceStep > 0) status.hasUncapLevel = weapon.uncapLevel !== undefined && weapon.uncapLevel !== null status.hasElement = !!(weapon.element && weapon.weapon?.element === 0) @@ -68,6 +71,7 @@ export function detectModifications( status.hasAwakening || status.hasWeaponKeys || status.hasAxSkills || + status.hasBefoulment || status.hasTranscendence || status.hasUncapLevel || status.hasElement @@ -111,13 +115,14 @@ export function canWeaponBeModified(gridWeapon: GridWeapon | undefined): boolean // Weapon keys (series-specific) - use utility function that handles both formats const hasWeaponKeys = seriesHasWeaponKeys(weapon.series) - // AX skills - const hasAxSkills = weapon.ax === true + // AX skills or Befoulment - check augmentType from series + const augmentType = weapon.series?.augmentType ?? 'none' + const hasAugments = augmentType !== 'none' // Awakening (maxAwakeningLevel > 0 means it can have awakening) const hasAwakening = (weapon.maxAwakeningLevel ?? 0) > 0 - return canChangeElement || hasWeaponKeys || hasAxSkills || hasAwakening + return canChangeElement || hasWeaponKeys || hasAugments || hasAwakening } /** diff --git a/src/stories/mocks/weapons.ts b/src/stories/mocks/weapons.ts index 0e34db62..e44cdd47 100644 --- a/src/stories/mocks/weapons.ts +++ b/src/stories/mocks/weapons.ts @@ -8,7 +8,7 @@ const mockOmegaSeries = { name: { en: 'Omega', ja: 'マグナ' }, hasWeaponKeys: false, hasAwakening: true, - hasAxSkills: true, + augmentType: 'ax' as const, extra: false, elementChangeable: false }; @@ -19,7 +19,7 @@ const mockOpusSeries = { name: { en: 'Opus', ja: 'オプス' }, hasWeaponKeys: true, hasAwakening: true, - hasAxSkills: false, + augmentType: 'none' as const, extra: false, elementChangeable: false }; @@ -30,7 +30,7 @@ const mockDraconicSeries = { name: { en: 'Draconic', ja: 'ドラゴニック' }, hasWeaponKeys: true, hasAwakening: false, - hasAxSkills: false, + augmentType: 'none' as const, extra: false, elementChangeable: false };