From 812ecc59c42c4d5cfff2f0a8a19f88e99a44ad64 Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Tue, 22 Feb 2022 12:31:42 +0200 Subject: [PATCH] preset system --- src/parser/ParsedItem.ts | 1 + src/parser/Parser.ts | 7 + src/web/price-check/CheckedItem.vue | 93 +++++-------- src/web/price-check/filters/FiltersBlock.vue | 59 ++++++-- .../filters/create-item-filters.ts | 41 +++--- src/web/price-check/filters/create-presets.ts | 88 ++++++++++++ .../filters/create-stat-filters.ts | 130 +++++++++++------- src/web/price-check/filters/interfaces.ts | 6 + src/web/price-check/trends/PriceTrend.vue | 3 +- src/web/price-check/trends/getDetailsId.ts | 3 +- 10 files changed, 296 insertions(+), 135 deletions(-) create mode 100644 src/web/price-check/filters/create-presets.ts diff --git a/src/parser/ParsedItem.ts b/src/parser/ParsedItem.ts index 0387a9dc..6e3db85a 100644 --- a/src/parser/ParsedItem.ts +++ b/src/parser/ParsedItem.ts @@ -49,6 +49,7 @@ export interface ParsedItem { influences: ItemInfluence[] logbookAreaMods?: ParsedModifier[][] isSynthesised?: boolean + isFractured?: boolean isVeiled?: boolean statsByType: StatCalculated[] newMods: ParsedModifier[] diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index 48015e64..d8f515c3 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -64,6 +64,7 @@ const parsers: Array = [ 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 diff --git a/src/web/price-check/CheckedItem.vue b/src/web/price-check/CheckedItem.vue index 93ca9703..7e358217 100644 --- a/src/web/price-check/CheckedItem.vue +++ b/src/web/price-check/CheckedItem.vue @@ -1,34 +1,34 @@ + + { "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": "База предмета" } } diff --git a/src/web/price-check/filters/create-item-filters.ts b/src/web/price-check/filters/create-item-filters.ts index 958a6fd2..368ee12e 100644 --- a/src/web/price-check/filters/create-item-filters.ts +++ b/src/web/price-check/filters/create-item-filters.ts @@ -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) { diff --git a/src/web/price-check/filters/create-presets.ts b/src/web/price-check/filters/create-presets.ts new file mode 100644 index 00000000..328d78ac --- /dev/null +++ b/src/web/price-check/filters/create-presets.ts @@ -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((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] + } +} diff --git a/src/web/price-check/filters/create-stat-filters.ts b/src/web/price-check/filters/create-stat-filters.ts index 8f3e2641..ea78abfe 100644 --- a/src/web/price-check/filters/create-stat-filters.ts +++ b/src/web/price-check/filters/create-stat-filters.ts @@ -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 } } } diff --git a/src/web/price-check/filters/interfaces.ts b/src/web/price-check/filters/interfaces.ts index 04268fb2..c55470d7 100644 --- a/src/web/price-check/filters/interfaces.ts +++ b/src/web/price-check/filters/interfaces.ts @@ -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 diff --git a/src/web/price-check/trends/PriceTrend.vue b/src/web/price-check/trends/PriceTrend.vue index 6c57c987..680747a2 100644 --- a/src/web/price-check/trends/PriceTrend.vue +++ b/src/web/price-check/trends/PriceTrend.vue @@ -11,8 +11,7 @@ :item-img="item.info.icon" >
diff --git a/src/web/price-check/trends/getDetailsId.ts b/src/web/price-check/trends/getDetailsId.ts index 07de61ed..ed70caaf 100644 --- a/src/web/price-check/trends/getDetailsId.ts +++ b/src/web/price-check/trends/getDetailsId.ts @@ -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) {