diff --git a/renderer/src/parser/Parser.ts b/renderer/src/parser/Parser.ts index bb5814d8..c7946526 100644 --- a/renderer/src/parser/Parser.ts +++ b/renderer/src/parser/Parser.ts @@ -52,6 +52,7 @@ const parsers: Array = [ parseHeistBlueprint, parseAreaLevel, parseAtzoatlRooms, + parseMirroredTablet, parseMirrored, parseSentinelCharge, parseLogbookArea, @@ -784,7 +785,8 @@ function parseAreaLevelNested (section: string[], item: ParsedItem) { function parseAreaLevel (section: string[], item: ParsedItem) { if ( item.info.refName !== 'Chronicle of Atzoatl' && - item.info.refName !== 'Expedition Logbook' + item.info.refName !== 'Expedition Logbook' && + item.info.refName !== 'Mirrored Tablet' ) return 'PARSER_SKIPPED' parseAreaLevelNested(section, item) @@ -830,6 +832,28 @@ function parseAtzoatlRooms (section: string[], item: ParsedItem) { return 'SECTION_PARSED' } +function parseMirroredTablet (section: string[], item: ParsedItem) { + if (item.info.refName !== 'Mirrored Tablet') return 'PARSER_SKIPPED' + if (section.length < 8) return 'SECTION_SKIPPED' + + for (const line of section) { + const found = tryParseTranslation({ string: line, unscalable: true }, ModifierType.Pseudo) + if (found) { + item.newMods.push({ + info: { tags: [], type: ModifierType.Pseudo }, + stats: [found] + }) + } else { + item.unknownModifiers.push({ + text: line, + type: ModifierType.Pseudo + }) + } + } + + return 'SECTION_PARSED' +} + function markupConditionParser (text: string) { // ignores state set by <> // always evaluates first condition to true {...} diff --git a/renderer/src/parser/modifiers.ts b/renderer/src/parser/modifiers.ts index a8d1267c..b3f36cc3 100644 --- a/renderer/src/parser/modifiers.ts +++ b/renderer/src/parser/modifiers.ts @@ -63,15 +63,19 @@ export function sumStatsByModType (mods: readonly ParsedModifier[]): StatCalcula } export function statSourcesTotal ( - sources: StatSource[] + sources: StatSource[], + mode: 'sum' | 'max' = 'sum' ): StatRoll | undefined { + const fn = (mode === 'sum') + ? ((a: number, b: number) => a + b) + : ((a: number, b: number) => Math.max(a, b)) return (sources.length === 1) ? (sources[0].contributes) : (sources.reduce((sum, { contributes }) => { contributes = contributes ?? { value: 1, min: 1, max: 1 } - sum.value += contributes.value - sum.min += contributes.min - sum.max += contributes.max + sum.value = fn(sum.value, contributes.value) + sum.min = fn(sum.min, contributes.min) + sum.max = fn(sum.max, contributes.max) return sum }, { value: 0, min: 0, max: 0 })) } diff --git a/renderer/src/web/price-check/filters/FilterModifier.vue b/renderer/src/web/price-check/filters/FilterModifier.vue index d7029a1a..1c6d2b2c 100644 --- a/renderer/src/web/price-check/filters/FilterModifier.vue +++ b/renderer/src/web/price-check/filters/FilterModifier.vue @@ -99,6 +99,7 @@ export default defineComponent({ props.filter.tag !== FilterTag.Property && props.filter.tradeId[0] !== 'item.has_empty_modifier' && props.item.info.refName !== 'Chronicle of Atzoatl' && + props.item.info.refName !== 'Mirrored Tablet' && !(props.item.rarity === ItemRarity.Unique && ( props.filter.tag === FilterTag.Explicit || props.filter.tag === FilterTag.Pseudo)) diff --git a/renderer/src/web/price-check/filters/create-item-filters.ts b/renderer/src/web/price-check/filters/create-item-filters.ts index a4a18a3b..7708b49b 100644 --- a/renderer/src/web/price-check/filters/create-item-filters.ts +++ b/renderer/src/web/price-check/filters/create-item-filters.ts @@ -81,6 +81,12 @@ export function createFilters ( disabled: false } } + if (item.info.refName === 'Mirrored Tablet') { + filters.areaLevel = { + value: item.areaLevel!, + disabled: false + } + } return filters } diff --git a/renderer/src/web/price-check/filters/create-stat-filters.ts b/renderer/src/web/price-check/filters/create-stat-filters.ts index a07469d9..ce930561 100644 --- a/renderer/src/web/price-check/filters/create-stat-filters.ts +++ b/renderer/src/web/price-check/filters/create-stat-filters.ts @@ -4,6 +4,7 @@ import { percentRoll, percentRollDelta, roundRoll } from './util' import { FilterTag, ItemHasEmptyModifier, StatFilter } from './interfaces' import { filterPseudo } from './pseudo' import { applyRules as applyAtzoatlRules } from './pseudo/atzoatl-rules' +import { applyRules as applyMirroredTabletRules } from './pseudo/reflection-rules' import { filterItemProp } from './pseudo/item-property' import { decodeOils, applyAnointmentRules } from './pseudo/anointments' import { StatBetter, CLIENT_STRINGS } from '@/assets/data' @@ -66,6 +67,10 @@ export function createExactStatFilters ( applyAtzoatlRules(ctx.filters) return ctx.filters } + if (item.info.refName === 'Mirrored Tablet') { + applyMirroredTabletRules(ctx.filters) + return ctx.filters + } for (const filter of ctx.filters) { filter.hidden = undefined @@ -168,7 +173,10 @@ export function calculatedStatToFilter ( } } - const roll = statSourcesTotal(calc.sources) + const roll = statSourcesTotal( + calc.sources, + (item.info.refName === 'Mirrored Tablet') ? 'max' : 'sum' + ) const translation = translateStatWithRoll(calc, roll) filter ??= { diff --git a/renderer/src/web/price-check/filters/pseudo/reflection-rules.ts b/renderer/src/web/price-check/filters/pseudo/reflection-rules.ts new file mode 100644 index 00000000..aaa5950a --- /dev/null +++ b/renderer/src/web/price-check/filters/pseudo/reflection-rules.ts @@ -0,0 +1,50 @@ +import { stat } from '@/assets/data' +import type { StatFilter } from '../interfaces' + +interface FilterRule { + ref: string + disabled?: boolean + difficulty?: 'any' +} + +const RULES: FilterRule[] = [ + { ref: stat('Reflection of the Breachlord (Difficulty #)') }, + { ref: stat('Reflection of Delirium (Difficulty #)'), difficulty: 'any' }, + { ref: stat('Reflection of Tyranny (Difficulty #)') }, + { ref: stat('Reflection of the Trove (Difficulty #)') }, + { ref: stat('Reflection of Thralldom (Difficulty #)') }, + { ref: stat('Reflection of Phaaryl (Difficulty #)') }, + { ref: stat('Reflection of Perverted Faith (Difficulty #)') }, + { ref: stat('Reflection of Kalandra (Difficulty #)'), disabled: false }, + { ref: stat('Reflection of Experimentation (Difficulty #)') }, + { ref: stat('Reflection of the Sun (Difficulty #)'), disabled: false }, + { ref: stat('Reflection of the Monolith (Difficulty #)') }, + { ref: stat('Reflection of the Nightmare (Difficulty #)') }, + { ref: stat('Reflection of Azurite (Difficulty #)') }, + { ref: stat('Reflection of Paradise (Difficulty #)'), disabled: false }, + { ref: stat('Reflection of Angling (Difficulty #)'), disabled: false }, +] + +export function applyRules (filters: StatFilter[]) { + for (let i = 0; i < filters.length;) { + const filter = filters[i] + const rule = RULES.find(rule => rule.ref === filter.statRef) + if (!rule) { + const difficulty = filter.roll!.value + if (difficulty < 8) { + filters.splice(i, 1) + continue + } else { + filter.hidden = 'low_tier_reflection' + } + } else { + if (rule.difficulty === 'any') { + filter.roll = undefined + } + if (rule.disabled !== undefined) { + filter.disabled = rule.disabled + } + } + i += 1 + } +}