diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchByType.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchByType.kt index b4352d6902..c28abea392 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchByType.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchByType.kt @@ -11,5 +11,6 @@ package com.cobblemon.mod.common.api.pokedex.filter enum class SearchByType { SPECIES, ABILITIES, + MOVES, DROPS; } \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchFilter.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchFilter.kt index 5bcd6d2744..cf1437991b 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchFilter.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SearchFilter.kt @@ -9,14 +9,21 @@ package com.cobblemon.mod.common.api.pokedex.filter import com.cobblemon.mod.common.api.drop.ItemDropEntry +import com.cobblemon.mod.common.api.moves.MoveTemplate import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry import com.cobblemon.mod.common.api.pokemon.PokemonSpecies +import com.cobblemon.mod.common.api.pokemon.evolution.Evolution +import com.cobblemon.mod.common.api.tms.TechnicalMachines +import com.cobblemon.mod.common.client.CobblemonClient import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility +import com.cobblemon.mod.common.pokemon.FormData +import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace import com.cobblemon.mod.common.util.asTranslated import com.cobblemon.mod.common.util.itemRegistry import net.minecraft.client.Minecraft +import net.minecraft.resources.ResourceLocation import net.minecraft.world.item.ItemStack /** @@ -47,6 +54,23 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString: } return abilityList.any { it.contains(searchString.trim().lowercase()) } } + SearchByType.MOVES -> { + if (pokedexManager.getHighestKnowledgeFor(entry) !== PokedexEntryProgress.CAUGHT) return false + val search = searchString.trim().lowercase() + val learnedTMs = CobblemonClient.clientTMMoveData.learnedTMs + val speciesLevels = CobblemonClient.clientSpeciesLevelData.speciesLevels + val forms = pokedexManager.getCaughtForms(entry) + val formData = if (forms.isEmpty()) { + listOf(species.standardForm) + } else { + forms.map { form -> + species.forms.find { it.name.equals(form.displayForm, ignoreCase = true) } ?: species.standardForm + } + } + return formData.any { form -> + hasDiscoveredMove(form, search, speciesLevels, learnedTMs) + } + } SearchByType.DROPS -> { if (pokedexManager.getHighestKnowledgeFor(entry) !== PokedexEntryProgress.CAUGHT) return false val dropsList = mutableListOf() @@ -68,4 +92,132 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString: } } -} \ No newline at end of file + private fun hasDiscoveredMove( + form: FormData, + search: String, + speciesLevels: Map, + learnedTMs: Set + ): Boolean { + val evolutionMoveLevels = buildEvolutionMoveLevelIndex(form) + + fun matches(move: MoveTemplate): Boolean { + return move.displayName.string.lowercase().contains(search) + } + + fun isLevelUpDiscovered(move: MoveTemplate, level: Int): Boolean { + val currentLevel = speciesLevels[form.species.resourceIdentifier] ?: 0 + if (currentLevel >= level) return true + + for ((evolutionSpeciesId, moveLevels) in evolutionMoveLevels) { + val evolutionLevel = moveLevels[move.name] ?: continue + val evolutionHighest = speciesLevels[evolutionSpeciesId] ?: 0 + if (evolutionHighest >= evolutionLevel) return true + } + return false + } + + form.moves.levelUpMoves.forEach { (level, moves) -> + for (move in moves) { + if (matches(move) && isLevelUpDiscovered(move, level)) return true + } + } + + form.moves.tmMoves.forEach { move -> + val tmId = TechnicalMachines.moveToTM[move]?.id + val discovered = tmId == null || tmId in learnedTMs + if (discovered && matches(move)) return true + } + + val alwaysDiscovered = sequenceOf( + form.moves.tutorMoves, + form.moves.eggMoves, + form.moves.evolutionMoves, + form.moves.formChangeMoves, + form.moves.specialMoves, + form.moves.legacyMoves + ) + + for (moves in alwaysDiscovered) { + for (move in moves) { + if (matches(move)) return true + } + } + + return false + } + + private fun buildEvolutionMoveLevelIndex(form: FormData): Map> { + val evolutionForms = collectEvolutionForms(form) + val levelsBySpecies = mutableMapOf>() + + for (evolutionForm in evolutionForms) { + val speciesId = evolutionForm.species.resourceIdentifier + val moveLevels = levelsBySpecies.getOrPut(speciesId) { mutableMapOf() } + buildMoveLevelIndex(evolutionForm).forEach { (moveName, level) -> + val current = moveLevels[moveName] + if (current == null || level < current) { + moveLevels[moveName] = level + } + } + } + + return levelsBySpecies + } + + private fun buildMoveLevelIndex(form: FormData): Map { + val levels = mutableMapOf() + form.moves.levelUpMoves.forEach { (level, moves) -> + moves.forEach { move -> + val current = levels[move.name] + if (current == null || level < current) { + levels[move.name] = level + } + } + } + return levels + } + + private fun collectEvolutionForms(rootForm: FormData): List { + val results = mutableListOf() + val visited = mutableSetOf() + + fun key(form: FormData): String { + return "${form.species.resourceIdentifier}|${form.name.lowercase()}" + } + + fun nextEvolutions(current: FormData): Set { + return if (current.evolutions.isNotEmpty()) { + current.evolutions + } else { + current.species.evolutions + } + } + + fun traverse(current: FormData) { + for (evolution in nextEvolutions(current)) { + val evolutionForm = resolveEvolutionForm(evolution) ?: continue + val evolutionKey = key(evolutionForm) + if (!visited.add(evolutionKey)) continue + results.add(evolutionForm) + traverse(evolutionForm) + } + } + + traverse(rootForm) + return results + } + + private fun resolveEvolutionForm(evolution: Evolution): FormData? { + val speciesId = evolution.result.species?.asIdentifierDefaultingNamespace() ?: return null + val species = PokemonSpecies.getByIdentifier(speciesId) ?: return null + val formId = evolution.result.form + return if (formId == null) { + species.standardForm + } else { + species.forms.firstOrNull { + it.formOnlyShowdownId().equals(formId, ignoreCase = true) || it.name.equals(formId, ignoreCase = true) + } ?: species.standardForm + } + } + +} diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SecondaryPokedexFilter.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SecondaryPokedexFilter.kt new file mode 100644 index 0000000000..96a575cdef --- /dev/null +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/pokedex/filter/SecondaryPokedexFilter.kt @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2023 Cobblemon Contributors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package com.cobblemon.mod.common.api.pokedex.filter + +import com.cobblemon.mod.common.api.moves.MoveTemplate +import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager +import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress +import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry +import com.cobblemon.mod.common.api.pokemon.PokemonSpecies +import com.cobblemon.mod.common.api.pokemon.evolution.Evolution +import com.cobblemon.mod.common.api.tms.TechnicalMachines +import com.cobblemon.mod.common.client.CobblemonClient +import com.cobblemon.mod.common.pokemon.FormData +import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace +import net.minecraft.resources.ResourceLocation + +enum class SecondaryPokedexFilterType { + ALL, + CAUGHT, + SEEN, + UNDISCOVERED, + LEVEL_UP_TM_UNDISCOVERED +} + +class SecondaryPokedexFilter( + private val pokedexManager: AbstractPokedexManager, + private val filterType: SecondaryPokedexFilterType +) : EntryFilter() { + + override fun test(entry: PokedexEntry): Boolean { + return when (filterType) { + SecondaryPokedexFilterType.ALL -> true + SecondaryPokedexFilterType.CAUGHT -> pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.CAUGHT + SecondaryPokedexFilterType.SEEN -> pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.ENCOUNTERED + SecondaryPokedexFilterType.UNDISCOVERED -> pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.NONE + SecondaryPokedexFilterType.LEVEL_UP_TM_UNDISCOVERED -> hasUndiscoveredLevelUpTM(entry) + } + } + + private fun hasUndiscoveredLevelUpTM(entry: PokedexEntry): Boolean { + if (pokedexManager.getHighestKnowledgeFor(entry) != PokedexEntryProgress.CAUGHT) return false + val species = PokemonSpecies.getByIdentifier(entry.speciesId) ?: return false + val speciesLevels = CobblemonClient.clientSpeciesLevelData.speciesLevels + val forms = pokedexManager.getCaughtForms(entry) + val formData = if (forms.isEmpty()) { + listOf(species.standardForm) + } else { + forms.map { form -> + species.forms.find { it.name.equals(form.displayForm, ignoreCase = true) } ?: species.standardForm + } + } + + return formData.any { form -> + hasUndiscoveredLevelUpTM(form, speciesLevels) + } + } + + private fun hasUndiscoveredLevelUpTM( + form: FormData, + speciesLevels: Map + ): Boolean { + val evolutionMoveLevels = buildEvolutionMoveLevelIndex(form) + + fun isLevelUpDiscovered(move: MoveTemplate, level: Int): Boolean { + val currentLevel = speciesLevels[form.species.resourceIdentifier] ?: 0 + if (currentLevel >= level) return true + + for ((evolutionSpeciesId, moveLevels) in evolutionMoveLevels) { + val evolutionLevel = moveLevels[move.name] ?: continue + val evolutionHighest = speciesLevels[evolutionSpeciesId] ?: 0 + if (evolutionHighest >= evolutionLevel) return true + } + + return false + } + + form.moves.levelUpMoves.forEach { (level, moves) -> + for (move in moves) { + if (TechnicalMachines.moveToTM[move] != null && !isLevelUpDiscovered(move, level)) { + return true + } + } + } + + return false + } + + private fun buildEvolutionMoveLevelIndex(form: FormData): Map> { + val evolutionForms = collectEvolutionForms(form) + val levelsBySpecies = mutableMapOf>() + + for (evolutionForm in evolutionForms) { + val speciesId = evolutionForm.species.resourceIdentifier + val moveLevels = levelsBySpecies.getOrPut(speciesId) { mutableMapOf() } + buildMoveLevelIndex(evolutionForm).forEach { (moveName, level) -> + val current = moveLevels[moveName] + if (current == null || level < current) { + moveLevels[moveName] = level + } + } + } + + return levelsBySpecies + } + + private fun buildMoveLevelIndex(form: FormData): Map { + val levels = mutableMapOf() + form.moves.levelUpMoves.forEach { (level, moves) -> + moves.forEach { move -> + val current = levels[move.name] + if (current == null || level < current) { + levels[move.name] = level + } + } + } + return levels + } + + private fun collectEvolutionForms(rootForm: FormData): List { + val results = mutableListOf() + val visited = mutableSetOf() + + fun key(form: FormData): String { + return "${form.species.resourceIdentifier}|${form.name.lowercase()}" + } + + fun nextEvolutions(current: FormData): Set { + return if (current.evolutions.isNotEmpty()) { + current.evolutions + } else { + current.species.evolutions + } + } + + fun traverse(current: FormData) { + for (evolution in nextEvolutions(current)) { + val evolutionForm = resolveEvolutionForm(evolution) ?: continue + val evolutionKey = key(evolutionForm) + if (!visited.add(evolutionKey)) continue + results.add(evolutionForm) + traverse(evolutionForm) + } + } + + traverse(rootForm) + return results + } + + private fun resolveEvolutionForm(evolution: Evolution): FormData? { + val speciesId = evolution.result.species?.asIdentifierDefaultingNamespace() ?: return null + val species = PokemonSpecies.getByIdentifier(speciesId) ?: return null + val formId = evolution.result.form + return if (formId == null) { + species.standardForm + } else { + species.forms.firstOrNull { + it.formOnlyShowdownId().equals(formId, ignoreCase = true) || it.name.equals(formId, ignoreCase = true) + } ?: species.standardForm + } + } +} diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/PokedexGUI.kt b/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/PokedexGUI.kt index 9500700d13..31da2fae81 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/PokedexGUI.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/PokedexGUI.kt @@ -22,6 +22,8 @@ import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm import com.cobblemon.mod.common.api.pokedex.filter.EntryFilter import com.cobblemon.mod.common.api.pokedex.filter.SearchByType import com.cobblemon.mod.common.api.pokedex.filter.SearchFilter +import com.cobblemon.mod.common.api.pokedex.filter.SecondaryPokedexFilter +import com.cobblemon.mod.common.api.pokedex.filter.SecondaryPokedexFilterType import com.cobblemon.mod.common.api.pokemon.PokemonSpecies import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager import com.cobblemon.mod.common.api.text.bold @@ -84,6 +86,7 @@ class PokedexGUI private constructor( private val arrowDownIcon = cobblemonResource("textures/gui/pokedex/arrow_down.png") private val tabSelectArrow = cobblemonResource("textures/gui/pokedex/select_arrow.png") + private val secondaryFilterIcon = cobblemonResource("textures/gui/pokedex/filter_icon_button.png") private val tabIcons = arrayOf( cobblemonResource("textures/gui/pokedex/tab_info.png"), cobblemonResource("textures/gui/pokedex/tab_abilities.png"), @@ -129,11 +132,13 @@ class PokedexGUI private constructor( private lateinit var regionSelectWidgetUp: ScaledButton private lateinit var regionSelectWidgetDown: ScaledButton private lateinit var searchByTypeButton: ScaledButton + private lateinit var secondaryFilterButton: ScaledButton private lateinit var scrollScreen: EntriesScrollingWidget private lateinit var pokemonInfoWidget: PokemonInfoWidget private lateinit var searchWidget: SearchWidget private var selectedSearchByType: SearchByType = SearchByType.SPECIES + private var selectedSecondaryFilter: SecondaryPokedexFilterType = SecondaryPokedexFilterType.ALL private val tabButtons: MutableList = mutableListOf() lateinit var tabInfoElement: GuiEventListener @@ -165,7 +170,7 @@ class PokedexGUI private constructor( displaytabInfoElement(tabInfoIndex, false) if (::searchWidget.isInitialized) removeWidget(searchWidget) - searchWidget = SearchWidget(x + 26, y + 28, 128, HEADER_BAR_HEIGHT, update = ::updateFilters) + searchWidget = SearchWidget(x + 26, y + 28, 120, HEADER_BAR_HEIGHT, update = ::updateFilters) addRenderableWidget(searchWidget) if (::regionSelectWidgetUp.isInitialized) removeWidget(regionSelectWidgetUp) @@ -210,6 +215,23 @@ class PokedexGUI private constructor( ) addRenderableWidget(searchByTypeButton) + if (::secondaryFilterButton.isInitialized) removeWidget(secondaryFilterButton) + secondaryFilterButton = ScaledButton( + buttonX = (x + 146.5).toFloat(), + buttonY = (y + 29.5).toFloat(), + buttonWidth = 16, + buttonHeight = 16, + scale = SCALE, + resource = secondaryFilterIcon, + clickAction = { + val filters = SecondaryPokedexFilterType.entries.toList() + val selectedIndex = filters.indexOf(selectedSecondaryFilter) + selectedSecondaryFilter = filters[if (selectedIndex == filters.lastIndex) 0 else (selectedIndex + 1)] + updateFilters() + } + ) + addRenderableWidget(secondaryFilterButton) + updateFilters(true) } @@ -333,6 +355,18 @@ class PokedexGUI private constructor( -14 ) } + + if (secondaryFilterButton.isButtonHovered(mouseX, mouseY)) { + val filterText = lang("ui.pokedex.filter.${selectedSecondaryFilter.name.lowercase()}").bold() + renderTooltip( + context, + filterText, + mouseX, + mouseY, + delta, + -14 + ) + } } override fun onClose() { @@ -443,6 +477,7 @@ class PokedexGUI private constructor( fun getFilters(): Collection { val filters: MutableList = mutableListOf() + filters.add(SecondaryPokedexFilter(CobblemonClient.clientPokedexData, selectedSecondaryFilter)) filters.add(SearchFilter(CobblemonClient.clientPokedexData, searchWidget.value, selectedSearchByType)) return filters diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/widgets/MovesLearnsetWidget.kt b/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/widgets/MovesLearnsetWidget.kt index 6ed020fb37..0a3be88bd6 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/widgets/MovesLearnsetWidget.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/client/gui/pokedex/widgets/MovesLearnsetWidget.kt @@ -85,6 +85,7 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( private val sortAlphaIcon = cobblemonResource("textures/gui/pokedex/moves_sort_alpha.png") private val sortTypeIcon = cobblemonResource("textures/gui/pokedex/moves_sort_type.png") private val sortSourceIcon = cobblemonResource("textures/gui/pokedex/moves_sort_source.png") + private val sortDiscoveredIcon = cobblemonResource("textures/gui/pokedex/moves_sort_discovered.png") private val tmDiscIcon = cobblemonResource("textures/item/tms/tm.png") private val movesPowerIconResource = cobblemonResource("textures/gui/summary/summary_moves_icon_power.png") private val movesAccuracyIconResource = cobblemonResource("textures/gui/summary/summary_moves_icon_accuracy.png") @@ -445,7 +446,6 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( private fun applyFilter() { val filtered = when (currentFilter()) { LearnsetFilter.ALL -> moveEntries - LearnsetFilter.DISCOVERED -> moveEntries.filter { it.isDiscovered } LearnsetFilter.LEVEL_UP -> moveEntries.filter { it.source == LearnsetSource.LEVEL_UP } LearnsetFilter.TM -> moveEntries.filter { it.source == LearnsetSource.TM } LearnsetFilter.EGG -> moveEntries.filter { it.source == LearnsetSource.EGG } @@ -462,21 +462,27 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( } private fun sortEntries(entries: List): List { + val baseEntries = if (sortMode == LearnsetSort.DISCOVERED) { + entries.filter { it.isDiscovered } + } else { + entries + } return when (sortMode) { - LearnsetSort.ALPHABETICAL -> entries.sortedWith( + LearnsetSort.ALPHABETICAL -> baseEntries.sortedWith( compareBy( { it.move.displayName.string.lowercase() }, { it.level ?: Int.MAX_VALUE } ) ) - LearnsetSort.TYPE -> entries.sortedWith( + LearnsetSort.TYPE -> baseEntries.sortedWith( compareBy( { it.move.elementalType.displayName.string.lowercase() }, { it.move.displayName.string.lowercase() }, { it.level ?: Int.MAX_VALUE } ) ) - LearnsetSort.SOURCE -> entries.sortedWith( + LearnsetSort.SOURCE, + LearnsetSort.DISCOVERED -> baseEntries.sortedWith( compareBy( { sourceOrder(it.source) }, { it.level ?: Int.MAX_VALUE }, @@ -500,12 +506,14 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( sortMode = when (sortMode) { LearnsetSort.ALPHABETICAL -> LearnsetSort.TYPE LearnsetSort.TYPE -> LearnsetSort.SOURCE - LearnsetSort.SOURCE -> LearnsetSort.ALPHABETICAL + LearnsetSort.SOURCE -> LearnsetSort.DISCOVERED + LearnsetSort.DISCOVERED -> LearnsetSort.ALPHABETICAL } sortButton.resource = when (sortMode) { LearnsetSort.ALPHABETICAL -> sortAlphaIcon LearnsetSort.TYPE -> sortTypeIcon LearnsetSort.SOURCE -> sortSourceIcon + LearnsetSort.DISCOVERED -> sortDiscoveredIcon } applyFilter() } @@ -726,7 +734,6 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( private enum class LearnsetFilter(val label: MutableComponent) { ALL(Component.literal("All")), - DISCOVERED(lang("ui.moves.learnset.tm.discovered")), LEVEL_UP(Component.literal("Level-Up")), TM(Component.literal("TM")), EGG(Component.literal("Egg")), @@ -736,7 +743,8 @@ class MovesLearnsetWidget(val pX: Int, val pY: Int) : SoundlessWidget( private enum class LearnsetSort { ALPHABETICAL, TYPE, - SOURCE + SOURCE, + DISCOVERED } private data class LearnsetMoveEntry( diff --git a/common/src/main/resources/assets/cobblemon/lang/en_us.json b/common/src/main/resources/assets/cobblemon/lang/en_us.json index dcbf00fdcc..c9e285a3bf 100644 --- a/common/src/main/resources/assets/cobblemon/lang/en_us.json +++ b/common/src/main/resources/assets/cobblemon/lang/en_us.json @@ -1294,7 +1294,13 @@ "cobblemon.ui.pokedex.search.search_by": "Search by %1$s", "cobblemon.ui.pokedex.search.type.species": "Species Name", "cobblemon.ui.pokedex.search.type.abilities": "Ability", + "cobblemon.ui.pokedex.search.type.moves": "Move Name", "cobblemon.ui.pokedex.search.type.drops": "Drops", + "cobblemon.ui.pokedex.filter.all": "All", + "cobblemon.ui.pokedex.filter.caught": "Caught", + "cobblemon.ui.pokedex.filter.seen": "Seen", + "cobblemon.ui.pokedex.filter.undiscovered": "Undiscovered", + "cobblemon.ui.pokedex.filter.level_up_tm_undiscovered": "Undiscovered TM (Level-Up)", "cobblemon.ui.pokedex.info.ability": "Ability: %1$s", "cobblemon.ui.pokedex.info.entry": "Entry", diff --git a/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/filter_icon_button.png b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/filter_icon_button.png new file mode 100644 index 0000000000..88926b9280 Binary files /dev/null and b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/filter_icon_button.png differ diff --git a/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/moves_sort_discovered.png b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/moves_sort_discovered.png new file mode 100644 index 0000000000..dd02492155 Binary files /dev/null and b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/moves_sort_discovered.png differ diff --git a/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/tab_moves.png b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/tab_moves.png index 04481a46fa..cd5a420ad3 100644 Binary files a/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/tab_moves.png and b/common/src/main/resources/assets/cobblemon/textures/gui/pokedex/tab_moves.png differ