preset system

This commit is contained in:
Alexander Drozdov
2022-02-22 12:31:42 +02:00
parent 09c6f5a920
commit 812ecc59c4
10 changed files with 296 additions and 135 deletions
+1
View File
@@ -49,6 +49,7 @@ export interface ParsedItem {
influences: ItemInfluence[]
logbookAreaMods?: ParsedModifier[][]
isSynthesised?: boolean
isFractured?: boolean
isVeiled?: boolean
statsByType: StatCalculated[]
newMods: ParsedModifier[]
+7
View File
@@ -64,6 +64,7 @@ const parsers: Array<ParserFn | { virtual: VirtualParserFn }> = [
parseModifiers, // implicit
parseModifiers, // explicit
{ virtual: transformToLegacyModifiers },
{ virtual: parseFractured },
{ virtual: parseBlightedMap },
{ virtual: pickCorrectVariant }
]
@@ -223,6 +224,12 @@ function parseBlightedMap (item: ParsedItem) {
}
}
function parseFractured (item: ParserState) {
if (item.newMods.some(mod => mod.info.type === ModifierType.Fractured)) {
item.isFractured = true
}
}
function pickCorrectVariant (item: ParserState) {
if (!item.info.disc) return
+38 -55
View File
@@ -1,34 +1,34 @@
<template>
<div v-if="show" class="p-4 layout-column min-h-0">
<filter-name
ref="nameFilter"
:filters="itemFilters"
:item="item" />
<price-prediction v-if="showPredictedPrice" class="mb-4"
:item="item" />
<price-trend
<price-trend v-else
:item="item"
:filters="itemFilters"
@filter-item-base="applyItemBaseFilter" />
:filters="itemFilters" />
<filters-block
ref="filtersBlock"
:filters="itemFilters"
:stats="itemStats"
:item="item"
@submit="interactedOnce = true" />
:presets="presets"
@preset="selectPreset"
@submit="doSearch = true" />
<trade-listing
v-if="tradeAPI === 'trade' && interactedOnce"
v-if="tradeAPI === 'trade' && doSearch"
ref="tradeService"
:filters="itemFilters"
:stats="itemStats"
:item="item" />
<trade-bulk
v-if="tradeAPI === 'bulk' && interactedOnce"
v-if="tradeAPI === 'bulk' && doSearch"
ref="tradeService"
:filters="itemFilters"
:item="item" />
<div v-if="!interactedOnce" @mouseenter="handleSearchMouseenter">
<button class="btn" @click="interactedOnce = true">{{ t('Search') }}</button>
<div v-if="!doSearch" @mouseenter="handleSearchMouseenter">
<button class="btn" @click="doSearch = true">{{ t('Search') }}</button>
</div>
<stack-value :filters="itemFilters" :item="item"/>
<div v-if="showSupportLinks" class="mt-auto border border-dashed p-2">
@@ -42,7 +42,7 @@
</template>
<script lang="ts">
import { defineComponent, PropType, watch, ref, nextTick, computed, Ref, ComponentPublicInstance } from 'vue'
import { defineComponent, PropType, watch, ref, nextTick, computed, ComponentPublicInstance } from 'vue'
import { useI18n } from 'vue-i18n'
import { ItemRarity, ItemCategory, ParsedItem } from '@/parser'
import TradeListing from './trade/TradeListing.vue'
@@ -50,14 +50,13 @@ import TradeBulk from './trade/TradeBulk.vue'
import { apiToSatisfySearch } from './trade/common'
import PriceTrend from './trends/PriceTrend.vue'
import FiltersBlock from './filters/FiltersBlock.vue'
import { createFilters } from './filters/create-item-filters'
import { initUiModFilters } from './filters/create-stat-filters'
import { createPresets } from './filters/create-presets'
import PricePrediction from './price-prediction/PricePrediction.vue'
import StackValue from './stack-value/StackValue.vue'
import FilterName from './filters/FilterName.vue'
import { CATEGORY_TO_TRADE_ID } from './trade/pathofexile-trade'
import { AppConfig } from '@/web/Config'
import { FilterTag, ItemFilters, StatFilter } from './filters/interfaces'
import { FilterPreset } from './filters/interfaces'
import { PriceCheckWidget } from '../overlay/interfaces'
import { selected as selectedLeague, isPublic as isPublicLeague } from '@/web/background/Leagues'
@@ -87,34 +86,31 @@ export default defineComponent({
setup (props) {
const widget = computed(() => AppConfig<PriceCheckWidget>('price-check')!)
const itemFilters = ref<ItemFilters>(null!)
const itemStats = ref<StatFilter[]>(null!)
const interactedOnce = ref(false)
const presets = ref<{ active: string, presets: FilterPreset[] }>(null!)
const itemFilters = computed(() => presets.value.presets.find(preset => preset.id === presets.value.active)!.filters)
const itemStats = computed(() => presets.value.presets.find(preset => preset.id === presets.value.active)!.stats)
const doSearch = ref(false)
const tradeAPI = ref<'trade' | 'bulk'>('bulk')
// TradeListing.vue OR TradeBulk.vue
const tradeService = ref<{ execSearch(): void } | null>(null)
// FilterName.vue
const nameFilter = ref<{ toggleAccuracy(): void }>(null!)
// FiltersBlock.vue
const filtersBlock = ref<ComponentPublicInstance<{}, { showHidden: Ref<boolean> }>>(null!)
const filtersBlock = ref<ComponentPublicInstance<{}, {}>>(null!)
watch(() => props.item, (item) => {
itemFilters.value = createFilters(item, {
presets.value = createPresets(item, {
league: selectedLeague.value!,
chaosPriceThreshold: widget.value.chaosPriceThreshold,
collapseListings: widget.value.collapseListings,
activateStockFilter: widget.value.activateStockFilter
})
itemStats.value = initUiModFilters(item, {
activateStockFilter: widget.value.activateStockFilter,
searchStatRange: widget.value.searchStatRange
})
if ((!props.advancedCheck && !widget.value.smartInitialSearch) ||
(props.advancedCheck && !widget.value.lockedInitialSearch)) {
interactedOnce.value = false
doSearch.value = false
} else {
interactedOnce.value = Boolean(
doSearch.value = Boolean(
(item.rarity === ItemRarity.Unique) ||
(item.category === ItemCategory.Map) ||
(item.category === ItemCategory.HeistBlueprint) ||
@@ -125,8 +121,8 @@ export default defineComponent({
}
}, { immediate: true })
watch(() => [props.item, interactedOnce.value], () => {
if (interactedOnce.value === false) return
watch(() => [props.item, doSearch.value], () => {
if (doSearch.value === false) return
tradeAPI.value = apiToSatisfySearch(props.item, itemStats.value, itemFilters.value)
@@ -138,13 +134,13 @@ export default defineComponent({
})
}, { deep: false, immediate: true })
watch(() => [props.item, interactedOnce.value, itemStats.value, itemFilters.value], (curr, prev) => {
watch(() => [props.item, doSearch.value, itemStats.value, itemFilters.value], (curr, prev) => {
const cItem = curr[0]; const pItem = prev[0]
const cIntaracted = curr[1]; const pIntaracted = prev[1]
if (cItem === pItem && cIntaracted === true && pIntaracted === true) {
// force user to press Search button on change
interactedOnce.value = false
doSearch.value = false
}
}, { deep: true })
@@ -154,7 +150,7 @@ export default defineComponent({
if (cItem === pItem && cTrade !== pTrade) {
nextTick(() => {
interactedOnce.value = true
doSearch.value = true
})
}
}, { deep: false })
@@ -164,12 +160,15 @@ export default defineComponent({
AppConfig().language !== 'en' ||
!isPublicLeague.value) return false
if (presets.value.active === 'Base item') return false
return props.item.rarity === ItemRarity.Rare &&
props.item.category !== ItemCategory.Map &&
props.item.category !== ItemCategory.CapturedBeast &&
props.item.category !== ItemCategory.HeistContract &&
props.item.category !== ItemCategory.HeistBlueprint &&
props.item.category !== ItemCategory.Invitation &&
props.item.info.refName !== 'Expedition Logbook' &&
!props.item.isUnidentified
})
@@ -179,28 +178,9 @@ export default defineComponent({
props.item.info.unique == null)
})
async function applyItemBaseFilter () {
for (const stat of itemStats.value) {
// TODO or 'Syntesized'
if (stat.tag === FilterTag.Fractured && stat.hidden) {
stat.disabled = false
filtersBlock.value.showHidden = true
} else {
stat.disabled = true
}
}
await nextTick()
itemFilters.value.itemLevel!.disabled = false
if (itemFilters.value.influences) {
itemFilters.value.influences[0].disabled = false
}
nameFilter.value.toggleAccuracy()
}
function handleSearchMouseenter (e: MouseEvent) {
if ((filtersBlock.value.$el as HTMLElement).contains(e.relatedTarget as HTMLElement)) {
interactedOnce.value = true
doSearch.value = true
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur()
@@ -209,7 +189,7 @@ export default defineComponent({
}
const showSupportLinks = ref(false)
watch(() => [props.item, interactedOnce.value], ([cItem, cInteracted], [pItem]) => {
watch(() => [props.item, doSearch.value], ([cItem, cInteracted], [pItem]) => {
if (_showSupportLinksCounter >= 13 && (!cInteracted || tradeAPI.value === 'bulk')) {
showSupportLinks.value = true
_showSupportLinksCounter = 0
@@ -227,16 +207,19 @@ export default defineComponent({
t,
itemFilters,
itemStats,
interactedOnce,
doSearch,
tradeAPI,
tradeService,
nameFilter,
filtersBlock,
showPredictedPrice,
show,
applyItemBaseFilter,
handleSearchMouseenter,
showSupportLinks
showSupportLinks,
presets: computed(() => presets.value.presets.map(preset =>
({ id: preset.id, active: (preset.id === presets.value.active) }))),
selectPreset (id: string) {
presets.value.active = id
}
}
}
})
+51 -8
View File
@@ -35,7 +35,7 @@
:filter="filters.veiled" text="Veiled" />
<filter-btn-logical v-if="filters.mirrored" active
:filter="filters.mirrored" :text="filters.mirrored.disabled ? 'Not Mirrored' : 'Mirrored'" />
<filter-btn-logical v-if="stats.length"
<filter-btn-logical v-if="hasStats"
:collapse="statsVisibility.disabled"
:filter="statsVisibility"
:active="totalSelectedMods > 0"
@@ -44,13 +44,25 @@
: t('Stats ignored')"
/>
</div>
<div v-if="!statsVisibility.disabled && stats.length" class="my-4">
<div v-if="!statsVisibility.disabled && hasStats" class="mb-4" :class="(presets.length > 1) ? 'mt-1' : 'mt-4'">
<div class="flex" v-if="presets.length > 1">
<div class="w-5 border-b border-gray-700" />
<div class="flex divide-x border-gray-700 border-t border-l border-r rounded-t overflow-hidden">
<button v-for="preset in presets"
:class="[$style.presetBtn, { [$style.active]: preset.active }]"
@click="selectPreset(preset.id)"
>{{ t(preset.id) }}</button>
</div>
<div class="flex-1 border-b border-gray-700" />
</div>
<form @submit.prevent="handleStatsSubmit">
<filter-modifier v-for="filter of shownStats" :key="filter.tag + '/' + filter.text"
<filter-modifier v-for="filter of filteredStats" :key="filter.tag + '/' + filter.text"
:filter="filter"
:item="item"
:show-sources="showFilterSources"
@submit="handleStatsSubmit" />
<div v-if="!filteredStats.length && !item.unknownModifiers.length"
class="border-b border-gray-700 py-2">{{ t('No relevant stats were found') }}</div>
<unknown-modifier v-for="stat of item.unknownModifiers" :key="stat.type + '/' + stat.text"
:stat="stat" />
<input type="submit" class="hidden" />
@@ -58,7 +70,7 @@
<div class="flex gap-x-4">
<button @click="statsVisibility.disabled = !statsVisibility.disabled" class="bg-gray-700 px-2 py-1 text-gray-400 leading-none rounded-b w-40"
>{{ t('Collapse') }} <i class="fas fa-chevron-up pl-1 text-xs text-gray-600"></i></button>
<ui-toggle v-if="shownStats.length != stats.length"
<ui-toggle v-if="filteredStats.length != stats.length"
v-model="showHidden" class="text-gray-400 pt-2">{{ t('Hidden') }}</ui-toggle>
<!-- <ui-toggle
v-model="showFilterSources" class="ml-auto text-gray-400 pt-2">{{ t('Mods') }}</ui-toggle> -->
@@ -75,11 +87,11 @@ import FilterBtnNumeric from './FilterBtnNumeric.vue'
import FilterBtnLogical from './FilterBtnLogical.vue'
import UnknownModifier from './UnknownModifier.vue'
import { ItemFilters, StatFilter } from './interfaces'
import { ParsedItem } from '@/parser'
import { ParsedItem, ItemRarity } from '@/parser'
export default defineComponent({
name: 'FiltersBlock',
emits: ['submit'],
emits: ['submit', 'preset'],
components: {
FilterModifier,
FilterBtnNumeric,
@@ -87,6 +99,10 @@ export default defineComponent({
UnknownModifier
},
props: {
presets: {
type: Array as PropType<Array<{ id: string, active: boolean }>>,
required: true
},
filters: {
type: Object as PropType<ItemFilters>,
required: true
@@ -120,21 +136,44 @@ export default defineComponent({
totalSelectedMods: computed(() => {
return props.stats.filter(stat => !stat.disabled).length
}),
shownStats: computed(() => {
filteredStats: computed(() => {
if (showHidden.value) {
return props.stats.filter(s => s.hidden)
} else {
return props.stats.filter(s => !s.hidden)
}
}),
hasStats: computed(() =>
props.stats.length ||
(props.item.unknownModifiers.length && props.item.rarity === ItemRarity.Unique) ||
props.presets.length > 1),
handleStatsSubmit () {
ctx.emit('submit')
},
selectPreset (id: string) {
ctx.emit('preset', id)
}
}
}
})
</script>
<style lang="postcss" module>
.presetBtn {
@apply border-gray-700 bg-gray-800;
@apply px-2;
min-width: 3rem;
&:hover {
@apply bg-gray-700;
}
&.active {
background: linear-gradient(to bottom, theme('colors.gray.900'), theme('colors.gray.800'));
}
}
</style>
<i18n>
{
"ru": {
@@ -142,7 +181,11 @@ export default defineComponent({
"Collapse": "Свернуть",
"Stats ignored": "Св-ва не важны",
"{0} of {1}, stats": "Св-ва: {0} из {1}",
"Mods": "Моды"
"Mods": "Моды",
"No relevant stats were found": "Подходящие свойства не найдены",
"Pseudo": "Псевдо",
"Base item": "База предмета"
}
}
</i18n>
@@ -1,5 +1,5 @@
import type { ItemFilters } from './interfaces'
import { ParsedItem, ItemCategory, ItemRarity } from '@/parser'
import { ParsedItem, ItemCategory, ItemRarity, ItemInfluence } from '@/parser'
import { tradeTag, PERMANENT_LEAGUES } from '../trade/common'
import { ModifierType } from '@/parser/modifiers'
import { ITEM_BY_REF } from '@/assets/data'
@@ -14,6 +14,7 @@ export function createFilters (
chaosPriceThreshold: number
collapseListings: 'app' | 'api'
activateStockFilter: boolean
exact: boolean
}
): ItemFilters {
const filters: ItemFilters = {
@@ -154,7 +155,7 @@ export function createFilters (
if (item.category && CATEGORY_TO_TRADE_ID.has(item.category)) {
filters.searchRelaxed = {
category: item.category,
disabled: (item.rarity !== ItemRarity.Rare)
disabled: opts.exact
}
}
}
@@ -198,11 +199,21 @@ export function createFilters (
filters.mirrored = { disabled: false }
}
if (item.influences.length) {
filters.influences = item.influences.map(influecne => ({
value: influecne,
disabled: true
}))
if (item.influences.length && item.influences.length <= 2) {
if (opts.exact) {
filters.influences = item.influences.map(influecne => ({
value: influecne,
disabled: false
}))
} else if (item.influences.length === 1 && (
item.influences[0] === ItemInfluence.Shaper ||
item.influences[0] === ItemInfluence.Elder
)) {
filters.influences = [{
value: item.influences[0],
disabled: true
}]
}
}
if (item.itemLevel) {
@@ -216,7 +227,7 @@ export function createFilters (
if (item.itemLevel > 86) {
filters.itemLevel = {
value: 86,
disabled: true
disabled: !opts.exact
}
// @TODO limit by item type
// If (RegExMatch(subtype, "i)Helmet|Gloves|Boots|Body Armour|Shield|Quiver")) {
@@ -232,7 +243,7 @@ export function createFilters (
} else {
filters.itemLevel = {
value: item.itemLevel,
disabled: true
disabled: !opts.exact
}
}
}
@@ -268,18 +279,6 @@ export function createFilters (
value: true,
disabled: (item.rarity !== ItemRarity.Unique)
}
if (item.rarity !== ItemRarity.Unique) {
if (filters.itemLevel) {
filters.itemLevel.disabled = false
}
if (filters.influences) {
filters.influences[0].disabled = false
}
if (filters.searchRelaxed) {
filters.searchRelaxed.disabled = true
}
}
}
if (item.isVeiled) {
@@ -0,0 +1,88 @@
import { createFilters } from './create-item-filters'
import { createExactStatFilters, initUiModFilters } from './create-stat-filters'
import { ModifierType, sumStatsByModType } from '@/parser/modifiers'
import { ItemCategory, ItemRarity, ParsedItem } from '@/parser'
import type { FilterPreset } from './interfaces'
const ROMAN_NUMERALS = ['I', 'II', 'III', 'IV', 'V']
export function createPresets (
item: ParsedItem,
opts: {
league: string
chaosPriceThreshold: number
collapseListings: 'app' | 'api'
activateStockFilter: boolean
searchStatRange: number
}
): { presets: FilterPreset[], active: string } {
if (item.info.refName === 'Expedition Logbook') {
return {
active: ROMAN_NUMERALS[0],
presets: item.logbookAreaMods!.map<FilterPreset>((area, idx) => ({
id: ROMAN_NUMERALS[idx],
filters: createFilters(item, { ...opts, exact: true }),
stats: createExactStatFilters(item, sumStatsByModType(area), opts)
}))
}
}
if (
(!item.info.craftable && item.rarity !== ItemRarity.Unique) ||
item.isUnidentified ||
item.rarity === ItemRarity.Normal ||
item.category === ItemCategory.Map ||
item.category === ItemCategory.Invitation ||
item.category === ItemCategory.HeistContract ||
item.category === ItemCategory.HeistBlueprint
) {
return {
active: 'Exact',
presets: [{
id: 'Exact',
filters: createFilters(item, { ...opts, exact: true }),
stats: createExactStatFilters(item, item.statsByType, opts)
}]
}
}
const pseudoPreset: FilterPreset = {
id: 'Pseudo',
filters: createFilters(item, { ...opts, exact: false }),
stats: initUiModFilters(item, opts)
}
const likelyFinishedItem = (
item.rarity === ItemRarity.Unique ||
item.statsByType.some(calc => calc.type === ModifierType.Crafted) ||
item.quality === 20 || // quality > 20 can be used for selling bases, quality < 20 drops sometimes
item.isCorrupted ||
item.isMirrored
)
const hasCraftingValue = (
item.isSynthesised ||
item.isFractured ||
item.influences.length ||
item.category === ItemCategory.ClusterJewel ||
(item.category === ItemCategory.Jewel && item.rarity === ItemRarity.Magic) ||
(item.category !== ItemCategory.Jewel &&
item.category !== ItemCategory.AbyssJewel &&
item.itemLevel! >= 82)
)
if (likelyFinishedItem || !hasCraftingValue) {
return { active: pseudoPreset.id, presets: [pseudoPreset] }
}
const baseItemPreset: FilterPreset = {
id: 'Base item',
filters: createFilters(item, { ...opts, exact: true }),
stats: createExactStatFilters(item, item.statsByType, opts)
}
return {
active: pseudoPreset.id,
presets: [pseudoPreset, baseItemPreset]
}
}
@@ -14,21 +14,90 @@ export interface FiltersCreationContext {
statsByType: StatCalculated[]
}
export function createExactStatFilters (
item: ParsedItem,
statsByType: StatCalculated[],
_opts: {}
): StatFilter[] {
if (item.mapBlighted) return []
if (
item.isUnidentified &&
item.rarity === ItemRarity.Unique &&
!item.isSynthesised
) return []
const keepByType = [ModifierType.Pseudo, ModifierType.Implicit, ModifierType.Fractured]
if (
item.category !== ItemCategory.Amulet &&
item.category !== ItemCategory.Ring &&
item.category !== ItemCategory.Flask
) {
keepByType.push(ModifierType.Enchant)
}
if (item.rarity === ItemRarity.Magic && (
item.category !== ItemCategory.Flask &&
item.category !== ItemCategory.ClusterJewel &&
item.category !== ItemCategory.Map &&
item.category !== ItemCategory.Invitation &&
item.category !== ItemCategory.HeistContract &&
item.category !== ItemCategory.HeistBlueprint
)) {
keepByType.push(ModifierType.Explicit)
}
const ctx: FiltersCreationContext = {
item,
searchInRange: 100,
filters: [],
statsByType: statsByType.filter(calc => keepByType.includes(calc.type))
}
ctx.filters.push(
...ctx.statsByType.map(mod => calculatedStatToFilter(mod, ctx.searchInRange, item))
)
if (item.info.refName === 'Chronicle of Atzoatl') {
applyAtzoatlRules(ctx.filters)
return ctx.filters
}
for (const filter of ctx.filters) {
filter.hidden = undefined
if (filter.tag === FilterTag.Explicit) {
filter.disabled = !filter.sources.some(source =>
source.modifier.info.tier != null &&
source.modifier.info.tier <= 2
)
} else {
filter.disabled = false
}
if (item.category === ItemCategory.ClusterJewel) {
if (filter.statRef === '# Added Passive Skills are Jewel Sockets') {
filter.hidden = 'Roll is not variable'
filter.disabled = true
}
if (filter.statRef === 'Adds # Passive Skills') {
filter.roll!.min = filter.roll!.default.min
// https://www.poewiki.net/wiki/Cluster_Jewel#Optimal_passive_skill_amounts
if (filter.roll!.max === 4) {
filter.roll!.max = 5
}
}
}
}
return ctx.filters
}
export function initUiModFilters (
item: ParsedItem,
opts: {
searchStatRange: number
}
): StatFilter[] {
if (
(item.rarity === ItemRarity.Unique && item.category === ItemCategory.Map) ||
item.category === ItemCategory.Invitation ||
item.category === ItemCategory.HeistContract ||
item.category === ItemCategory.HeistBlueprint
) {
return []
}
const ctx: FiltersCreationContext = {
item,
filters: [],
@@ -44,15 +113,8 @@ export function initUiModFilters (
})
}
if (!item.isUnidentified) {
filterItemProp(ctx)
filterPseudo(ctx)
}
if (!item.isCorrupted && !item.isMirrored) {
ctx.statsByType = ctx.statsByType.filter(mod => mod.type !== ModifierType.Fractured)
ctx.statsByType.push(...item.statsByType.filter(mod => mod.type === ModifierType.Fractured))
}
filterItemProp(ctx)
filterPseudo(ctx)
if (item.isVeiled) {
ctx.statsByType = ctx.statsByType.filter(mod => mod.type !== ModifierType.Veiled)
@@ -62,35 +124,10 @@ export function initUiModFilters (
...ctx.statsByType.map(mod => calculatedStatToFilter(mod, ctx.searchInRange, item))
)
if (item.info.refName === 'Chronicle of Atzoatl') {
applyAtzoatlRules(ctx.filters)
return ctx.filters
}
if (!item.isCorrupted && !item.isMirrored && item.isSynthesised) {
const transformedImplicits = item.statsByType.filter(mod =>
mod.type === ModifierType.Implicit &&
!ctx.statsByType.includes(mod))
const synthImplicitFilters = transformedImplicits.map(mod => calculatedStatToFilter(mod, ctx.searchInRange, item))
for (const filter of synthImplicitFilters) {
filter.hidden = 'Select only if price-checking as base item for crafting'
}
ctx.filters.push(...synthImplicitFilters)
}
if (item.isUnidentified && item.rarity === ItemRarity.Unique) {
ctx.filters = ctx.filters.filter(f => !f.hidden)
}
if (item.isVeiled) {
ctx.filters.forEach(filter => { filter.disabled = true })
}
if (item.category === ItemCategory.Map) {
ctx.filters = ctx.filters.filter(f => f.tag !== FilterTag.Explicit)
}
finalFilterTweaks(ctx)
return ctx.filters
@@ -266,11 +303,8 @@ function finalFilterTweaks (ctx: FiltersCreationContext) {
filter.hidden = 'Roll is not variable'
}
if (filter.statRef === 'Adds # Passive Skills') {
// https://pathofexile.gamepedia.com/Cluster_Jewel#Optimal_passive_skill_amounts
filter.disabled = false
if (filter.roll!.max === 4) {
filter.roll!.max = 5
}
filter.disabled = true
filter.roll!.max = undefined
}
}
}
@@ -2,6 +2,12 @@ import type { ItemInfluence, ItemCategory } from '@/parser'
import type { StatCalculated } from '@/parser/modifiers'
import type { ParsedItem } from '@/parser/ParsedItem'
export interface FilterPreset {
id: 'Pseudo' | 'Base' | string
filters: ItemFilters
stats: StatFilter[]
}
interface SearchFilter {
name?: string
baseType?: string
+1 -2
View File
@@ -11,8 +11,7 @@
:item-img="item.info.icon"
>
<template #item v-if="isValuableBasetype">
<button class="text-gray-400 hover:bg-gray-700 rounded px-1 -mx-1"
@click="$emit('filter-item-base')">{{ t('Base item') }}</button>
<span class="text-gray-400">{{ t('Base item') }}</span>
</template>
</item-quick-price>
<div v-if="trend.changeStr" class="px-2 text-center">
+2 -1
View File
@@ -78,10 +78,11 @@ function forBasetype (item: ParsedItem) {
if (item.influences.length === 1) {
id += ` // ${item.influences[0]}`
return id
} else if (item.influences.length > 1) {
return undefined
}
return id
}
function forUniqueItem (item: ParsedItem) {