mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2026-09-26 06:35:45 +00:00
map check changes
This commit is contained in:
+7
-21
@@ -62,7 +62,7 @@ type WidgetWellKnownFlag =
|
||||
'hide-on-focus'
|
||||
|
||||
export const defaultConfig: Config = {
|
||||
configVersion: 7,
|
||||
configVersion: 8,
|
||||
priceCheckKey: 'D',
|
||||
priceCheckKeyHold: 'Ctrl',
|
||||
priceCheckLocked: 'Ctrl + Alt + D',
|
||||
@@ -148,41 +148,27 @@ export const defaultConfig: Config = {
|
||||
wmZorder: 'exclusive',
|
||||
wmFlags: ['hide-on-blur', 'skip-menu'],
|
||||
maps: {
|
||||
showNewStats: false,
|
||||
selectedStats: [
|
||||
{
|
||||
matcher: 'Slaying Enemies close together has a #% chance to attract monsters from Beyond',
|
||||
invert: false,
|
||||
valueWarning: '',
|
||||
valueDanger: '',
|
||||
valueDesirable: '+'
|
||||
decision: 'desirable'
|
||||
},
|
||||
{
|
||||
matcher: '#% maximum Player Resistances',
|
||||
invert: true,
|
||||
valueWarning: '-10',
|
||||
valueDanger: '',
|
||||
valueDesirable: ''
|
||||
decision: 'warning'
|
||||
},
|
||||
{
|
||||
matcher: 'Monsters reflect #% of Physical Damage',
|
||||
invert: false,
|
||||
valueWarning: '',
|
||||
valueDanger: '+',
|
||||
valueDesirable: ''
|
||||
decision: 'danger'
|
||||
},
|
||||
{
|
||||
matcher: 'Monsters reflect #% of Elemental Damage',
|
||||
invert: false,
|
||||
valueWarning: '',
|
||||
valueDanger: '+',
|
||||
valueDesirable: ''
|
||||
decision: 'danger'
|
||||
},
|
||||
{
|
||||
matcher: 'Area contains two Unique Bosses',
|
||||
invert: false,
|
||||
valueWarning: '',
|
||||
valueDanger: '',
|
||||
valueDesirable: '+'
|
||||
decision: 'desirable'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+16
-1
@@ -118,7 +118,7 @@ export const config = (() => {
|
||||
if (config.configVersion < 7) {
|
||||
const mapCheck = config.widgets.find(w => w.wmType === 'map-check')!
|
||||
mapCheck.wmType = 'item-check'
|
||||
;(mapCheck as ItemCheckWidget).maps = { selectedStats: mapCheck.selectedStats }
|
||||
mapCheck.maps = { selectedStats: mapCheck.selectedStats }
|
||||
mapCheck.selectedStats = undefined
|
||||
|
||||
config.itemCheckKey = (config as any).mapCheckKey || null
|
||||
@@ -127,6 +127,21 @@ export const config = (() => {
|
||||
config.configVersion = 7
|
||||
}
|
||||
|
||||
if (config.configVersion < 8) {
|
||||
const itemCheck = config.widgets.find(w => w.wmType === 'item-check')!
|
||||
;(itemCheck as ItemCheckWidget).maps.showNewStats = false
|
||||
itemCheck.maps.selectedStats = (itemCheck as ItemCheckWidget).maps.selectedStats.map(entry => ({
|
||||
matcher: entry.matcher,
|
||||
decision:
|
||||
(entry as any).valueDanger ? 'danger'
|
||||
: (entry as any).valueWarning ? 'warning'
|
||||
: (entry as any).valueDesirable ? 'desirable'
|
||||
: 'seen'
|
||||
}))
|
||||
|
||||
config.configVersion = 8
|
||||
}
|
||||
|
||||
store.store = config
|
||||
return store
|
||||
})()
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
<div class="flex">
|
||||
<button @click="handleClick"
|
||||
class="px-2 leading-none py-2 m-0 text-left flex-1 flex items-center overflow-hidden"
|
||||
:class="state === 'danger' ? 'bg-red-700'
|
||||
: state === 'warning' ? 'bg-orange-600'
|
||||
: state === 'desirable' ? 'bg-green-700'
|
||||
:class="decision === 'danger' ? 'bg-red-700'
|
||||
: decision === 'warning' ? 'bg-orange-600'
|
||||
: decision === 'desirable' ? 'bg-green-700'
|
||||
: 'hover:bg-gray-700'">
|
||||
<template v-if="true">
|
||||
<i v-if="!state || state === 'not-matched'"
|
||||
<i v-if="!decision || decision === 'seen'"
|
||||
class="inline-block mr-2" style="min-width: 1rem;">{{ '\u2009' }}</i>
|
||||
<i v-else
|
||||
class="fas mr-2 text-center" style="min-width: 1rem;"
|
||||
:class="state === 'danger' ? 'fa-skull-crossbones'
|
||||
: state === 'warning' ? 'fa-exclamation-triangle'
|
||||
:class="decision === 'danger' ? 'fa-skull-crossbones'
|
||||
: decision === 'warning' ? 'fa-exclamation-triangle'
|
||||
: 'fa-check'"></i>
|
||||
</template>
|
||||
<item-modifier-text :text="stat.matcher" :roll="stat.roll" class="truncate" />
|
||||
</button>
|
||||
<div class="flex leading-none items-center text-gray-600 w-8 text-center justify-center">
|
||||
<i v-if="state === 'not-matched'" class="fas fa-eye-slash"></i>
|
||||
</div>
|
||||
<button @click="toggleSeenStatus" class="flex leading-none items-center text-gray-600 w-8 text-center justify-center">
|
||||
<i v-if="showNewStatIcon" class="fas fa-eye-slash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -42,89 +42,47 @@ export default defineComponent({
|
||||
const config = computed(() => {
|
||||
return Config.store.widgets.find(widget => widget.wmType === 'item-check') as ItemCheckWidget
|
||||
})
|
||||
|
||||
const entryInSelected = computed(() => {
|
||||
const entry = computed(() => {
|
||||
return config.value.maps.selectedStats.find(_ => _.matcher === props.stat.matcher)
|
||||
})
|
||||
|
||||
const state = computed(() => {
|
||||
if (!entryInSelected.value) return undefined
|
||||
|
||||
const valueDanger = Number(entryInSelected.value.valueDanger || 'NaN')
|
||||
const valueWarning = Number(entryInSelected.value.valueWarning || 'NaN')
|
||||
const valueDesirable = Number(entryInSelected.value.valueDesirable || 'NaN')
|
||||
|
||||
if (entryInSelected.value.valueDanger !== '' && Number.isNaN(valueDanger)) {
|
||||
return 'danger'
|
||||
}
|
||||
if (entryInSelected.value.valueWarning !== '' && Number.isNaN(valueWarning)) {
|
||||
return 'warning'
|
||||
}
|
||||
if (entryInSelected.value.valueDesirable !== '' && Number.isNaN(valueDesirable)) {
|
||||
return 'desirable'
|
||||
}
|
||||
|
||||
if (!entryInSelected.value.invert) {
|
||||
if (!Number.isNaN(valueDanger) && props.stat.roll! >= valueDanger) {
|
||||
return 'danger'
|
||||
}
|
||||
if (!Number.isNaN(valueWarning) && props.stat.roll! >= valueWarning) {
|
||||
return 'warning'
|
||||
}
|
||||
if (!Number.isNaN(valueDesirable) && props.stat.roll! >= valueDesirable) {
|
||||
return 'desirable'
|
||||
}
|
||||
} else {
|
||||
if (!Number.isNaN(valueDanger) && props.stat.roll! <= valueDanger) {
|
||||
return 'danger'
|
||||
}
|
||||
if (!Number.isNaN(valueWarning) && props.stat.roll! <= valueWarning) {
|
||||
return 'warning'
|
||||
}
|
||||
if (!Number.isNaN(valueDesirable) && props.stat.roll! <= valueDesirable) {
|
||||
return 'desirable'
|
||||
}
|
||||
}
|
||||
|
||||
return 'not-matched'
|
||||
const showNewStatIcon = computed(() => {
|
||||
return config.value.maps.showNewStats && !entry.value
|
||||
})
|
||||
|
||||
const canCycle = computed(() => {
|
||||
const values = [
|
||||
entryInSelected.value!.valueDanger,
|
||||
entryInSelected.value!.valueWarning,
|
||||
entryInSelected.value!.valueDesirable
|
||||
]
|
||||
return (
|
||||
values.filter(_ => _ === '+').length === 1 &&
|
||||
values.filter(_ => _ === '').length === 2
|
||||
)
|
||||
})
|
||||
function toggleSeenStatus () {
|
||||
if (!config.value.maps.showNewStats) return
|
||||
|
||||
if (!entry.value) {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.stat.matcher,
|
||||
decision: 'seen'
|
||||
})
|
||||
} else if (entry.value.decision === 'seen') {
|
||||
config.value.maps.selectedStats = config.value.maps.selectedStats.filter(selected => selected !== entry.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
decision: computed(() => entry.value?.decision),
|
||||
showNewStatIcon,
|
||||
toggleSeenStatus,
|
||||
handleClick () {
|
||||
if (!entryInSelected.value) {
|
||||
if (!entry.value) {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.stat.matcher,
|
||||
invert: false,
|
||||
valueDanger: '+',
|
||||
valueWarning: '',
|
||||
valueDesirable: ''
|
||||
decision: 'danger'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!canCycle.value) return
|
||||
|
||||
if (entryInSelected.value.valueDanger === '+') {
|
||||
entryInSelected.value.valueDanger = ''
|
||||
entryInSelected.value.valueWarning = '+'
|
||||
} else if (entryInSelected.value.valueWarning === '+') {
|
||||
entryInSelected.value.valueWarning = ''
|
||||
entryInSelected.value.valueDesirable = '+'
|
||||
} else if (entryInSelected.value.valueDesirable === '+') {
|
||||
config.value.maps.selectedStats = config.value.maps.selectedStats.filter(selected => selected !== entryInSelected.value)
|
||||
} else {
|
||||
if (entry.value.decision === 'danger') {
|
||||
entry.value.decision = 'warning'
|
||||
} else if (entry.value.decision === 'warning') {
|
||||
entry.value.decision = 'desirable'
|
||||
} else if (entry.value.decision === 'desirable') {
|
||||
entry.value.decision = 'seen'
|
||||
} else if (entry.value.decision === 'seen') {
|
||||
entry.value.decision = 'danger'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,12 +53,10 @@ export interface PriceCheckWidget extends Widget {
|
||||
|
||||
export interface ItemCheckWidget extends Widget {
|
||||
maps: {
|
||||
showNewStats: boolean
|
||||
selectedStats: Array<{
|
||||
matcher: string
|
||||
invert: boolean
|
||||
valueWarning: string
|
||||
valueDanger: string
|
||||
valueDesirable: string
|
||||
decision: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<template>
|
||||
<div class="flex py-1 w-full" :class="$style.row">
|
||||
<div class="flex-1 truncate px-2">{{ matcher }}</div>
|
||||
<div class="flex" :class="{ [$style.controlsAutoHide]: !entryInSelected }">
|
||||
<div class="pr-1"><ui-toggle v-model="invert" /></div>
|
||||
<div><input v-model.trim="valueWarning" @focus="handleFocus($event, 'valueWarning')" :placeholder="t(!invert ? 'min' : 'max')" class="bg-gray-900 w-12 text-center rounded-l"></div>
|
||||
<div><input v-model.trim="valueDanger" @focus="handleFocus($event, 'valueDanger')" :placeholder="t(!invert ? 'min' : 'max')" class="bg-gray-900 w-12 text-center mx-px"></div>
|
||||
<div><input v-model.trim="valueDesirable" @focus="handleFocus($event, 'valueDesirable')" :placeholder="t(!invert ? 'min' : 'max')" class="bg-gray-900 w-12 text-center rounded-r"></div>
|
||||
<div class="flex" :class="{ [$style.controlsAutoHide]: !removable }">
|
||||
<ui-radio v-model="decision" value="warning" class="pl-1 w-7 mx-2"></ui-radio>
|
||||
<ui-radio v-model="decision" value="danger" class="pl-1 w-7 mx-2"></ui-radio>
|
||||
<ui-radio v-model="decision" value="desirable" class="pl-1 w-7 mx-2"></ui-radio>
|
||||
<div class="flex w-6">
|
||||
<button v-if="entryInSelected"
|
||||
<button v-if="removable"
|
||||
@click="remove"
|
||||
class="mx-1 leading-none flex items-center"><i class="fas fa-times w-4"></i></button>
|
||||
</div>
|
||||
@@ -16,8 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, nextTick } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import { Config } from '@/web/Config'
|
||||
import { ItemCheckWidget } from '../overlay/interfaces'
|
||||
|
||||
@@ -27,105 +25,47 @@ export default defineComponent({
|
||||
matcher: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
autoRemove: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const config = computed(() => {
|
||||
return Config.store.widgets.find(widget => widget.wmType === 'item-check') as ItemCheckWidget
|
||||
})
|
||||
const entryInSelected = computed(() => {
|
||||
const entry = computed(() => {
|
||||
return config.value.maps.selectedStats.find(_ => _.matcher === props.matcher)
|
||||
})
|
||||
|
||||
const invert = computed<boolean>({
|
||||
get () { return entryInSelected.value?.invert ?? false },
|
||||
set (value) { setProp('invert', value) }
|
||||
})
|
||||
const valueWarning = computed<string>({
|
||||
get () { return entryInSelected.value?.valueWarning ?? '' },
|
||||
set (value) { setProp('valueWarning', value) }
|
||||
})
|
||||
const valueDanger = computed<string>({
|
||||
get () { return entryInSelected.value?.valueDanger ?? '' },
|
||||
set (value) { setProp('valueDanger', value) }
|
||||
})
|
||||
const valueDesirable = computed<string>({
|
||||
get () { return entryInSelected.value?.valueDesirable ?? '' },
|
||||
set (value) { setProp('valueDesirable', value) }
|
||||
})
|
||||
|
||||
function setProp<T extends keyof ItemCheckWidget['maps']['selectedStats'][number]> (
|
||||
key: T,
|
||||
value: ItemCheckWidget['maps']['selectedStats'][number][T]
|
||||
) {
|
||||
if (entryInSelected.value) {
|
||||
entryInSelected.value[key] = value
|
||||
if (props.autoRemove) {
|
||||
removeIfNotUsed()
|
||||
const decision = computed<undefined | string>({
|
||||
get () {
|
||||
return entry.value?.decision
|
||||
},
|
||||
set (value) {
|
||||
if (entry.value) {
|
||||
entry.value.decision = value!
|
||||
} else {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.matcher,
|
||||
decision: value!
|
||||
})
|
||||
}
|
||||
} else {
|
||||
config.value.maps.selectedStats.push({
|
||||
matcher: props.matcher,
|
||||
invert: false,
|
||||
valueWarning: '',
|
||||
valueDanger: '',
|
||||
valueDesirable: '',
|
||||
...{ [key]: value }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function removeIfNotUsed () {
|
||||
if (
|
||||
entryInSelected.value &&
|
||||
!entryInSelected.value.invert &&
|
||||
entryInSelected.value.valueWarning === '' &&
|
||||
entryInSelected.value.valueDanger === '' &&
|
||||
entryInSelected.value.valueDesirable === ''
|
||||
) {
|
||||
remove()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function remove () {
|
||||
if (!entryInSelected.value) return
|
||||
|
||||
config.value.maps.selectedStats = config.value.maps.selectedStats
|
||||
.filter(selected => selected !== entryInSelected.value)
|
||||
}
|
||||
|
||||
function handleFocus (e: FocusEvent, type: 'valueWarning' | 'valueDanger' | 'valueDesirable') {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (target.value === '') {
|
||||
;({
|
||||
valueWarning,
|
||||
valueDanger,
|
||||
valueDesirable
|
||||
})[type].value = '+'
|
||||
|
||||
nextTick(() => {
|
||||
target.select()
|
||||
})
|
||||
} else {
|
||||
target.select()
|
||||
if (entry.value) {
|
||||
decision.value = 'seen'
|
||||
}
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
const removable = computed(() => {
|
||||
return entry.value && decision.value !== 'seen'
|
||||
})
|
||||
|
||||
return {
|
||||
t,
|
||||
entryInSelected,
|
||||
invert,
|
||||
valueWarning,
|
||||
valueDanger,
|
||||
valueDesirable,
|
||||
remove,
|
||||
handleFocus
|
||||
entry,
|
||||
decision,
|
||||
removable,
|
||||
remove
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
+20
-24
@@ -3,27 +3,16 @@
|
||||
<div class="p-1 flex">
|
||||
<input :placeholder="t('Search') + '...'" v-model="search" class="bg-gray-900 rounded px-1">
|
||||
<ui-toggle v-model="onlySelected" class="mx-2">{{ t('Only selected') }}</ui-toggle>
|
||||
<ui-popover>
|
||||
<template #target>
|
||||
<div class="flex items-center justify-center">
|
||||
<i class="fas fa-question-circle leading-none mr-1"></i>{{ t('help') }}</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="flex flex-col justify-center text-base"
|
||||
v-html="t('help-text')">
|
||||
</div>
|
||||
</template>
|
||||
</ui-popover>
|
||||
<ui-toggle v-model="showNewStats" class="ml-12">{{ t('Show new stats') }}</ui-toggle>
|
||||
</div>
|
||||
<div class="flex font-bold py-1 shadow">
|
||||
<div class="flex-1 px-2">{{ t('Stat (found: {0})', [filteredStats.length]) }}</div>
|
||||
<div class="flex" style="padding-right: calc(0.875rem + 1.5rem);">
|
||||
<div class="px-2">{{ t('Invert') }}</div>
|
||||
<div class="w-12 bg-orange-600 rounded-l leading-none flex items-center justify-center">
|
||||
<div class="w-8 mx-1 leading-none flex items-center justify-center bg-orange-600">
|
||||
<i class="fas fa-exclamation-triangle"></i></div>
|
||||
<div class="w-12 bg-red-700 mx-px leading-none flex items-center justify-center">
|
||||
<div class="w-8 mx-0 leading-none flex items-center justify-center bg-red-700">
|
||||
<i class="fas fa-skull-crossbones"></i></div>
|
||||
<div class="w-12 bg-green-700 rounded-r leading-none flex items-center justify-center">
|
||||
<div class="w-8 mx-1 leading-none flex items-center justify-center bg-green-700">
|
||||
<i class="fas fa-check"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,8 +25,7 @@
|
||||
>
|
||||
<maps-stat-entry
|
||||
:style="{ position: 'absolute', top: `${props.top}px` }"
|
||||
:matcher="props.item.matchStr"
|
||||
:auto-remove="!onlySelected" />
|
||||
:matcher="props.item.matchStr" />
|
||||
</virtual-scroll>
|
||||
</div>
|
||||
</template>
|
||||
@@ -70,19 +58,32 @@ export default defineComponent({
|
||||
return Config.store.widgets.find(widget => widget.wmType === 'item-check') as ItemCheckWidget
|
||||
})
|
||||
|
||||
const selectedMatchers = computed(() => {
|
||||
return new Set(
|
||||
config.value.maps.selectedStats
|
||||
.filter(entry => entry.decision !== 'seen')
|
||||
.map(entry => entry.matcher))
|
||||
})
|
||||
|
||||
const showNewStats = computed<boolean>({
|
||||
get () { return config.value.maps.showNewStats },
|
||||
set (value) { config.value.maps.showNewStats = value }
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
return {
|
||||
t,
|
||||
search,
|
||||
onlySelected,
|
||||
showNewStats,
|
||||
filteredStats: computed(() => {
|
||||
const q = search.value.toLowerCase().split(' ')
|
||||
|
||||
return statList.value.filter(stat =>
|
||||
q.every(part => stat.searchStr.includes(part)) &&
|
||||
(onlySelected.value
|
||||
? (config.value.maps.selectedStats.some(selected => selected.matcher === stat.matchStr))
|
||||
? selectedMatchers.value.has(stat.matchStr)
|
||||
: true)
|
||||
)
|
||||
}),
|
||||
@@ -96,15 +97,10 @@ export default defineComponent({
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"help-text": "- Use \"Invert\" toggle on stats like \"-7% maximum Player Resistances\".<br>- Non-numeric values are valid (for example, \"+\"), it just means<br>highlight stat without taking into account rolled value."
|
||||
},
|
||||
"ru": {
|
||||
"Only selected": "Только выбранные",
|
||||
"help": "справка",
|
||||
"Stat (found: {0})": "Свойства (найдено: {0})",
|
||||
"Invert": "Инвертировать",
|
||||
"help-text": "- Используйте переключатель \"Инвертировать\" на таких свойствах как \"-7% максимум сопротивлений игроков\".<br>- Нечисловые значения действительны (например, \"+\"), это просто означает<br>подсветить свойство не обращая внимание на ролл."
|
||||
"Show new stats": "Показывать новые статы"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
Reference in New Issue
Block a user