Display detailed info for imported filter settings

This commit is contained in:
SpectralFlame 2023-05-13 04:07:55 -05:00 committed by cyip92
parent 5b0358bcd8
commit ed72471da9
6 changed files with 294 additions and 57 deletions

View File

@ -479,12 +479,6 @@
background: black;
}
.l-glyph-auto-pick-options__container {
display: flex;
flex-direction: row;
justify-content: center;
}
.c-glyph-auto-pick-options__option {
display: flex;
flex-direction: column;

View File

@ -1,4 +1,5 @@
<script>
import ImportFilterSingleType from "./ImportFilterSingleType";
import ModalWrapperChoice from "@/components/modals/ModalWrapperChoice";
import PrimaryButton from "@/components/PrimaryButton";
@ -6,10 +7,12 @@ export default {
name: "ImportFilterModal",
components: {
ModalWrapperChoice,
PrimaryButton
PrimaryButton,
ImportFilterSingleType
},
data() {
return {
currentSettings: {},
input: "",
};
},
@ -23,21 +26,11 @@ export default {
return false;
}
},
},
mounted() {
this.$refs.input.select();
},
methods: {
importFilter() {
if (!this.inputIsValid) return;
this.emitClose();
parsedSettings() {
if (!this.inputIsValid) return null;
const decoded = GameSaveSerializer.decodeText(this.input, "glyph filter");
const parts = decoded.split("|");
player.reality.glyphs.filter.select = Number(parts[0]);
player.reality.glyphs.filter.simple = Number(parts[1]);
player.reality.glyphs.filter.trash = Number(parts[2]);
const typeInfo = {};
let partIndex = 3;
for (const type of ALCHEMY_BASIC_GLYPH_TYPES) {
@ -52,7 +45,45 @@ export default {
};
partIndex++;
}
player.reality.glyphs.filter.types = typeInfo;
return {
select: Number(parts[0]),
simple: Number(parts[1]),
trash: Number(parts[2]),
types: typeInfo,
};
},
selectStr() {
return this.changedValue(this.parsedSettings.select, this.currentSettings.select,
x => AutoGlyphProcessor.filterModeName(x));
},
basicCountStr() {
return this.changedValue(this.parsedSettings.simple, this.currentSettings.simple, formatInt);
},
trashStr() {
return this.changedValue(this.parsedSettings.trash, this.currentSettings.trash,
x => AutoGlyphProcessor.trashModeDesc(x));
},
// Hide effarig if it hasn't been unlocked yet
availableTypes() {
return ALCHEMY_BASIC_GLYPH_TYPES.filter(t => !GlyphTypes.locked.map(e => e.id).includes(t));
}
},
mounted() {
this.$refs.input.select();
},
methods: {
update() {
this.currentSettings = JSON.parse(JSON.stringify(player.reality.glyphs.filter));
},
changedValue(oldVal, newVal, applyFn) {
if (oldVal === newVal) return "(No change)";
return `${applyFn(oldVal)}${applyFn(newVal)}`;
},
importFilter() {
if (this.parsedSettings === null) return;
this.emitClose();
player.reality.glyphs.filter = this.parsedSettings;
},
},
};
@ -80,7 +111,22 @@ export default {
<div class="c-modal-import__save-info">
<div v-if="!input" />
<div v-else-if="inputIsValid">
PLACEHOLDER FOR BEFORE/AFTER FILTER INFO
<b>Selection mode:</b> {{ selectStr }}
<br>
<b>Effect Count ("Number of Effects"):</b> {{ basicCountStr }}
<br>
<b>Rejected Glyphs:</b> {{ trashStr }}
<br>
<u><b>Type-specific Settings</b></u>
<br>
<ImportFilterSingleType
v-for="type in availableTypes"
:key="type"
class="c-single-type"
:type="type"
:curr-settings="currentSettings.types[type]"
:new-settings="parsedSettings.types[type]"
/>
</div>
<div v-else>
Not a valid Glyph filter string
@ -95,4 +141,11 @@ export default {
Import
</PrimaryButton>
</ModalWrapperChoice>
</template>
</template>
<style scoped>
.c-single-type {
left: 0;
text-align: left;
}
</style>

View File

@ -0,0 +1,173 @@
<script>
export default {
name: "ImportFilterSingleType",
props: {
type: {
type: String,
required: true,
},
currSettings: {
type: Object,
required: true,
},
newSettings: {
type: Object,
required: true,
}
},
computed: {
settingsChanged() {
return JSON.stringify(this.currSettings) !== JSON.stringify(this.newSettings);
},
symbol() {
return GLYPH_SYMBOLS[this.type];
},
capitalized() {
return `${this.type.charAt(0).toUpperCase()}${this.type.substring(1)}`;
},
rarityStr() {
return this.changedValue(this.currSettings.rarity, this.newSettings.rarity, x => formatPercents(x / 100));
},
effectStr() {
return this.changedValue(this.currSettings.effectCount, this.newSettings.effectCount, formatInt);
},
scoreStr() {
return this.changedValue(this.currSettings.score, this.newSettings.score, formatInt);
},
effectData() {
const changes = [];
for (let index = 0; index < this.currSettings.effectScores.length; index++) {
const bitmaskIndex = AutoGlyphProcessor.bitmaskIndexOffset(this.type) + index;
changes.push({
bitmaskIndex,
oldReq: (this.currSettings.specifiedMask & (1 << bitmaskIndex)) !== 0,
newReq: (this.newSettings.specifiedMask & (1 << bitmaskIndex)) !== 0,
oldScore: this.currSettings.effectScores[index],
newScore: this.newSettings.effectScores[index],
});
}
return changes;
}
},
methods: {
changedValue(oldVal, newVal, applyFn) {
if (oldVal === newVal) return applyFn(oldVal);
return `${applyFn(oldVal)}${applyFn(newVal)}`;
},
effectBox(effectEntry) {
if (effectEntry.oldReq && effectEntry.newReq) return "☑";
if (!effectEntry.oldReq && effectEntry.newReq) return "⊕";
if (effectEntry.oldReq && !effectEntry.newReq) return "⊖";
return "☒";
},
effectScoreStr(effectEntry) {
return this.changedValue(effectEntry.oldScore, effectEntry.newScore, formatInt);
},
topLevelClassObject(key) {
return {
"o-cell": true,
"o-cell--changed": this.currSettings[key] !== this.newSettings[key],
};
},
effectClassObject(effectEntry) {
return {
"o-cell": true,
"o-cell--changed": effectEntry.oldReq !== effectEntry.newReq || effectEntry.oldScore !== effectEntry.newScore,
};
}
},
};
</script>
<template>
<div>
{{ symbol }}:
<span v-if="settingsChanged">
<span class="c-single-row">
<span
class="c-rarity"
:class="topLevelClassObject('rarity')"
>
{{ rarityStr }}
</span>
<span
class="c-effects-count"
:class="topLevelClassObject('effectCount')"
>
Specified Effects: {{ effectStr }}
</span>
<span
class="c-target-score"
:class="topLevelClassObject('score')"
>
Score: {{ scoreStr }}
</span>
</span>
<br>
<span class="c-single-row">
<span
v-for="effect in effectData.slice(0, 4)"
:key="effect.bitmaskIndex"
class="c-single-score"
:class="effectClassObject(effect)"
>
{{ effectBox(effect) }} {{ effectScoreStr(effect) }}
</span>
</span>
<br>
<span
v-if="effectData.length > 4"
class="c-single-row"
>
<span
v-for="effect in effectData.slice(4)"
:key="effect.bitmaskIndex"
class="c-single-score o-cell"
:class="effectClassObject(effect)"
>
{{ effectBox(effect) }} {{ effectScoreStr(effect) }}
</span>
</span>
</span>
<span v-else>
(No changes)
</span>
</div>
</template>
<style scoped>
.c-single-row {
display: flex;
justify-content: center;
align-items: center;
margin: -2rem 0 0 3rem;
}
.o-cell {
display: flex;
justify-content: center;
align-items: center;
border: var(--var-border-width, 0.2rem) solid;
padding: 0.1rem;
}
.o-cell--changed {
background-color: var(--color-good);
}
.c-rarity {
width: 8rem;
}
.c-effects-count {
width: 22rem;
}
.c-target-score {
width: 15rem;
}
.c-single-score {
width: 10rem;
}
</style>

View File

@ -128,24 +128,7 @@ export default {
}
},
filterMode(index) {
switch (index) {
case this.modes.LOWEST_SACRIFICE:
return "Lowest Total Glyph Sacrifice";
case this.modes.EFFECT_COUNT:
return "Number of Effects";
case this.modes.RARITY_THRESHOLD:
return "Rarity Threshold";
case this.modes.SPECIFIED_EFFECT:
return "Specified Effect";
case this.modes.EFFECT_SCORE:
return "Effect Score";
case this.modes.LOWEST_ALCHEMY:
return "Lowest Alchemy Resource";
case this.modes.ALCHEMY_VALUE:
return "Refinement Value";
default:
throw Error("Unrecognized glyph filter mode");
}
return AutoGlyphProcessor.filterModeName(index);
},
isUnlocked(index) {
switch (index) {
@ -405,7 +388,7 @@ export default {
}
.l-glyph-filter-export-btn {
border: solid 0.1rem;
border: var(--var-border-width, 0.2rem) solid;
width: 3rem;
margin: 0.5rem;
padding: 0.5rem;

View File

@ -10,6 +10,9 @@ export default {
modes() {
return AUTO_GLYPH_REJECT;
},
availableModes() {
return Object.values(this.modes);
}
},
methods: {
optionClass(idx) {
@ -26,6 +29,9 @@ export default {
setMode(m) {
AutoGlyphProcessor.sacMode = m;
},
modeDesc(id) {
return AutoGlyphProcessor.trashModeDesc(id);
}
}
};
</script>
@ -38,27 +44,21 @@ export default {
<br>
<div class="l-glyph-auto-pick-options__container">
<div
:class="optionClass(modes.SACRIFICE)"
@click="setMode(modes.SACRIFICE)"
v-for="modeID in availableModes"
:key="modeID"
:class="optionClass(modeID)"
@click="setMode(modeID)"
>
Always sacrifice
</div>
<div
:class="optionClass(modes.REFINE)"
@click="setMode(modes.REFINE)"
>
Always refine
</div>
<div
:class="optionClass(modes.REFINE_TO_CAP)"
@click="setMode(modes.REFINE_TO_CAP)"
>
Refine to cap, then sacrifice
{{ modeDesc(modeID) }}
</div>
</div>
</div>
</template>
<style scoped>
.l-glyph-auto-pick-options__container {
display: flex;
flex-direction: row;
justify-content: center;
}
</style>

View File

@ -156,6 +156,40 @@ export const AutoGlyphProcessor = {
hasNegativeEffectScore() {
return this.scoreMode === AUTO_GLYPH_SCORE.EFFECT_SCORE &&
Object.values(this.types).map(t => t.effectScores.min()).min() < 0;
},
// These are here because they're used in multiple UI components
filterModeName(id) {
switch (id) {
case AUTO_GLYPH_SCORE.LOWEST_SACRIFICE:
return "Lowest Total Glyph Sacrifice";
case AUTO_GLYPH_SCORE.EFFECT_COUNT:
return "Number of Effects";
case AUTO_GLYPH_SCORE.RARITY_THRESHOLD:
return "Rarity Threshold";
case AUTO_GLYPH_SCORE.SPECIFIED_EFFECT:
return "Specified Effect";
case AUTO_GLYPH_SCORE.EFFECT_SCORE:
return "Effect Score";
case AUTO_GLYPH_SCORE.LOWEST_ALCHEMY:
return "Lowest Alchemy Resource";
case AUTO_GLYPH_SCORE.ALCHEMY_VALUE:
return "Refinement Value";
default:
return "Invalid Glyph filter mode";
}
},
trashModeDesc(id) {
switch (id) {
case AUTO_GLYPH_REJECT.SACRIFICE:
return "Always sacrifice";
case AUTO_GLYPH_REJECT.REFINE:
return "Always refine";
case AUTO_GLYPH_REJECT.REFINE_TO_CAP:
return "Refine to cap, then sacrifice";
default:
return "Invalid Glyph trash mode";
}
}
};