StatBetter, fix some rounding, SourceInfo

This commit is contained in:
Alexander Drozdov
2021-10-12 12:14:40 +03:00
parent eb9a02c0d8
commit f3ba29b8bf
8 changed files with 112 additions and 82 deletions
+7
View File
@@ -7,10 +7,17 @@ export interface StatMatcher {
value?: number
}
export enum StatBetter {
NegativeRoll = -1,
PositiveRoll = 1,
NotComparable = 0
}
export interface Stat {
ref: string
dp?: true
matchers: StatMatcher[]
better: StatBetter
trade: {
inverted?: true
option?: 'num' | 'str'
+3 -3
View File
@@ -137,9 +137,9 @@ export function applyIncr (mod: ModifierInfo, parsed: ParsedStat): ParsedStat |
roll: {
unscalable: roll.unscalable,
dp: roll.dp,
value: percentRoll(roll.value, rollIncr, (roll.value > 0) ? Math.floor : Math.ceil, roll.dp && DIV_BY_100),
min: percentRoll(roll.min, rollIncr, (roll.min > 0) ? Math.floor : Math.ceil, roll.dp && DIV_BY_100),
max: percentRoll(roll.max, rollIncr, (roll.max > 0) ? Math.floor : Math.ceil, roll.dp && DIV_BY_100)
value: percentRoll(roll.value, rollIncr, Math.trunc, roll.dp && DIV_BY_100),
min: percentRoll(roll.min, rollIncr, Math.trunc, roll.dp && DIV_BY_100),
max: percentRoll(roll.max, rollIncr, Math.trunc, roll.dp && DIV_BY_100)
}
}
}
+13 -4
View File
@@ -1,8 +1,8 @@
<template>
<div :class="$style['filter']">
<div :class="$style['mods']">
<div class="pl-5 pr-3 py-1" v-for="(source, idx) of filter.sources" :key="idx">
<source-info :source="source" />
<div v-if="showSourceInfo" :class="$style['mods']">
<div class="pl-5 py-1" v-for="(source, idx) of filter.sources" :key="idx">
<source-info :source="source" :filter="filter" />
</div>
</div>
<div class="flex flex-col min-w-0 flex-1">
@@ -195,7 +195,7 @@ export default defineComponent({
set (value: string) { props.filter.roll!.max = Number(value) }
}),
tag: computed(() => props.filter.tag),
changeStep: computed(() => props.filter.roll!.step),
changeStep: computed(() => props.filter.roll!.dp ? 0.01 : 1),
showInputs: computed(() => props.filter.roll != null),
fontSize: computed(() => AppConfig().fontSize),
isDisabled: computed(() => props.filter.disabled),
@@ -205,6 +205,15 @@ export default defineComponent({
showRollBounds: computed(() => props.filter.roll?.bounds != null),
isHidden: computed(() => props.filter.hidden != null),
hiddenReason: computed(() => t(props.filter.hidden!)),
showSourceInfo: computed(() =>
props.filter.sources.length &&
props.filter.option == null && (
props.filter.sources.length >= 2 ||
props.filter.sources[0].modifier.info.name != null ||
props.filter.sources[0].modifier.info.tier != null ||
props.filter.sources[0].modifier.info.rank != null
)
),
inputFocus,
toggleFilter
}
+21 -4
View File
@@ -3,7 +3,7 @@
<div :class="$style['modinfo']">{{ modText }}</div>
<div v-for="stat of stats" :key="stat.text" class="flex">
<item-modifier-text :text="stat.text" :roll="stat.roll" :class="{ 'line-through': !stat.contributes }" />
<div v-if="stat.contributes && stat.contribution" class="ml-auto">{{ stat.contribution }}</div>
<div v-if="stat.contributes && stat.contribution" :class="$style['contribution']">{{ stat.contribution }}</div>
</div>
</div>
</template>
@@ -11,10 +11,11 @@
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import type { StatCalculated } from '@/parser/modifiers'
import { applyIncr } from '@/parser/advanced-mod-desc'
import { roundRoll } from './util'
import ItemModifierText from '@/web/ui/ItemModifierText.vue'
import type { StatCalculated } from '@/parser/modifiers'
import type { StatFilter } from './interfaces'
export default defineComponent({
components: { ItemModifierText },
@@ -22,6 +23,10 @@ export default defineComponent({
source: {
type: Object as PropType<StatCalculated['sources'][number]>,
required: true
},
filter: {
type: Object as PropType<StatFilter>,
required: true
}
},
setup (props) {
@@ -47,8 +52,12 @@ export default defineComponent({
const { stats } = props.source.modifier
const { stat: contribStat } = props.source.stat
// TODO: percentRoll, isNegated
const contribution = props.source.contributes?.value
let contribution = props.source.contributes?.value
if (contribution != null) {
const filter = props.filter.roll!
contribution *= (filter.isNegated) ? -1 : 1
contribution = roundRoll(contribution, filter.dp)
}
return stats.map((parsed) => {
if (parsed.stat.ref !== contribStat.ref) {
@@ -89,6 +98,14 @@ export default defineComponent({
@apply text-gray-500;
font-style: italic;
}
.contribution {
margin-left: auto;
@apply w-12;
@apply rounded;
@apply border border-gray-700;
text-align: center;
}
</style>
<i18n>
@@ -1,11 +1,12 @@
import { ParsedItem, ItemRarity, ItemCategory } from '@/parser'
import { ModifierType, StatCalculated, StatRoll, statSourcesTotal, translateStatWithRoll } from '@/parser/modifiers'
import { ModifierType, StatCalculated, statSourcesTotal, translateStatWithRoll } from '@/parser/modifiers'
import { uniqueModFilterPartial } from './unique-roll'
import { rollToFilter, percentRoll, roundRoll } from './util'
import { percentRoll, roundRoll } from './util'
import { FilterTag, ItemHasEmptyModifier, StatFilter } from './interfaces'
import { filterPseudo } from './pseudo'
import { filterItemProp } from './pseudo/item-property'
import { filterUniqueItemProp } from './pseudo/item-property-unique'
import { StatBetter } from '@/assets/data'
export interface FiltersCreationContext {
readonly item: ParsedItem
@@ -133,7 +134,21 @@ export function calculatedStatToFilter (
) {
uniqueModFilterPartial(item, roll, filter, (opts.percent * 2), dp)
} else {
itemModFilterPartial(calc, roll, filter, opts.percent, dp)
const percent = (calc.type === ModifierType.Enchant)
? 0
: opts.percent
filter.roll = {
value: roundRoll(roll.value, dp),
min: undefined,
max: undefined,
default: {
min: percentRoll(roll.value, -percent, Math.floor, dp),
max: percentRoll(roll.value, +percent, Math.ceil, dp)
},
dp: dp,
isNegated: false
}
}
}
@@ -142,31 +157,6 @@ export function calculatedStatToFilter (
return filter
}
function itemModFilterPartial (
calc: StatCalculated,
roll: StatRoll,
filter: StatFilter,
percent: number,
dp: boolean
) {
if (roll) {
if (calc.type === ModifierType.Enchant) {
filter.roll = {
value: roundRoll(roll.value, dp),
min: percentRoll(roll.value, 0, Math.floor, dp),
max: percentRoll(roll.value, 0, Math.ceil, dp),
default: {
min: percentRoll(roll.value, 0, Math.floor, dp),
max: percentRoll(roll.value, 0, Math.ceil, dp)
},
step: dp ? 0.01 : 1
}
} else {
filter.roll = rollToFilter(roll.value, { dp: dp, percent })
}
}
}
function filterAdjustmentForNegate (
calc: StatCalculated,
negate: boolean,
@@ -176,37 +166,41 @@ function filterAdjustmentForNegate (
const { roll } = filter
if (roll.min == null && roll.max == null) {
switch (calc.stat.better) {
case StatBetter.PositiveRoll:
roll.min = roll.default.min
break
case StatBetter.NegativeRoll:
roll.max = roll.default.max
break
case StatBetter.NotComparable:
roll.min = roll.default.min
roll.max = roll.default.max
break
}
}
if (negate) {
roll.tradeInvert = true
roll.isNegated = true
const swap = JSON.parse(JSON.stringify(roll)) as typeof roll
if (roll.bounds) {
roll.bounds.min = -1 * swap.bounds!.max
roll.bounds.max = -1 * swap.bounds!.min
if (swap.bounds) {
roll.bounds!.min = -1 * swap.bounds.max
roll.bounds!.max = -1 * swap.bounds.min
}
roll.default.min = -1 * swap.default.max
roll.default.max = -1 * swap.default.min
if (roll.min == null && roll.max == null) {
// TODO: for some stats reduced is better
roll.min = -1 * swap.default.max
} else {
if (roll.max != null) {
roll.min = -1 * (swap.max as number)
}
if (roll.min != null) {
roll.max = -1 * (swap.min as number)
}
}
if (roll.value != null) {
roll.value = -1 * swap.value
}
} else {
if (roll.min == null && roll.max == null) {
// TODO: for some stats reduced is better
roll.min = roll.default.min
}
roll.value = -1 * swap.value
roll.min = (typeof swap.max === 'number')
? -1 * swap.max
: undefined
roll.max = (typeof swap.min === 'number')
? -1 * swap.min
: undefined
}
if (calc.stat.trade.inverted) {
+2 -1
View File
@@ -91,7 +91,8 @@ export interface StatFilter {
default: { min: number, max: number }
bounds?: { min: number, max: number }
tradeInvert?: boolean
step: number
dp: boolean | number
isNegated: boolean
}
option?: {
value: number // NOTE: mutable in UI
+4 -2
View File
@@ -27,7 +27,8 @@ export function uniqueModFilterPartial (
min: statRoll.value,
max: statRoll.value
},
step: dp ? 0.01 : 1
dp: dp,
isNegated: false
}
if (filter.tag !== FilterTag.Variant && filter.tag !== FilterTag.Corrupted) {
@@ -46,7 +47,8 @@ export function uniqueModFilterPartial (
min: statRoll.min,
max: statRoll.max
},
step: dp ? 0.01 : 1
dp: dp,
isNegated: false
}
}
}
+18 -18
View File
@@ -10,14 +10,16 @@ function decimalPlaces (value: number, dp: number | boolean): number {
}
}
export function roundRoll (value: number, dp: number | boolean) {
const round = Math.pow(10, decimalPlaces(value, dp))
// round value down (toward zero)
return Math.trunc(value * round) / round
}
export const roundRoll = (value: number, dp: number | boolean) =>
percentRoll(value, 0, Math.trunc, dp)
export function percentRoll (value: number, p: number, method: Math['floor'] | Math['ceil'], dp: number | boolean = false): number {
const res = value + value * p / 100
export function percentRoll (
value: number,
p: number,
method: Math['floor'] | Math['ceil'] | Math['trunc'],
dp: number | boolean = false
): number {
const res = value + Math.abs(value) * p / 100
const rounding = Math.pow(10, decimalPlaces(value, dp))
return method((res + Number.EPSILON) * rounding) / rounding
@@ -32,21 +34,19 @@ export function percentRollDelta (value: number, delta: number, p: number, metho
export function rollToFilter (
roll: number,
opts: { percent: number, neverNegated?: true, dp?: boolean | number }
opts: { percent: number, neverNegated: true, dp?: boolean | number }
): StatFilter['roll'] {
const { percent, neverNegated, dp } = opts
const { percent, dp } = opts
// opts.neverNegated is false only in one case, but keep it
// disabled by default, so opts.neverNegated acts more like
// acknowledgment of what you are doing
return {
value: roundRoll(roll, dp ?? false),
default: {
min: percentRoll(roll, -percent * Math.sign(roll), Math.floor, dp),
max: percentRoll(roll, +percent * Math.sign(roll), Math.ceil, dp)
},
min: neverNegated ? percentRoll(roll, -percent * Math.sign(roll), Math.floor, dp) : undefined,
min: percentRoll(roll, -percent, Math.floor, dp),
max: undefined,
step: dp ? 0.01 : 1
default: {
min: percentRoll(roll, -percent, Math.floor, dp),
max: percentRoll(roll, +percent, Math.ceil, dp)
},
dp: dp ?? false,
isNegated: false
}
}