Compare commits

..
Author SHA1 Message Date
阿鱼andWeblate da82eb8d61 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.9% (8993 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-27 11:50:29 +00:00
Watuneni iteiteandWeblate 2dc93f3336 Translated using Weblate (Japanese)
Currently translated at 96.7% (9158 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-24 10:16:38 +00:00
阿鱼andWeblate e8864418d4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.9% (8992 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-23 22:49:29 +00:00
阿鱼andWeblate 82b418d54d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.9% (8993 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-18 21:12:39 +00:00
Paul d5a08314eb Merge remote-tracking branch 'origin/lang-updates' 2026-06-16 20:36:49 +10:00
Paul 062c32be2a Correct the parsing of phases in habitat GUI (they aren't moon phases) 2026-06-16 20:33:54 +10:00
阿鱼andWeblate 09590b49cd Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.9% (8988 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 10:14:47 +00:00
Polymeta 420cbd2c99 Merge branch 'fix-pvn-fainted-party-battle' into 'main'
Fix PvN battle start with fainted parties

See merge request cable-mc/cobblemon!2311
2026-06-16 09:45:36 +00:00
Jongho Hong 0380013f37 Add changelog entry 2026-06-16 18:41:43 +09:00
阿鱼andWeblate 6c1fcc103a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.7% (8973 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 09:14:38 +00:00
阿鱼andWeblate 59b01c3988 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.7% (8971 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 08:58:39 +00:00
阿鱼andWeblate 678fa2d0ce Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.6% (8961 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 08:28:14 +00:00
Jongho Hong 94abd79923 Fix PvN battle start with fainted parties 2026-06-16 17:22:50 +09:00
阿鱼andWeblate 0a1931aaae Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.6% (8958 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 08:21:26 +00:00
阿鱼andWeblate 85d76dcc29 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.5% (8952 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 08:07:26 +00:00
阿鱼andWeblate bd0a9ef654 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.4% (8944 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 07:27:07 +00:00
阿鱼andWeblate 7a702e276c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.2% (8926 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 05:41:55 +00:00
阿鱼andWeblate 3f9a2825cb Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 94.2% (8921 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 05:30:18 +00:00
阿鱼andWeblate d1462bc27b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.9% (8892 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 05:05:07 +00:00
阿鱼andWeblate 211b14dbd0 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.5% (8852 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 04:59:55 +00:00
阿鱼andWeblate 47e83003c3 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.4% (8850 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 04:59:34 +00:00
阿鱼andWeblate 59134c4212 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.4% (8849 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-16 04:32:46 +00:00
阿鱼andWeblate 44b434562c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.4% (8847 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-15 20:32:05 +00:00
Hiroku 344b0750f9 Merge branch 'implement_pokemon' into 'main'
more QA fixes

See merge request cable-mc/cobblemon!2310
2026-06-15 04:26:30 +00:00
ewwww 10d9d97c11 restored broken or missing seat locators for Ariados, Bastiodon, Dhelmise, Dondozo, Drifblim, Girafarig, and Klinklang 2026-06-15 00:06:56 -04:00
Paul 94bcfba076 Phase count should be derived, not set 2026-06-14 22:10:46 +10:00
RedGenesectNinja 69a75ffcd4 Fixed broken Alola bias Exeggcute textures 2026-06-13 13:25:57 -05:00
阿鱼andWeblate cc1317dd06 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.4% (8845 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-13 07:46:03 +00:00
Polymeta e15ac73b1b Merge branch 'fix-enchanted-fossil-items' into 'main'
Fix crash when using enchanted items in the ressurection machine

Closes #1973

See merge request cable-mc/cobblemon!2307
2026-06-11 21:48:56 +00:00
lionandPolymeta 6c6576c117 Fix crash when using enchanted items in the ressurection machine 2026-06-11 21:48:55 +00:00
Polymeta ebdfa7edc0 Merge branch 'fix-pokemon-properties-nickname-parsing-to-json' into 'main'
Add pokémon nickname when serializing and deserializing to json on pokémon properties

Closes #1981

See merge request cable-mc/cobblemon!2306
2026-06-11 13:48:21 +00:00
lionandPolymeta 297e8eae77 Add pokémon nickname when serializing and deserializing to json on pokémon properties 2026-06-11 13:48:21 +00:00
Polymeta ea8179018d Merge branch 'modded-discs-compat' into 'main'
Add modded discs compatibility with disc shelves

See merge request cable-mc/cobblemon!2305
2026-06-11 08:20:18 +00:00
lionandPolymeta 14fccfae1d Add modded discs compatibility with disc shelves 2026-06-11 08:20:18 +00:00
RedGenesectNinja a3c5a6c377 Implemented Yamask fixes 2026-06-09 21:58:33 -05:00
Watuneni iteiteandWeblate abb5346305 Translated using Weblate (Japanese)
Currently translated at 96.5% (9139 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-09 15:19:33 +00:00
Watuneni iteiteandWeblate 9466f66721 Translated using Weblate (Japanese)
Currently translated at 96.4% (9129 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-09 14:13:54 +00:00
Watuneni iteiteandWeblate 716ea55bc7 Translated using Weblate (Japanese)
Currently translated at 96.2% (9115 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-09 14:01:57 +00:00
ManriqueandWeblate 15f0ad1821 Translated using Weblate (Spanish)
Currently translated at 97.2% (9211 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-06-08 08:42:34 +00:00
Watuneni iteiteandWeblate a16975c750 Translated using Weblate (Japanese)
Currently translated at 96.1% (9105 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-07 15:19:10 +00:00
Watuneni iteiteandWeblate c0e6d87c40 Translated using Weblate (Japanese)
Currently translated at 96.1% (9105 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-07 12:39:38 +00:00
Watuneni iteiteandWeblate 91078b917e Translated using Weblate (Japanese)
Currently translated at 96.0% (9090 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-06-07 12:02:11 +00:00
ewwww b7e27fa52a Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-06-05 21:10:08 -04:00
ewwww dc87ffd2a8 luvdisc faint fix 2026-06-05 21:09:49 -04:00
阿鱼andWeblate cbeda361d4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.3% (8835 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-04 15:12:59 +00:00
阿鱼andWeblate 079a2fb50d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.3% (8835 of 9467 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-06-03 06:11:14 +00:00
95 changed files with 739 additions and 2063 deletions
+3
View File
@@ -300,6 +300,8 @@
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
- Fixed a crash that could occur when starting a PvN battle with only fainted Pokémon.
### Fixes
- Fixed Croagunk's walkspeed
@@ -360,6 +362,7 @@
- Separated all the functions of MoLangFunctions.kt into their own files.
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.Renderable
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.network.chat.Component
@@ -54,8 +55,6 @@ abstract class ParentWidget(
}
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (!active) return false
return children.any {
it.mouseClicked(pMouseX, pMouseY, pButton)
}
@@ -1,116 +0,0 @@
/*
* 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.gui
import kotlin.math.max
import kotlin.math.min
interface TreeNode<T> {
val children: List<TreeNode<T>>
}
class TreeDrawingNode<T>(
val value: T,
val children: List<TreeDrawingNode<T>>,
) {
var x = 0
var y = 0
var offset = 0
}
fun <T> createDrawingTree(treeNode: TreeNode<T>): TreeDrawingNode<T> {
val root = setup(treeNode, 0, mutableListOf<Int>(), mutableListOf<Int>())
addMods(root, 0)
return root
}
@Suppress("UNCHECKED_CAST")
private fun <T> setup(
treeNode: TreeNode<T>,
depth: Int,
nexts: MutableList<Int>,
offset: MutableList<Int>,
): TreeDrawingNode<T> {
val children = treeNode.children.map { child ->
setup(child, depth + 1, nexts, offset)
}
val treeDrawingNode = TreeDrawingNode<T>(treeNode as T, children)
treeDrawingNode.y = depth
while (nexts.size <= depth) {
nexts.add(0)
}
while (offset.size <= depth) {
offset.add(0)
}
var place =
if (children.isEmpty()) {
nexts[depth]
} else if (children.size == 1) {
// children.first().x - 1
children.first().x
} else {
// (children[0].x + children[1].x) / 2
(children.first().x + children.last().x) / 2
}
offset[depth] = max(offset[depth], nexts[depth] - place)
if (children.isEmpty()) {
treeDrawingNode.x = place
} else {
treeDrawingNode.x = place + offset[depth]
}
nexts[depth] += 2
treeDrawingNode.offset = offset[depth]
return treeDrawingNode
}
private fun <T> addMods(
treeNode: TreeDrawingNode<T>,
modSum: Int,
) {
treeNode.x += modSum
val newModSum = modSum + treeNode.offset
treeNode.children.forEach { child ->
addMods(child, newModSum)
}
}
data class TreeDrawingBounds(val minX: Int, val maxX: Int, val minY: Int, val maxY: Int) {
val width = maxX - minX
val height = maxY - minY
val xCenter = (maxX + minX) / 2.0
val yCenter = (maxY + minY) / 2.0
}
fun <T> calculateBounds(treeDrawingNode: TreeDrawingNode<T>): TreeDrawingBounds {
var minX = treeDrawingNode.x
var maxX = treeDrawingNode.x
var minY = treeDrawingNode.y
var maxY = treeDrawingNode.y
for (child in treeDrawingNode.children) {
val childBounds = calculateBounds(child)
minX = min(minX, childBounds.minX)
maxX = max(maxX, childBounds.maxX)
minY = min(minY, childBounds.minY)
maxY = max(maxY, childBounds.maxY)
}
return TreeDrawingBounds(minX, maxX, minY, maxY)
}
@@ -69,7 +69,7 @@ class HabitatPool {
pool.spawns = spawns
return pool
} else {
return HabitatPools.habitatPoolsById[poolId] ?: HabitatPool.default()
return HabitatPools.habitatPoolsById[poolId] ?: default()
}
}
}
@@ -94,6 +94,14 @@ class HabitatPool {
return spawns.mapNotNull { it.createSpawnDetail(habitatBlockEntity) }
}
fun getPhaseCount(): Int {
return spawns
.flatMap { it.phases?.ranges?.flatten() ?: emptySet() }
.toSet()
.count()
.coerceAtLeast(1)
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(id)
buffer.writeUtf(name)
@@ -17,7 +17,6 @@ import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
class HabitatSettingsDTO() {
var numberOfPhases = 1
var phaseOrder = HabitatPhaseOrder.SIMPLE
lateinit var levelRange: IntRange
var modifiers: String = ""
@@ -28,7 +27,6 @@ class HabitatSettingsDTO() {
var naturalSettings: NaturalHabitatSettingsDTO? = null
constructor(habitatBlockEntity: HabitatBlockEntity) : this() {
this.numberOfPhases = habitatBlockEntity.numberOfPhases
this.phaseOrder = habitatBlockEntity.phaseOrder
this.levelRange = habitatBlockEntity.levelRange
this.modifiers = habitatBlockEntity.modifiers.asString()
@@ -44,7 +42,6 @@ class HabitatSettingsDTO() {
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(numberOfPhases)
buffer.writeEnum(phaseOrder)
buffer.writeInt(levelRange.first)
buffer.writeInt(levelRange.last)
@@ -60,7 +57,6 @@ class HabitatSettingsDTO() {
}
fun decode(buffer: RegistryFriendlyByteBuf) {
this.numberOfPhases = buffer.readInt()
this.phaseOrder = buffer.readEnum(HabitatPhaseOrder::class.java)
val levelRangeStart = buffer.readInt()
val levelRangeEnd = buffer.readInt()
@@ -72,40 +72,6 @@ abstract class AbstractPokedexManager {
} ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?): PokedexEntryProgress {
if (form == null) return getHighestKnowledgeFor(entry)
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return PokedexEntryProgress.UNREGISTERED
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return PokedexEntryProgress.UNREGISTERED
}
return speciesRecord.getFormRecord(form.displayForm)?.knowledge ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?, aspects: Iterable<String>): PokedexEntryProgress {
val formKnowledge = getHighestKnowledgeFor(entry, form)
if (formKnowledge == PokedexEntryProgress.UNREGISTERED) return PokedexEntryProgress.UNREGISTERED
val seenAspects = getSeenAspects(entry)
val allSeenAspects = aspects
// TODO this is ugly
.filter { it ->
if (Dexes.equivalentFormsLookup[it] != null) return@filter false
if (it.uppercase() in setOf(Gender.MALE.name, Gender.FEMALE.name, Gender.GENDERLESS.name)) return@filter false
if ("shiny".equals(it, ignoreCase = true)) return@filter false
return@filter true
}
.all { it -> seenAspects.contains(it) }
if (!allSeenAspects) return PokedexEntryProgress.UNREGISTERED
return formKnowledge
}
fun getEncounteredForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.SEEN)
}
@@ -10,9 +10,6 @@ package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
@@ -43,17 +40,6 @@ object Dexes : JsonDataRegistry<PokedexDef> {
//Maps a dex id to its PokedexDef
val dexEntryMap = linkedMapOf<ResourceLocation, PokedexDef>()
val equivalentForms = mapOf(
"galar" to listOf("region-bias-galar", "bias-galar", "galar-bias", "galarian", "galar"),
"alola" to listOf("region-bias-alola", "bias-alola", "alola-bias", "alolan", "alola"),
"hisui" to listOf("region-bias-hisui", "bias-hisui", "hisui-bias", "hisuian", "hisui"),
"paldea" to listOf("region-bias-paldea", "bias-paldea", "paldea-bias", "paldean", "paldea"),
)
val equivalentFormsLookup = equivalentForms.flatMap { (key, values) ->
values.map { it to key }
}.toMap()
override fun reload(data: Map<ResourceLocation, PokedexDef>) {
dexEntryMap.clear()
data.entries.sortedBy { it.value.sortOrder }.forEach { (id, def) -> dexEntryMap[id] = def }
@@ -63,34 +49,4 @@ object Dexes : JsonDataRegistry<PokedexDef> {
override fun sync(player: ServerPlayer) {
PokedexDexSyncPacket(dexEntryMap.values).sendToPlayer(player)
}
fun findDexEntryBySpeciesId(regionId: ResourceLocation, speciesId: ResourceLocation): PokedexEntry? {
return dexEntryMap[regionId]?.getEntries()?.firstOrNull { it -> it.speciesId == speciesId }
}
fun findDexEntryBySpeciesId(speciesId: ResourceLocation): PokedexEntry? {
return findDexEntryBySpeciesId(cobblemonResource("national"), speciesId)
}
fun findRootDexEntryBySpeciesId(speciesId: ResourceLocation, formName: String): Pair<PokedexEntry, PokedexForm> {
var rootSpecies = speciesId.let { PokemonSpecies.getByIdentifier(it) }!!
while (rootSpecies.preEvolution != null) {
rootSpecies = rootSpecies.preEvolution!!.species
}
val entry = findDexEntryBySpeciesId(rootSpecies.resourceIdentifier)
?: throw RuntimeException("Root dex entry not found")
val formEquivalents = getFormEquivalents(formName)
val form =
entry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
entry.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
return entry to form
}
fun getFormEquivalents(formName: String): List<String> {
val key = equivalentFormsLookup[formName.lowercase()]
return equivalentForms[key] ?: listOf(formName.lowercase())
}
}
@@ -759,6 +759,7 @@ open class PokemonProperties {
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, it.string) }
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
@@ -795,6 +796,7 @@ open class PokemonProperties {
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let(Component::literal)
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
@@ -1,30 +0,0 @@
/*
* 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.pokemon.evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.*
interface EvolutionVisitor<R> {
fun visit(evolution: Evolution): R? {
return when (evolution) {
is BlockClickEvolution -> visitBlockClickEvolution(evolution)
is DummyEvolution -> visitDummyEvolution(evolution)
is ItemInteractionEvolution -> visitItemInteractionEvolution(evolution)
is LevelUpEvolution -> visitLevelUpEvolution(evolution)
is TradeEvolution -> visitTradeEvolution(evolution)
else -> null
}
}
fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): R
fun visitDummyEvolution(evolution: Evolution): R // TODO: Use dummyEvolution?
fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): R
fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): R
fun visitTradeEvolution(tradeEvolution: TradeEvolution): R
}
@@ -21,7 +21,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 21st, 2022
*/
abstract class EntityQueryRequirement : Requirement() {
interface EntityQueryRequirement : Requirement {
override fun check(pokemon: Pokemon): Boolean {
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
return this.check(pokemon, queriedEntity)
@@ -34,5 +34,5 @@ abstract class EntityQueryRequirement : Requirement() {
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
* @return If the requirement was satisfied.
*/
abstract fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
}
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
* @since May 6th, 2025
*/
abstract class OwnerQueryRequirement : Requirement() {
interface OwnerQueryRequirement : Requirement {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
@@ -44,7 +44,7 @@ abstract class OwnerQueryRequirement : Requirement() {
* @param owner The [Player] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
abstract fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -55,5 +55,5 @@ abstract class OwnerQueryRequirement : Requirement() {
* @param owner The [NPCEntity] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
abstract fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.resources.ResourceLocation
/**
* Represents a universal requirement suitable for various checks on pokemon..
@@ -23,7 +22,7 @@ import net.minecraft.resources.ResourceLocation
* @author Licious
* @since March 19th, 2022
*/
abstract class Requirement {
fun interface Requirement {
/**
* Checks if the given [Pokemon] satisfies the requirement.
@@ -31,8 +30,6 @@ abstract class Requirement {
* @param pokemon The [Pokemon] being queried.
* @return If the requirement was satisfied.
*/
abstract fun check(pokemon: Pokemon): Boolean
fun check(pokemon: Pokemon): Boolean
val pokedexIcon: ResourceLocation? = null
val pokedexTooltip: String? = null
}
@@ -1,74 +0,0 @@
/*
* 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.pokemon.requirement
import com.cobblemon.mod.common.pokemon.requirements.*
interface RequirementVisitor<R> {
fun visit(requirement: Requirement): R? {
return when (requirement) {
is AdvancementRequirement -> visitAdvancementRequirement(requirement)
is AnyRequirement -> visitAnyRequirement(requirement)
is AreaRequirement -> visitAreaRequirement(requirement)
is AttackDefenceRatioRequirement -> visitAttackDefenceRatioRequirement(requirement)
is BattleCriticalHitsRequirement -> visitBattleCriticalHitsRequirement(requirement)
is BiomeRequirement -> visitBiomeRequirement(requirement)
is BlocksTraveledRequirement -> visitBlocksTraveledRequirement(requirement)
is DamageTakenRequirement -> visitDamageTakenRequirement(requirement)
is DefeatRequirement -> visitDefeatRequirement(requirement)
is FriendshipRequirement -> visitFriendshipRequirement(requirement)
is HeldItemRequirement -> visitHeldItemRequirement(requirement)
is LevelRequirement -> visitLevelRequirement(requirement)
is MoonPhaseRequirement -> visitMoonPhaseRequirement(requirement)
is MoveSetRequirement -> visitMoveSetRequirement(requirement)
is MoveTypeRequirement -> visitMoveTypeRequirement(requirement)
is OwnerHoldsItemRequirement -> visitOwnerHoldsItemRequirement(requirement)
is PartyMemberRequirement -> visitPartyMemberRequirement(requirement)
is PokemonPropertiesRequirement -> visitPokemonPropertiesRequirement(requirement)
is PropertyRangeRequirement -> visitPropertyRangeRequirement(requirement)
is RecoilRequirement -> visitRecoilRequirement(requirement)
is StatCompareRequirement -> visitStatCompareRequirement(requirement)
is StatEqualRequirement -> visitStatEqualRequirement(requirement)
is StructureRequirement -> visitStructureRequirement(requirement)
is TimeRangeRequirement -> visitTimeRangeRequirement(requirement)
is UseMoveRequirement -> visitUseMoveRequirement(requirement)
is WeatherRequirement -> visitWeatherRequirement(requirement)
is WorldRequirement -> visitWorldRequirement(requirement)
else -> null
}
}
fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): R
fun visitAnyRequirement(anyRequirement: AnyRequirement): R
fun visitAreaRequirement(areaRequirement: AreaRequirement): R
fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): R
fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): R
fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): R
fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): R
fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): R
fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): R
fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): R
fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): R
fun visitLevelRequirement(levelRequirement: LevelRequirement): R
fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): R
fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): R
fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): R
fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): R
fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): R
fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): R
fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): R
fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): R
fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): R
fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): R
fun visitStructureRequirement(structureRequirement: StructureRequirement): R
fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): R
fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): R
fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): R
fun visitWorldRequirement(worldRequirement: WorldRequirement): R
}
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.TimeRange.Companion.timeRanges
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
/**
@@ -51,25 +49,4 @@ class TimeRange : IntRanges {
constructor() : super()
constructor(vararg ranges: IntRange) : super(*ranges)
fun displayName(): MutableComponent? {
val key = timeRanges.entries.firstOrNull { entry -> this == entry.value }?.key ?: return null
return lang("ui.time_range.$key")
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TimeRange) return false
if (other.ranges.size != this.ranges.size) return false
other.ranges.forEachIndexed { index, otherRange ->
if (this.ranges[index] != otherRange) return false
}
return true
}
override fun hashCode(): Int {
return ranges.hashCode()
}
}
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.level.Level
/**
@@ -44,7 +42,4 @@ enum class MoonPhase {
fun ofWorld(world: Level): MoonPhase = VALUES[world.moonPhase]
}
fun displayName(): MutableComponent {
return lang("ui.moon_phase.${this.name.lowercase()}")
}
}
@@ -349,11 +349,12 @@ object BattleBuilder {
npcPartyStores.add(npcParty)
}
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
val playerAvailablePokemon = playerActor.pokemonList.count { it.health > 0 }
if (playerAvailablePokemon < battleFormat.battleType.slotsPerActor) {
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
actorEntity = player,
requiredCount = battleFormat.battleType.slotsPerActor,
hadCount = playerActor.pokemonList.size
hadCount = playerAvailablePokemon
)
}
@@ -163,7 +163,8 @@ class TrackerActor(val uuid: UUID) {
//we assume that AI knows it all about our allies
trackerActor.party.addAll(actor.pokemonList.map { createAllied(it) })
actor.activePokemon.forEach {
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
val battlePokemon = it.battlePokemon ?: return@forEach
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
trackerActor.party.remove(active)
trackerActor.activePokemon.add(active)
}
@@ -176,7 +177,8 @@ class TrackerActor(val uuid: UUID) {
//only know basics of what we see right now
trackerActor.party.addAll(actor.pokemonList.map { createOpposing(it) })
actor.activePokemon.forEach {
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
val battlePokemon = it.battlePokemon ?: return@forEach
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
trackerActor.party.remove(active)
trackerActor.activePokemon.add(active)
}
@@ -16,24 +16,20 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.core.component.DataComponents
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundSource
import net.minecraft.world.ContainerHelper
import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.WorldlyContainer
import net.minecraft.world.*
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.level.gameevent.GameEvent
import java.util.OptionalInt
import net.minecraft.world.phys.BlockHitResult
import java.util.*
import kotlin.math.pow
class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DISC_SHELF, pos, state), WorldlyContainer {
@@ -134,25 +130,7 @@ class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobbl
return stack.item is TechnicalMachineItem
|| stack.item == CobblemonItems.UPGRADE
|| stack.item == CobblemonItems.DUBIOUS_DISC
|| stack.item == Items.MUSIC_DISC_13
|| stack.item == Items.MUSIC_DISC_CAT
|| stack.item == Items.MUSIC_DISC_BLOCKS
|| stack.item == Items.MUSIC_DISC_CHIRP
|| stack.item == Items.MUSIC_DISC_FAR
|| stack.item == Items.MUSIC_DISC_MALL
|| stack.item == Items.MUSIC_DISC_MELLOHI
|| stack.item == Items.MUSIC_DISC_STAL
|| stack.item == Items.MUSIC_DISC_STRAD
|| stack.item == Items.MUSIC_DISC_WARD
|| stack.item == Items.MUSIC_DISC_11
|| stack.item == Items.MUSIC_DISC_WAIT
|| stack.item == Items.MUSIC_DISC_OTHERSIDE
|| stack.item == Items.MUSIC_DISC_5
|| stack.item == Items.MUSIC_DISC_RELIC
|| stack.item == Items.MUSIC_DISC_PRECIPICE
|| stack.item == Items.MUSIC_DISC_CREATOR
|| stack.item == Items.MUSIC_DISC_CREATOR_MUSIC_BOX
|| stack.item == Items.MUSIC_DISC_PIGSTEP
|| stack.has(DataComponents.JUKEBOX_PLAYABLE)
}
fun onNoteBlockPulse(level: Level, noteBlockPos: BlockPos, soundEvent: SoundEvent) {
@@ -60,10 +60,12 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
var spawningStyle: HabitatSpawningStyle = ActivatedHabitatSpawning(this)
var numberOfPhases: Int = 1
var phaseOrder = HabitatPhaseOrder.SIMPLE
var currentPhase = 1
val numberOfPhases: Int
get() = pool.getPhaseCount()
var levelRange: IntRange = 1..Cobblemon.config.maxPokemonLevel
var modifiers: PokemonProperties = PokemonProperties()
var pool: HabitatPool = HabitatPool.default()
@@ -139,7 +141,6 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
val activatedSettings = habitatSettingsDTO.activatedSettings
val naturalSettings = habitatSettingsDTO.naturalSettings
val isActivated = habitatSettingsDTO.isActivatedSpawning
this.numberOfPhases = habitatSettingsDTO.numberOfPhases
this.phaseOrder = habitatSettingsDTO.phaseOrder
this.levelRange = habitatSettingsDTO.levelRange
this.modifiers = PokemonProperties.parse(habitatSettingsDTO.modifiers)
@@ -169,7 +170,6 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
override fun saveAdditional(tag: CompoundTag, registryLookup: HolderLookup.Provider) {
super.saveAdditional(tag, registryLookup)
tag.putString(DataKeys.HABITAT_MIMIC, mimicId.toString())
tag.putInt(DataKeys.HABITAT_PHASE_COUNT, numberOfPhases)
tag.putString(DataKeys.HABITAT_PHASE_ORDER, phaseOrder.toString())
// Only save the level range when it's a non-trivial one
if (levelRange.first != 1 || levelRange.last != Cobblemon.config.maxPokemonLevel) {
@@ -201,7 +201,6 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
return // Client doesn't need to try loading the rest
}
numberOfPhases = tag.getInt(DataKeys.HABITAT_PHASE_COUNT)
phaseOrder = HabitatPhaseOrder.valueOf(tag.getString(DataKeys.HABITAT_PHASE_ORDER))
levelRange = tag.getString(DataKeys.HABITAT_LEVEL_RANGE).takeIf { it.isNotBlank() }?.let(IntRangeAdapter::deserialize) ?: 1..Cobblemon.config.maxPokemonLevel
modifiers = tag.getString(DataKeys.HABITAT_MODIFIERS).takeIf { it.isNotBlank() }?.let(PokemonProperties::parse) ?: PokemonProperties()
@@ -630,7 +630,8 @@ class FossilMultiblockStructure (
result.putInt(DataKeys.ORGANIC_MATERIAL, organicMaterialInside)
val fossilInv = ListTag()
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(NbtOps.INSTANCE, it).orThrow) }
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(ops, it).getOrThrow()) }
result.put(DataKeys.FOSSIL_INVENTORY, fossilInv)
result.putString(DataKeys.CONNECTOR_DIRECTION, tankConnectorDirection?.toString())
@@ -652,9 +653,9 @@ class FossilMultiblockStructure (
const val TICKS_PER_MINUTE = 1200
const val MATERIAL_TO_START = 128
const val TIME_TO_TAKE = 100
const val TIME_PER_STAGE = 100 / 8
const val PROTECTION_TIME = 100
const val TIME_TO_TAKE = TICKS_PER_MINUTE * 12
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
const val PROTECTION_TIME = TICKS_PER_MINUTE * 5
fun fromNbt(nbt: CompoundTag, registryLookup: HolderLookup.Provider, animAge: Int = -1, partialTicks: Float = 0f): FossilMultiblockStructure {
val monitorPos = NbtUtils.readBlockPos(nbt, DataKeys.MONITOR_POS).get()
@@ -669,7 +670,10 @@ class FossilMultiblockStructure (
val fossilInv = if (nbt.contains(DataKeys.FOSSIL_INVENTORY)) { (nbt.get(DataKeys.FOSSIL_INVENTORY) as ListTag) } else ListTag()
val actualFossilList = mutableListOf<ItemStack>()
fossilInv.forEach { ItemStack.parse(registryLookup, it).ifPresent(actualFossilList::add) }
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInv.forEach { ItemStack.CODEC.parse(ops, it).result().ifPresent(actualFossilList::add) }
result.fossilInventory = actualFossilList
result.tankConnectorDirection = Direction.byName(nbt.getString(DataKeys.CONNECTOR_DIRECTION))
@@ -115,35 +115,19 @@ class HabitatEditGUI(
addOptionWidget(mimicInput)
y += spacing
labels.add(lang("ui.edit.habitat.phase_number") to (10 to y))
y += 12
val phasesInput = EditBox(font, 10, y, buttonWidth, 20, "Phases".text())
phasesInput.value = habitatSettingsDTO.numberOfPhases.toString()
phasesInput.setResponder { value ->
val phases = value.toIntOrNull()
val valid = phases != null && phases > 0
if (valid) {
habitatSettingsDTO.numberOfPhases = phases
}
phasesInput.setTextColor(if (valid) validTextColor else invalidTextColor)
setFieldValidity("phases", valid, "ui.edit.habitat.validation.phases")
// Phase setting only visible if there's more than one phase
val phaseCount = habitatSettingsDTO.pool.toHabitatPool()?.getPhaseCount() ?: 1
if (phaseCount > 1) {
phaseOrderButton = addOptionWidget(
Button.builder(getPhaseOrderText()) {
val orders = HabitatPhaseOrder.entries
val currentIndex = orders.indexOf(habitatSettingsDTO.phaseOrder)
habitatSettingsDTO.phaseOrder = orders[(currentIndex + 1) % orders.size]
refresh()
}.bounds(10, y, buttonWidth, 20).build()
)
y += spacing
}
val initialPhases = phasesInput.value.toIntOrNull()
val initialPhasesValid = initialPhases != null && initialPhases > 0
phasesInput.setTextColor(if (initialPhasesValid) validTextColor else invalidTextColor)
setFieldValidity("phases", initialPhasesValid, "ui.edit.habitat.validation.phases")
addOptionWidget(phasesInput)
y += spacing
phaseOrderButton = addOptionWidget(
Button.builder(getPhaseOrderText()) {
val orders = HabitatPhaseOrder.entries
val currentIndex = orders.indexOf(habitatSettingsDTO.phaseOrder)
habitatSettingsDTO.phaseOrder = orders[(currentIndex + 1) % orders.size]
refresh()
}.bounds(10, y, buttonWidth, 20).build()
)
y += spacing
labels.add(lang("ui.edit.habitat.level_range") to (10 to y))
y += 12
@@ -390,7 +374,10 @@ class HabitatEditGUI(
}
fun refresh() {
phaseOrderButton.message = getPhaseOrderText()
val phaseCount = habitatSettingsDTO.pool.toHabitatPool()?.getPhaseCount() ?: 1
if (phaseCount > 1 && ::phaseOrderButton.isInitialized) {
phaseOrderButton.message = getPhaseOrderText()
}
spawnModeButton.message = getSpawnModeText()
poolSelectorButton.message = getPoolText()
viewPoolButton.message = getViewPoolText()
@@ -439,6 +426,7 @@ class HabitatEditGUI(
}
habitatSettingsDTO.pool = newCustomPool
}
rebuildWidgets()
return
}
@@ -451,6 +439,7 @@ class HabitatEditGUI(
}
habitatSettingsDTO.pool = selectedPool
rebuildWidgets()
}
private fun validateLevelRangeInputs() {
@@ -45,7 +45,6 @@ class HabitatSpawnEditorGUI(
private val actionButtonBottomMargin = 10
private val validTextColor = 0xFFFFFF
private val invalidTextColor = 0xFF5555
private val moonPhaseRange = 0..7
private lateinit var positionTypeButton: Button
private lateinit var bucketButton: Button
private lateinit var timeOfDayButton: Button
@@ -185,7 +184,7 @@ class HabitatSpawnEditorGUI(
phasesInput.setTextColor(validTextColor)
setFieldValidity("phases_list", true, "ui.edit.habitat.validation.phases_list")
} else {
val parsed = parseMoonPhases(value)
val parsed = parsePhases(value)
val valid = parsed != null
if (valid) {
spawn.phases = parsed
@@ -194,7 +193,7 @@ class HabitatSpawnEditorGUI(
setFieldValidity("phases_list", valid, "ui.edit.habitat.validation.phases_list")
}
}
val initialPhasesValid = phasesInput.value.isBlank() || parseMoonPhases(phasesInput.value) != null
val initialPhasesValid = phasesInput.value.isBlank() || parsePhases(phasesInput.value) != null
phasesInput.setTextColor(if (initialPhasesValid) validTextColor else invalidTextColor)
setFieldValidity("phases_list", initialPhasesValid, "ui.edit.habitat.validation.phases_list")
addOptionWidget(phasesInput)
@@ -332,7 +331,7 @@ class HabitatSpawnEditorGUI(
return runCatching { PokemonSpecies.getByName(lowered) }.getOrNull()
}
private fun parseMoonPhases(raw: String): IntRanges? {
private fun parsePhases(raw: String): IntRanges? {
val ranges = mutableListOf<IntRange>()
val tokens = raw.split(",").map(String::trim)
if (tokens.isEmpty() || tokens.any { it.isEmpty() }) {
@@ -344,13 +343,12 @@ class HabitatSpawnEditorGUI(
val range = when (parts.size) {
1 -> {
val value = parts[0].toIntOrNull() ?: return null
if (value !in moonPhaseRange) return null
value..value
}
2 -> {
val start = parts[0].toIntOrNull() ?: return null
val end = parts[1].toIntOrNull() ?: return null
if (start !in moonPhaseRange || end !in moonPhaseRange || start > end) {
if (start > end) {
return null
}
start..end
@@ -34,27 +34,28 @@ import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HEADER_BAR_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_ARROW_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ABILITIES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DESCRIPTION
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DROPS
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_EVOLUTION_TREE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ICON_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_MOVES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_STATS
import com.cobblemon.mod.common.client.gui.pokedex.widgets.*
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.AbilitiesWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DescriptionWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DropsScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.MovesLearnsetWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonInfoWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SearchWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SizeWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.StatsWidget
import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.isInventoryKeyPressed
@@ -91,10 +92,6 @@ class PokedexGUI private constructor(
private val categoryBarOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_bar_category.png")
// TODO: separate into smaller components / widgets?
private val backgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay.png")
private val expandedBackgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay_expanded.png")
private val tabSelectArrow = cobblemonResource("textures/gui/pokedex/select_arrow.png")
private val tabIcons = arrayOf(
cobblemonResource("textures/gui/pokedex/tab_info.png"),
@@ -102,8 +99,7 @@ class PokedexGUI private constructor(
cobblemonResource("textures/gui/pokedex/tab_size.png"),
cobblemonResource("textures/gui/pokedex/tab_stats.png"),
cobblemonResource("textures/gui/pokedex/tab_drops.png"),
cobblemonResource("textures/gui/pokedex/tab_moves.png"),
cobblemonResource("textures/gui/pokedex/tab_evolution_tree.png"),
cobblemonResource("textures/gui/pokedex/tab_moves.png")
)
val arrowUpIcon = cobblemonResource("textures/gui/pokedex/arrow_up.png")
@@ -116,8 +112,6 @@ class PokedexGUI private constructor(
TAB_MOVES
)
private val ICONS_PADDING_BETWEEN = (BASE_WIDTH / 2 - ICONS_PADDING_AROUND * 2) / tabIcons.size
/**
* Attempts to open this screen for a client.
*/
@@ -136,7 +130,6 @@ class PokedexGUI private constructor(
var oldDragPosX = 0.0
var canDragRender = false
private var activeDragableElement: GuiEventListener? = null
private var filteredPokedex: Collection<PokedexDef> = mutableListOf()
private var seenCount = "0000"
@@ -160,29 +153,13 @@ class PokedexGUI private constructor(
private lateinit var scrollScreen: EntriesScrollingWidget
private lateinit var pokemonInfoWidget: PokemonInfoWidget
private lateinit var searchWidget: SearchWidget
private lateinit var pokemonNameWidget: PokemonNameWidget
private var selectedSearchByType: SearchByType = SearchByType.SPECIES
private var selectedCategoryFilter: PokedexCategoryFilterType = PokedexCategoryFilterType.ALL
private val tabButtons: MutableList<ScaledButton> = mutableListOf()
var seenShinyStates = setOf<String>()
var shiny = false
var maleRatio = -1F
var gender = Gender.GENDERLESS
var aspects = mutableSetOf<String>()
lateinit var tabInfoElement: GuiEventListener
var tabInfoIndex = TAB_DESCRIPTION
var evolutionTreeExpanded = false
set(value) {
field = value
if (::pokemonInfoWidget.isInitialized) {
pokemonInfoWidget.active = !value
pokemonInfoWidget.visible = !value
}
}
override fun renderBlurredBackground(delta: Float) {}
override fun renderMenuBackground(context: GuiGraphics) {}
@@ -201,7 +178,7 @@ class PokedexGUI private constructor(
//Info Widget
if (::pokemonInfoWidget.isInitialized) removeWidget(pokemonInfoWidget)
pokemonInfoWidget = PokemonInfoWidget(this, x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
pokemonInfoWidget = PokemonInfoWidget(x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
addRenderableWidget(pokemonInfoWidget)
setUpTabs()
@@ -213,10 +190,6 @@ class PokedexGUI private constructor(
searchWidget = SearchWidget(x + 26, y + 28, 120, HEADER_BAR_HEIGHT, update = ::updateFilters)
addRenderableWidget(searchWidget)
if (::pokemonNameWidget.isInitialized) removeWidget(pokemonNameWidget)
pokemonNameWidget = PokemonNameWidget(this, x + 180, y + 28)
addRenderableWidget(pokemonNameWidget)
if (::regionSelectWidgetUp.isInitialized) removeWidget(regionSelectWidgetUp)
regionSelectWidgetUp = ScaledButton(
buttonX = (x + 95).toFloat(),
@@ -392,14 +365,6 @@ class PokedexGUI private constructor(
shadow = true
)
blitk(
matrixStack = matrices,
texture = if (evolutionTreeExpanded) expandedBackgroundOverlay else backgroundOverlay,
x = pokemonInfoWidget.x, y = pokemonInfoWidget.y,
width = HALF_OVERLAY_WIDTH,
height = HALF_OVERLAY_HEIGHT
)
// Category filter
blitk(
matrixStack = matrices,
@@ -435,7 +400,7 @@ class PokedexGUI private constructor(
blitk(
matrixStack = matrices,
texture = tabSelectArrow,
x = (x + BASE_WIDTH / 2 + ICONS_ARROW_PADDING_AROUND + tabInfoIndex * ICONS_PADDING_BETWEEN) / SCALE,
x = (x + 191.5F + (22F * tabInfoIndex)) / SCALE,
y = (y + 177) / SCALE,
width = 12,
height = 6,
@@ -469,7 +434,6 @@ class PokedexGUI private constructor(
val canDisplayEntry = true //selectedForm?.unlockForms
if (::pokemonInfoWidget.isInitialized
&& pokemonInfoWidget.active
&& !pokemonInfoWidget.suppressViewport
&& pokemonInfoWidget.isWithinPortraitSpace(mouseX, mouseY)
&& canDisplayEntry == true
@@ -478,12 +442,6 @@ class PokedexGUI private constructor(
isDragging = true
oldDragPosX = mouseX
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
activeDragableElement = pokemonInfoWidget
} else if (tabInfoIndex == TAB_EVOLUTION_TREE &&
::tabInfoElement.isInitialized &&
(tabInfoElement as EvolutionTreeWidget).isHovered(mouseX, mouseY)
) {
activeDragableElement = tabInfoElement
}
return try {
super.mouseClicked(mouseX, mouseY, button)
@@ -495,18 +453,14 @@ class PokedexGUI private constructor(
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (canDragRender) canDragRender = false
if (isDragging) isDragging = false
activeDragableElement = null
return super.mouseReleased(pMouseX, pMouseY, pButton)
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (isDragging && canDragRender && activeDragableElement == pokemonInfoWidget) {
if (isDragging && canDragRender) {
val dragOffsetY = (oldDragPosX - mouseX).toFloat()
pokemonInfoWidget.rotationY = (((pokemonInfoWidget.rotationY + dragOffsetY) % 360 + 360) % 360)
} else if (activeDragableElement == tabInfoElement) {
tabInfoElement.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
oldDragPosX = mouseX
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
@@ -597,8 +551,6 @@ class PokedexGUI private constructor(
selectedForm = CobblemonClient.clientPokedexData.getEncounteredForms(newSelectedEntry).firstOrNull()
pokemonInfoWidget.setDexEntry(selectedEntry!!)
pokemonNameWidget.update(selectedEntry!!)
displaytabInfoElement(tabInfoIndex)
}
@@ -610,7 +562,7 @@ class PokedexGUI private constructor(
for (i in tabIcons.indices) {
tabButtons.add(ScaledButton(
x + BASE_WIDTH / 2 + ICONS_PADDING_AROUND + i * ICONS_PADDING_BETWEEN,
x + 190.5F + (i * 22F),
y + 181.5F,
TAB_ICON_SIZE,
TAB_ICON_SIZE,
@@ -623,8 +575,6 @@ class PokedexGUI private constructor(
}
fun displaytabInfoElement(tabIndex: Int, update: Boolean = true) {
if (tabIndex != TAB_EVOLUTION_TREE) evolutionTreeExpanded = false
val showActiveTab = selectedEntry?.let { selectedForm in getSufficientlyKnownForms(it, tabIndex) } == true
var statSubIndex = 0
@@ -676,9 +626,6 @@ class PokedexGUI private constructor(
TAB_MOVES -> {
tabInfoElement = MovesLearnsetWidget(x + 180, y + 28)
}
TAB_EVOLUTION_TREE -> {
tabInfoElement = EvolutionTreeWidget(this, x, y)
}
}
val element = tabInfoElement
if (element is Renderable && element is NarratableEntry) {
@@ -753,9 +700,6 @@ class PokedexGUI private constructor(
selectedForm = fallbackForm
) { next -> cycleSelectedForm(next) }
}
TAB_EVOLUTION_TREE -> {
(tabInfoElement as EvolutionTreeWidget).setup(selectedEntry, selectedForm)
}
}
} else {
if (tabInfoIndex != TAB_DESCRIPTION) displaytabInfoElement(TAB_DESCRIPTION)
@@ -16,8 +16,6 @@ object PokedexGUIConstants {
const val HEADER_BAR_HEIGHT = 11
const val POKEMON_DESCRIPTION_HEIGHT = 42
const val POKEMON_DESCRIPTION_PADDING = 9
const val ICONS_PADDING_AROUND = 18.5f
const val ICONS_ARROW_PADDING_AROUND = ICONS_PADDING_AROUND + 1
const val TAB_ICON_SIZE = 16
@@ -38,7 +36,6 @@ object PokedexGUIConstants {
const val TAB_STATS = 3
const val TAB_DROPS = 4
const val TAB_MOVES = 5
const val TAB_EVOLUTION_TREE = 6
// RowScrollingWidget
const val SCROLL_BASE_HEIGHT = 141
@@ -20,95 +20,31 @@ import net.minecraft.network.chat.MutableComponent
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
fun renderTooltip(
context: GuiGraphics,
text: MutableComponent,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
renderTooltip(
context,
listOf(text),
posX,
posY,
delta,
offsetY,
)
}
fun renderTooltip(
context: GuiGraphics,
text: List<MutableComponent>,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
fun renderTooltip(context: GuiGraphics, text: MutableComponent, posX: Int, posY: Int, delta: Float, offsetY: Int = 0) {
val poseStack = context.pose()
val textWidth = text.maxOf { Minecraft.getInstance().font.width(it.font(CobblemonResources.DEFAULT_LARGE)) }
val tooltipPadding = 6
val tooltipWidth = textWidth + tooltipPadding
val textWidth = Minecraft.getInstance().font.width(text.font(CobblemonResources.DEFAULT_LARGE))
val tooltipWidth = textWidth + 6
val tooltipHeight = 11
val tooltipTop = posY + offsetY
poseStack.pushPose()
poseStack.translate(0.0, 0.0, 1000.0)
Minecraft.getInstance().let {
it.mainRenderTarget.bindWrite(false)
context.enableScissor(
posX - (tooltipWidth / 2),
tooltipTop + 1,
(posX - (tooltipWidth / 2)) + tooltipWidth,
tooltipTop + tooltipHeight * text.size - 1
tooltipTop + 10
)
it.gameRenderer.processBlurEffect(delta)
context.disableScissor()
it.mainRenderTarget.bindWrite(true)
}
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX - (tooltipWidth / 2) - 1,
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipBackground,
x = posX - (tooltipWidth / 2),
y = tooltipTop,
width = tooltipWidth,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX + (tooltipWidth / 2),
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
val centered = text.size == 1
text.forEachIndexed { index, it ->
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = it,
x = if (centered) posX else posX - tooltipWidth / 2 + tooltipPadding / 2,
y = tooltipTop + 1 + (tooltipHeight - 2) * index,
shadow = true,
centered = centered
)
}
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX - (tooltipWidth / 2) - 1, y = tooltipTop, width = 1, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipBackground, x = posX - (tooltipWidth / 2), y = tooltipTop, width = tooltipWidth, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX + (tooltipWidth / 2), y = tooltipTop, width = 1, height = tooltipHeight)
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = text, x = posX, y = tooltipTop + 1, shadow = true, centered = true)
poseStack.popPose()
}
@@ -20,8 +20,8 @@ import net.minecraft.client.sounds.SoundManager
import net.minecraft.resources.ResourceLocation
class ScaledButton(
buttonX: Float,
buttonY: Float,
var buttonX: Float,
var buttonY: Float,
val buttonWidth: Number,
val buttonHeight: Number,
var resource: ResourceLocation? = null,
@@ -30,18 +30,6 @@ class ScaledButton(
val clickAction: Button.OnPress
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
var buttonX: Float = buttonX
set(value) {
field = value
this.x = value.toInt()
}
var buttonY: Float = buttonY
set(value) {
field = value
this.y = value.toInt()
}
var isWidgetActive = false
var isVisible = true
@@ -12,13 +12,14 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.ScrollingWidget
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BAR_WIDTH
@@ -26,14 +27,19 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BA
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SPACING
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget.PokemonScrollSlotRow
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.util.Mth
import org.joml.Quaternionf
import org.joml.Vector3f
class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (PokedexEntry) -> (Unit)): ScrollingWidget<PokemonScrollSlotRow>(
width = PokedexGUIConstants.HALF_OVERLAY_WIDTH,
@@ -129,6 +135,13 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
val discoveryLevelList: MutableList<PokedexEntryProgress>,
val setPokedexEntry : (PokedexEntry) -> (Unit)
): Slot<PokemonScrollSlotRow>() {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
}
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -148,42 +161,128 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
hovered: Boolean,
tickDelta: Float
) {
dexDataList.forEachIndexed { index, pokedexEntry ->
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)
dexDataList.forEachIndexed { index, dexData ->
val state = FloatingState()
val species = PokemonSpecies.getByIdentifier(dexData.speciesId)
//FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = (species?.nationalPokedexNumber?.toString() ?: "0").padStart(4, '0')
val speciesNumber = pokemonNumber.text()
val discoveryLevel = discoveryLevelList[index]
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).firstOrNull()
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(dexData).firstOrNull()
val shouldDrawMon = firstVisibleForm != null
if (species == null) {
return@forEachIndexed
}
val renderablePokemon =
if (firstVisibleForm != null) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(pokedexEntry)
val variationAspects = pokedexEntry.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
val aspectsToDraw = (pokedexEntry.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
}
val matrices = context.pose()
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
val startPosX = x + ((SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index)
val startPosY = y + SCROLL_SLOT_SPACING + 1
PokemonSlotWidget.render(
context,
x = x + (SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index,
y = y + SCROLL_SLOT_SPACING + 1,
getHoveredSlotIndex(mouseX, mouseY) == index,
species,
renderablePokemon,
discoveryLevel,
blitk(
matrixStack = matrices,
texture = slotResource,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE
)
if (getHoveredSlotIndex(mouseX, mouseY) == index) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2
)
}
if (shouldDrawMon) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(dexData, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(dexData, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(dexData)
val variationAspects = dexData.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
context.enableScissor(
startPosX + 1,
startPosY + 1,
startPosX + SCROLL_SLOT_SIZE - 1,
startPosY + SCROLL_SLOT_SIZE - 2
)
val aspectsToDraw = (dexData.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
}
state.currentAspects = aspectsToDraw
matrices.pushPose()
matrices.translate(startPosX + (SCROLL_SLOT_SIZE / 2.0), startPosY + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
drawProfilePokemon(
renderablePokemon = RenderablePokemon(species, aspectsToDraw),
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = startPosX + 8.5,
y = startPosY + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (startPosX + 14) / SCALE,
y = (startPosY + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = startPosX + 1.5,//2,
y = startPosY + 2.5,//2
shadow = true,
scale = SCALE
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (startPosX + 18) / SCALE,
y = (startPosY + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexCosmeticVariation
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.bold
@@ -24,9 +24,8 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.PORTRAIT_POKE_BALL_HEIGHT
@@ -52,13 +51,15 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import org.joml.Quaternionf
import org.joml.Vector3f
import java.io.FileNotFoundException
class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
@@ -80,6 +81,7 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
private val arrowFormLeft = cobblemonResource("textures/gui/pokedex/forms_arrow_left.png")
private val arrowFormRight = cobblemonResource("textures/gui/pokedex/forms_arrow_right.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
private val typeBar = cobblemonResource("textures/gui/pokedex/type_bar.png")
private val typeBarDouble = cobblemonResource("textures/gui/pokedex/type_bar_double.png")
@@ -97,6 +99,9 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
var currentEntry : PokedexEntry? = null
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -105,6 +110,10 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
var selectedFormIndex: Int = 0
var type: Array<ElementalType?> = arrayOf(null, null)
var seenShinyStates: Set<String> = setOf()
var shiny = false
var maleRatio = -1F
var gender: Gender = Gender.GENDERLESS
var renderablePokemon : RenderablePokemon? = null
@@ -185,10 +194,7 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
20,
resource = buttonGenderMale,
clickAction = {
val maleRatio = parent.maleRatio
if (maleRatio > 0 && maleRatio < 1) {
parent.gender = if (parent.gender == Gender.MALE) Gender.FEMALE else Gender.MALE
}
if (maleRatio > 0 && maleRatio < 1) gender = if (gender == Gender.MALE) Gender.FEMALE else Gender.MALE
updateAspects()
}
).apply { addWidget(this) }
@@ -200,8 +206,8 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
20,
buttonNone,
clickAction = {
if (parent.seenShinyStates.size > 1) {
parent.shiny = !parent.shiny
if (seenShinyStates.size > 1) {
shiny = !shiny
updateAspects()
}
}
@@ -256,7 +262,8 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val currentEntry = this.currentEntry ?: return
val hasKnowledge = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val hasKnowledge =
CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val species = currentEntry.speciesId.let { PokemonSpecies.getByIdentifier(it) } ?: return
val matrices = context.pose()
@@ -269,6 +276,37 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
height = HALF_OVERLAY_HEIGHT
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = (if (hasKnowledge) speciesName else lang("ui.generic.question_marks")).bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
// Caught icon
if (isSelectedPokemonOwned()) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
if (!suppressViewport) {
blitk(
matrixStack = matrices,
@@ -531,6 +569,8 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
if (species != null) {
this.visibleForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).toMutableList()
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
if (forms.isNotEmpty()) {
formLeftButton.active = true
@@ -556,23 +596,23 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
variationButtons.forEach { removeWidget(it.getWidget()) }
variationButtons.clear()
parent.seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
parent.shiny = parent.seenShinyStates.count() == 1 && parent.seenShinyStates.first() == "shiny"
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
shinyButton.visible = parent.shiny || parent.seenShinyStates.size > 1
shinyButton.active = parent.seenShinyStates.size > 1
seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
shiny = seenShinyStates.count() == 1 && seenShinyStates.first() == "shiny"
shinyButton.resource = if (shiny) buttonShiny else buttonNone
shinyButton.visible = shiny || seenShinyStates.size > 1
shinyButton.active = seenShinyStates.size > 1
val form = species.forms.find { it.name.equals(pokedexForm.displayForm, ignoreCase = true) } ?: species.standardForm
parent.maleRatio = form.maleRatio
maleRatio = form.maleRatio
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, pokedexForm)
val visibleGenders = seenGenders.filter { it != Gender.GENDERLESS }
if (visibleGenders.isEmpty()) {
parent.gender = Gender.GENDERLESS
gender = Gender.GENDERLESS
genderButton.visible = false
genderButton.active = false
} else {
parent.gender = visibleGenders.first()
gender = visibleGenders.first()
genderButton.visible = true
genderButton.active = visibleGenders.size > 1
}
@@ -651,8 +691,8 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
return
}
genderButton.resource = if (parent.gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
genderButton.resource = if (gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (shiny) buttonShiny else buttonNone
val species = currentEntry?.speciesId?.let { PokemonSpecies.getByIdentifier(it) }
if (species != null) {
@@ -661,14 +701,12 @@ class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val up
updateType(species, form)
val aspects = parent.aspects
aspects.clear()
val aspects = mutableSetOf<String>()
if (shiny) aspects.add(SHINY_ASPECT.aspect)
if (parent.shiny) aspects.add(SHINY_ASPECT.aspect)
if (parent.gender == Gender.FEMALE) {
if (gender == Gender.FEMALE) {
aspects.add("female")
} else if (parent.gender == Gender.MALE) {
} else if (gender == Gender.MALE) {
aspects.add("male")
}
@@ -1,100 +0,0 @@
/*
* 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.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
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.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class PokemonNameWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
POKEMON_PORTRAIT_HEIGHT,
lang("ui.pokedex.pokemon_name"),
) {
companion object {
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
}
var hasKnowledge: Boolean = false
var isOwned: Boolean = false
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
override fun renderWidget(
context: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float
) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
if (hasKnowledge) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesName.bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
}
if (isOwned) {
blitk(
matrixStack = context.pose(),
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
}
fun update(pokedexEntry: PokedexEntry) {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId) ?: return
val progress = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(pokedexEntry.speciesId)
this.hasKnowledge = progress != PokedexEntryProgress.UNREGISTERED
this.isOwned = progress == PokedexEntryProgress.OWNED
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
}
}
@@ -1,151 +0,0 @@
/*
* 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.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.GuiGraphics
import org.joml.Quaternionf
import org.joml.Vector3f
abstract class PokemonSlotWidget {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
fun render(
context: GuiGraphics,
x: Int,
y: Int,
isHovered: Boolean,
species: Species,
renderablePokemon: RenderablePokemon?,
discoveryLevel: PokedexEntryProgress,
) {
val shouldDrawMon = renderablePokemon != null
// FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = species.nationalPokedexNumber.toString().padStart(4, '0')
val speciesNumber = pokemonNumber.text()
val matrices = context.pose()
blitk(
matrixStack = matrices,
texture = slotResource,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
)
if (isHovered) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2,
)
}
if (shouldDrawMon && discoveryLevel != PokedexEntryProgress.UNREGISTERED) {
context.enableScissor(
x + 1,
y + 1,
x + SCROLL_SLOT_SIZE - 1,
y + SCROLL_SLOT_SIZE - 2,
)
matrices.pushPose()
matrices.translate(x + SCROLL_SLOT_SIZE / 2.0, y + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
val state = FloatingState()
state.currentAspects = renderablePokemon.aspects
drawProfilePokemon(
renderablePokemon = renderablePokemon,
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = x + 8.5,
y = y + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (x + 14) / SCALE,
y = (y + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = x + 1.5,
y = y + 2.5,
shadow = true,
scale = SCALE
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (x + 18) / SCALE,
y = (y + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
}
@@ -1,124 +0,0 @@
/*
* 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.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionVisitor
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class EvolutionTreeEvolutionVisitor : EvolutionVisitor<RenderEvolutionData?> {
data class RenderEvolutionData(
val label: MutableComponent,
val icons: List<Item>,
val tooltips: List<MutableComponent>,
)
private val requirementVisitor = EvolutionTreeRequirementVisitor()
private fun visitRequirement(requirement: Requirement): RenderRequirementData? {
val icon = requirement.pokedexIcon?.let {
Minecraft.getInstance()?.player?.level()?.itemRegistry?.get(it)
}
val tooltip = requirement.pokedexTooltip?.let {
Component.translatable(it)
}
if (icon != null && tooltip != null) {
return RenderRequirementData(icon, tooltip)
}
return requirementVisitor.visit(requirement)
}
override fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): RenderEvolutionData? {
return null
}
override fun visitDummyEvolution(evolution: Evolution): RenderEvolutionData? {
return null
}
override fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.item_interact.label").bold()
val item = itemInteractionEvolution.requiredContext.items.get().first().value()
val icons = mutableListOf(item)
val tooltips =
mutableListOf(lang("ui.pokedex.evolution.item_interact.tooltip", item.description.plainCopy().green()))
val requirementsDataList = itemInteractionEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
override fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): RenderEvolutionData? {
val requirementsDataList = levelUpEvolution.requirements.map { requirement ->
visitRequirement(requirement)
}
val label = requirementsDataList.firstNotNullOfOrNull { requirement -> requirement?.label }
val icons = requirementsDataList.mapNotNull { requirementData -> requirementData?.icon }
val tooltips = requirementsDataList.mapNotNull { requirementData -> requirementData?.tooltip }
return RenderEvolutionData(label ?: Component.literal(""), icons, tooltips)
}
override fun visitTradeEvolution(tradeEvolution: TradeEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.trade.label")
val icons = mutableListOf<Item>(CobblemonItems.LINK_CABLE)
val tooltips = mutableListOf<MutableComponent>()
val species = tradeEvolution.requiredContext.species
if (species == null) {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_any_species"))
} else {
PokemonSpecies.getByIdentifier(cobblemonResource(species))?.let {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.green()))
}
}
val requirementsDataList = tradeEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
}
@@ -1,271 +0,0 @@
/*
* 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.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.requirement.RequirementVisitor
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.requirements.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
class EvolutionTreeRequirementVisitor : RequirementVisitor<RenderRequirementData?> {
data class RenderRequirementData(
val icon: Item,
val tooltip: MutableComponent,
val label: MutableComponent? = null,
)
override fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): RenderRequirementData? {
val icon = Items.BOOK
val advancementLanguageKey = advancementRequirement.requiredAdvancement.toLanguageKey()
val advancementComponent = Component.translatable("advancements.$advancementLanguageKey").green()
val tooltip = lang("ui.pokedex.requirement.advancement.tooltip", advancementComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitAnyRequirement(anyRequirement: AnyRequirement): RenderRequirementData? {
return null
}
override fun visitAreaRequirement(areaRequirement: AreaRequirement): RenderRequirementData? {
return null
}
override fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): RenderRequirementData? {
return null
}
override fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): RenderRequirementData? {
val icon = CobblemonItems.MEDICINAL_LEEK
val criticalsComponent = Component.literal(battleCriticalHitsRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.battle_critical_hits.tooltip", criticalsComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): RenderRequirementData? {
return null
}
override fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): RenderRequirementData? {
val icon = Items.LEATHER_BOOTS
val blocksComponent = Component.literal(blocksTraveledRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.blocks_traveled.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): RenderRequirementData? {
val icon = CobblemonItems.PUNCHING_GLOVE
val blocksComponent = Component.literal(damageTakenRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.damage_taken.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): RenderRequirementData? {
val species = defeatRequirement.target.species?.let { PokemonSpecies.getByIdentifier(cobblemonResource(it)) } ?: return null
val icon = CobblemonItems.PUNCHING_GLOVE
val defeatedAmount = defeatRequirement.amount
val descriptionComponent = Component.literal(defeatedAmount.toString()).plainCopy().add(" ").add(species.translatedName).green()
val tooltip = lang("ui.pokedex.requirement.defeat.tooltip", descriptionComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): RenderRequirementData? {
val icon = CobblemonItems.SOOTHE_BELL
val friendshipAmountComponent = Component.literal(friendshipRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.friendship.tooltip", friendshipAmountComponent)
val label = lang("ui.pokedex.requirement.friendship.label")
return RenderRequirementData(icon, tooltip, label)
}
override fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): RenderRequirementData? {
val item = heldItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitLevelRequirement(levelRequirement: LevelRequirement): RenderRequirementData? {
val minLevel = levelRequirement.minLevel
val maxLevel = levelRequirement.maxLevel
val icon = CobblemonItems.RARE_CANDY
val tooltip =
if (minLevel == maxLevel || maxLevel == Int.MAX_VALUE)
lang("ui.pokedex.requirement.level.tooltip.min", Component.literal(minLevel.toString()).green())
else
lang("ui.pokedex.requirement.level.tooltip.between", Component.literal(minLevel.toString()).green(), Component.literal(maxLevel.toString()).green())
val label = lang("ui.pokedex.requirement.level.label", minLevel)
return RenderRequirementData(icon, tooltip, label)
}
override fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().green()
val tooltip = lang("ui.pokedex.requirement.moon_phase.tooltip", moonPhaseComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): RenderRequirementData? {
val icon = CobblemonItems.PP_MAX
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): RenderRequirementData? {
val type = ElementalTypes.get(moveTypeRequirement.type.name)
val icon = when (type) {
ElementalTypes.NORMAL -> CobblemonItems.NORMAL_GEM
ElementalTypes.FIRE -> CobblemonItems.FIRE_GEM
ElementalTypes.WATER -> CobblemonItems.WATER_GEM
ElementalTypes.GRASS -> CobblemonItems.GRASS_GEM
ElementalTypes.ELECTRIC -> CobblemonItems.ELECTRIC_GEM
ElementalTypes.ICE -> CobblemonItems.ICE_GEM
ElementalTypes.FIGHTING -> CobblemonItems.FIGHTING_GEM
ElementalTypes.POISON -> CobblemonItems.POISON_GEM
ElementalTypes.GROUND -> CobblemonItems.GROUND_GEM
ElementalTypes.FLYING -> CobblemonItems.FLYING_GEM
ElementalTypes.PSYCHIC -> CobblemonItems.PSYCHIC_GEM
ElementalTypes.BUG -> CobblemonItems.BUG_GEM
ElementalTypes.ROCK -> CobblemonItems.ROCK_GEM
ElementalTypes.GHOST -> CobblemonItems.GHOST_GEM
ElementalTypes.DRAGON -> CobblemonItems.DRAGON_GEM
ElementalTypes.DARK -> CobblemonItems.DARK_GEM
ElementalTypes.STEEL -> CobblemonItems.STEEL_GEM
ElementalTypes.FAIRY -> CobblemonItems.FAIRY_GEM
else -> CobblemonItems.NORMAL_GEM
}
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.green())
val label = lang("ui.pokedex.requirement.has_move_type.label")
return RenderRequirementData(icon, tooltip, label)
}
// TODO test
override fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): RenderRequirementData? {
val item = ownerHoldsItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.owner_held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): RenderRequirementData? {
return null
}
override fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): RenderRequirementData? {
return null
}
override fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): RenderRequirementData? {
return null
}
override fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): RenderRequirementData? {
val icon = CobblemonItems.LIFE_ORB
val recoilComponent = Component.literal(recoilRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.recoil.tooltip", recoilComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): RenderRequirementData? {
val highStat = Stats.getStat(statCompareRequirement.highStat)
val lowStat = Stats.getStat(statCompareRequirement.lowStat)
val icon = when (highStat) {
Stats.HP, Stats.EVASION, Stats.ACCURACY -> CobblemonItems.HEALTH_MOCHI
Stats.ATTACK -> CobblemonItems.MUSCLE_MOCHI
Stats.DEFENCE -> CobblemonItems.RESIST_MOCHI
Stats.SPECIAL_ATTACK -> CobblemonItems.GENIUS_MOCHI
Stats.SPECIAL_DEFENCE -> CobblemonItems.CLEVER_MOCHI
Stats.SPEED -> CobblemonItems.SWIFT_MOCHI
}
val highStatComponent = highStat.displayName.plainCopy().green()
val lowStatComponent = lowStat.displayName.plainCopy().green()
val tooltip = lang("ui.pokedex.requirement.stat_compare.tooltip", highStatComponent, lowStatComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): RenderRequirementData? {
val statOne = Stats.getStat(statEqualRequirement.statOne)
val statTwo = Stats.getStat(statEqualRequirement.statTwo)
val statOneComponent = statOne.displayName.plainCopy().green()
val statTwoComponent = statTwo.displayName.plainCopy().green()
val icon = CobblemonItems.FRESH_START_MOCHI
val tooltip = lang("ui.pokedex.requirement.stat_equal.tooltip", statOneComponent, statTwoComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStructureRequirement(structureRequirement: StructureRequirement): RenderRequirementData? {
return null
}
override fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val timeRangeComponent = timeRangeRequirement.range.displayName() ?: return null
val tooltip = lang("ui.pokedex.requirement.time_range.tooltip", timeRangeComponent.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): RenderRequirementData? {
val icon = CobblemonItems.CHOICE_BAND
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
return null
}
override fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): RenderRequirementData? {
var icon: Item
var tooltip: MutableComponent
if (weatherRequirement.isThundering == true) {
icon = Items.LIGHTNING_ROD
tooltip = lang("ui.pokedex.requirement.weather.tooltip.thundering")
} else {
icon = Items.WATER_BUCKET
tooltip = lang("ui.pokedex.requirement.weather.tooltip.raining")
}
return RenderRequirementData(icon, tooltip)
}
override fun visitWorldRequirement(worldRequirement: WorldRequirement): RenderRequirementData? {
return null
}
}
@@ -1,552 +0,0 @@
/*
* 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.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.gui.*
import com.cobblemon.mod.common.api.pokedex.Dexes
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_DESCRIPTION_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.ScaledButton
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonSlotWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class EvolutionTreeWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX, pY,
HALF_OVERLAY_WIDTH,
POKEMON_DESCRIPTION_HEIGHT,
lang("ui.pokedex.pokemon_info")
) {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val expandResource = cobblemonResource("textures/gui/pokedex/expand.png")
private val minimizeResource = cobblemonResource("textures/gui/pokedex/minimize.png")
const val X_MARGIN = 180
const val Y_MARGIN_MINIMIZED = 135
const val Y_MARGIN_EXPANDED = 53
const val EXPANDED_HEIGHT = 125
const val HORIZONTAL_PADDING = 38
const val VERTICAL_PADDING = 2
const val TREE_FORK_LENGTH = 4
const val ICON_X_PADDING = -4.0
const val ICON_Y_PADDING = -4.0
const val MILLIS_BETWEEN_ICONS_CYCLE = 1000
const val ICON_SLOT_BACKGROUND_SIZE = 8
const val ICON_SLOT_PADDING = 4
const val ICON_SLOT_HALF_PADDING = ICON_SLOT_PADDING / 2
const val LINE_COLOR = 0xff1d6b85.toInt()
const val EXPAND_BUTTON_X_MARGIN = 127f
const val EXPAND_BUTTON_Y_MARGIN = -10.5f
const val EXPAND_BUTTON_SIZE = 20
private var previousRootPokedexEntry: PokedexEntry? = null
private var previousRootPokedexForm: PokedexForm? = null
private val evolutionVisitor = EvolutionTreeEvolutionVisitor()
}
private var rootTreeDrawingNode: TreeDrawingNode<EvolutionNode>? = null
private var treeDrawingBounds: TreeDrawingBounds? = null
private var zoomLevel: Double = 0.0
private var panningX: Double = 0.0
private var panningY: Double = 0.0
private var hoveredTooltips: List<MutableComponent>? = null
private val expandButton: ScaledButton = ScaledButton(
0f,
0f,
EXPAND_BUTTON_SIZE,
EXPAND_BUTTON_SIZE,
resource = expandResource,
clickAction = {
parent.evolutionTreeExpanded = !parent.evolutionTreeExpanded
expandButton.resource = if (parent.evolutionTreeExpanded) minimizeResource else expandResource
updatePositioning()
}
).apply { addWidget(this) }
override fun renderWidget(
guiGraphics: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float,
) {
drawScaledText(
context = guiGraphics,
font = CobblemonResources.DEFAULT_LARGE,
text = Component.translatable("cobblemon.ui.pokedex.info.evolution_tree").bold(),
x = x + 9,
y = y - 10,
shadow = true
)
expandButton.render(guiGraphics, mouseX, mouseY, partialTick)
rootTreeDrawingNode?.let {
enableScissors(guiGraphics)
renderTreeDrawingNode(guiGraphics, it, mouseX, mouseY, partialTick)
guiGraphics.disableScissor()
hoveredTooltips?.let { tooltips ->
renderTooltip(
guiGraphics,
tooltips,
mouseX,
mouseY,
partialTick,
4,
)
}
hoveredTooltips = null
}
}
fun setup(pokedexEntry: PokedexEntry?, pokedexForm: PokedexForm?) {
if (pokedexEntry == null || pokedexForm == null) return
updatePositioning()
val (rootPokedexEntry, rootPokedexForm) = Dexes.findRootDexEntryBySpeciesId(pokedexEntry.speciesId, pokedexForm.displayForm)
val rootEvolutionNode = buildEvolutionTree(rootPokedexEntry, rootPokedexForm, null)
// val isSameEntry = previousRootPokedexEntry != null && pokedexEntry?.id == previousRootPokedexEntry?.id
// val isSameForm =
// previousRootPokedexForm != null && pokedexForm?.displayForm == previousRootPokedexForm?.displayForm
// TODO: figure out how to prevent pokedex from resetting all the widgets state
// if (isSameEntry && isSameForm) {
// return
// }
previousRootPokedexEntry = pokedexEntry
previousRootPokedexForm = pokedexForm
createDrawingTree(rootEvolutionNode).also {
rootTreeDrawingNode = it
treeDrawingBounds = calculateBounds<EvolutionNode>(it)
}
zoomLevel = 0.0
panningX = 0.0
panningY = 0.0
}
fun updatePositioning() {
x = pX + X_MARGIN
y = pY + if (parent.evolutionTreeExpanded) Y_MARGIN_EXPANDED else Y_MARGIN_MINIMIZED
height = if (parent.evolutionTreeExpanded) EXPANDED_HEIGHT else POKEMON_DESCRIPTION_HEIGHT
panningX = 0.0
panningY = 0.0
expandButton.buttonX = x + EXPAND_BUTTON_X_MARGIN
expandButton.buttonY = y + EXPAND_BUTTON_Y_MARGIN
}
private fun buildEvolutionTree(
pokedexEntry: PokedexEntry,
pokedexForm: PokedexForm,
evolution: Evolution? = null
): EvolutionNode {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)!!
val formEquivalents = Dexes.getFormEquivalents(pokedexForm.displayForm)
val form = species.forms.firstOrNull { formEquivalents.contains(it.name.lowercase()) }
val parentSpecies = Dexes.findDexEntryBySpeciesId(species.resourceIdentifier)!!
val parentPokedexForm = parentSpecies.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
val aspects = evolution?.result?.aspects?.toMutableSet() ?: mutableSetOf()
form?.aspects?.let { aspects.addAll(it) }
val discoveryLevel = CobblemonClient.clientPokedexData.getHighestKnowledgeFor(pokedexEntry, pokedexForm, aspects)
val evolutions = form?.evolutions ?: species.evolutions
val drawData = evolution?.let { evolutionVisitor.visit(evolution) }
// TODO: figure out if this works for fakemon
val children = evolutions.mapNotNull { evolution ->
val speciesId = cobblemonResource(evolution.result.species!!)
val childPokedexEntry =
Dexes.findDexEntryBySpeciesId(speciesId)
if (childPokedexEntry == null) {
Cobblemon.LOGGER.warn("Dex entry not found for species: $speciesId")
return@mapNotNull null
}
val evolutionResult = evolution.result.create()
val formEquivalents = Dexes.getFormEquivalents(evolutionResult.form.name.lowercase())
val childPokedexForm = childPokedexEntry.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
return@mapNotNull buildEvolutionTree(childPokedexEntry, childPokedexForm, evolution)
}
return EvolutionNode(pokedexEntry, parentPokedexForm, aspects, discoveryLevel, children, drawData)
}
private fun renderTreeDrawingNode(
guiGraphics: GuiGraphics,
treeDrawingNode: TreeDrawingNode<EvolutionNode>,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val (treeX, treeY) = getDrawingCoordinates(treeDrawingNode)
if (treeDrawingNode.children.size == 1) {
val child = treeDrawingNode.children.first()
val (childX, _) = getDrawingCoordinates(child)
val lineStartX = treeX + SCROLL_SLOT_SIZE
val lineEndX = childX
val lineY = treeY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
} else if (treeDrawingNode.children.size > 1) {
val treeForkStart = treeX + SCROLL_SLOT_SIZE
val treeForkEnd = treeX + SCROLL_SLOT_SIZE + TREE_FORK_LENGTH
val middleStart = treeY + SCROLL_SLOT_SIZE / 2
val (_, firstChildY) = getDrawingCoordinates(treeDrawingNode.children.first())
val (_, lastChildY) = getDrawingCoordinates(treeDrawingNode.children.last())
guiGraphics.hLine(
treeForkStart,
treeForkEnd,
middleStart,
LINE_COLOR,
)
guiGraphics.vLine(
treeForkEnd,
firstChildY + SCROLL_SLOT_SIZE / 2,
lastChildY + SCROLL_SLOT_SIZE / 2,
LINE_COLOR,
)
treeDrawingNode.children.forEach { child ->
val (childX, childY) = getDrawingCoordinates(child)
val lineStartX = treeForkEnd
val lineEndX = childX
val lineY = childY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
}
}
treeDrawingNode.children.forEach { child ->
renderTreeDrawingNode(guiGraphics, child, mouseX, mouseY, delta)
}
val isVisible =
treeX >= x - SCROLL_SLOT_SIZE &&
treeX <= x + width &&
treeY >= y - SCROLL_SLOT_SIZE &&
treeY <= y + height
if (!isVisible) return
val evolutionNode = treeDrawingNode.value
val isSlotHovered =
isElementHovered(mouseX, mouseY, treeX, treeX + SCROLL_SLOT_SIZE, treeY, treeY + SCROLL_SLOT_SIZE)
val discoveryLevel = evolutionNode.pokedexEntryProgress
if (isSlotHovered) {
val text =
if (discoveryLevel == PokedexEntryProgress.UNREGISTERED) {
lang("ui.pokedex.unknown")
} else {
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val speciesComponent = species.translatedName
val formName = evolutionNode.pokedexForm.displayForm.lowercase()
val formComponent =
if (formName == "normal") null
else lang("ui.pokedex.info.form.${species}-${formName.replace("-", "")}")
formComponent?.add(" ")?.add(speciesComponent) ?: speciesComponent
}
guiGraphics.disableScissor()
renderTooltip(
context = guiGraphics,
text = text,
posX = mouseX,
posY = mouseY,
delta,
4,
)
enableScissors(guiGraphics)
}
val pokedexEntry = evolutionNode.pokedexEntry
val pokedexForm = evolutionNode.pokedexForm
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val encounteredForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry)
val formToRender = encounteredForms.firstOrNull { it.displayForm.equals(pokedexForm.displayForm, ignoreCase = true) }
val renderablePokemon =
if (formToRender != null) {
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, formToRender)
val seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, formToRender)
val aspectsToDraw = (pokedexEntry.displayAspects + evolutionNode.aspects).toMutableSet()
val formAspects = species.forms.firstOrNull { it.name.equals(formToRender.displayForm, ignoreCase = true) }?.aspects
if (formAspects != null) {
aspectsToDraw.addAll(formAspects)
}
if (seenGenders.contains(parent.gender)) {
aspectsToDraw.add(parent.gender.name.lowercase())
} else {
aspectsToDraw.add((seenGenders.firstOrNull() ?: Gender.GENDERLESS).name.lowercase())
}
if (parent.shiny && seenShinyStates.contains("shiny")) {
aspectsToDraw.add("shiny")
}
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
PokemonSlotWidget.render(
context = guiGraphics,
x = treeX,
y = treeY,
isHovered = isSlotHovered,
species = species,
renderablePokemon = renderablePokemon,
discoveryLevel = discoveryLevel,
)
}
private fun drawEvolutionInfo(
guiGraphics: GuiGraphics,
renderData: RenderEvolutionData,
lineStartX: Int,
lineEndX: Int,
lineY: Int,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val lineXMiddle = (lineStartX + lineEndX) / 2
val iconX = (lineXMiddle + ICON_X_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconY = (lineY + ICON_Y_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconSize = ICON_SLOT_BACKGROUND_SIZE + ICON_SLOT_PADDING
val isVisible =
iconX >= x - iconSize &&
iconX <= x + width &&
iconY >= y - iconSize &&
iconY <= y + height
if (!isVisible) {
return
}
if (renderData.icons.isEmpty()) {
guiGraphics.hLine(
lineStartX,
lineEndX,
lineY,
LINE_COLOR,
)
} else {
guiGraphics.hLine(
lineStartX,
iconX - 1,
lineY,
LINE_COLOR,
)
guiGraphics.hLine(
iconX + iconSize,
lineEndX,
lineY,
LINE_COLOR,
)
blitk(
matrixStack = guiGraphics.pose(),
texture = slotResource,
x = iconX,
y = iconY,
width = iconSize,
height = iconSize,
)
val index = (System.currentTimeMillis() / MILLIS_BETWEEN_ICONS_CYCLE) % renderData.icons.size
val item = renderData.icons[index.toInt()]
renderScaledGuiItemIcon(
itemStack = item.defaultInstance,
x = lineXMiddle + ICON_X_PADDING,
y = lineY + ICON_Y_PADDING,
matrixStack = guiGraphics.pose(),
scale = PokedexGUIConstants.SCALE.toDouble(),
)
}
val isLineHovered = isElementHovered(mouseX, mouseY, lineStartX, lineEndX, lineY - 1, lineY + 1)
val isIconHovered = isElementHovered(
mouseX,
mouseY,
iconX.toInt(),
iconX.toInt() + iconSize,
iconY.toInt(),
iconY.toInt() + iconSize,
)
if (renderData.tooltips.isNotEmpty() &&
(isLineHovered || isIconHovered) &&
this.isHovered(mouseX.toDouble(), mouseY.toDouble())
) {
hoveredTooltips = renderData.tooltips
}
}
private fun getDrawingCoordinates(node: TreeDrawingNode<EvolutionNode>): Pair<Int, Int> {
val halfSlot = SCROLL_SLOT_SIZE / 2f
val xStep = halfSlot + HORIZONTAL_PADDING
val yStep = halfSlot + VERTICAL_PADDING
// Swaps the x and y to draw the tree horizontally
val xDislocation = (node.y - treeDrawingBounds!!.yCenter) * xStep
val yDislocation = (node.x - treeDrawingBounds!!.xCenter) * yStep
val xCenter = width / 2f - halfSlot
val yCenter = height / 2f - halfSlot
val screenX = (xCenter.toInt() + xDislocation.toInt() + panningX.toInt() + x)
val screenY = (yCenter.toInt() + yDislocation.toInt() + panningY.toInt() + y)
return screenX to screenY
}
private fun isElementHovered(
mouseX: Int,
mouseY: Int,
startX: Int,
endX: Int,
startY: Int,
endY: Int,
): Boolean {
return mouseX >= startX && mouseX <= endX && mouseY >= startY && mouseY <= endY
}
override fun mouseDragged(
mouseX: Double,
mouseY: Double,
button: Int,
deltaX: Double,
deltaY: Double
): Boolean {
panningX += deltaX
panningY += deltaY
val bounds = treeDrawingBounds ?: return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
val treeHeight = bounds.height.coerceAtLeast(1)
val treeWidth = bounds.width.coerceAtLeast(1)
val xStep = HORIZONTAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val yStep = VERTICAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val minPanningX = (treeHeight - 1) * -xStep / 2.0 - (width + SCROLL_SLOT_SIZE) / 2.0
val maxPanningX = (treeHeight - 1) * xStep / 2.0 + (width + SCROLL_SLOT_SIZE) / 2.0
val divideBy = if (treeWidth % 2 == 0) 4.0 else 2.0
val minPanningY = (treeWidth - 1) * -yStep / 2.0 - height / 2.0 + SCROLL_SLOT_SIZE / divideBy
val maxPanningY = (treeWidth - 1) * yStep / 2.0 + height / 2.0 - SCROLL_SLOT_SIZE / divideBy
panningX = panningX.coerceIn(minPanningX, maxPanningX)
panningY = panningY.coerceIn(minPanningY, maxPanningY)
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
fun isHovered(mouseX: Double, mouseY: Double): Boolean {
return mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)
}
fun enableScissors(guiGraphics: GuiGraphics) {
guiGraphics.enableScissor(x + 1, y, x + width - 1, y + height)
}
private class EvolutionNode(
val pokedexEntry: PokedexEntry,
val pokedexForm: PokedexForm,
val aspects: Set<String>,
val pokedexEntryProgress: PokedexEntryProgress,
override val children: List<EvolutionNode>,
val renderData: RenderEvolutionData?,
) : TreeNode<EvolutionNode>
}
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.LevelRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
@@ -39,13 +40,13 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private val leftMargin = 1f
private val rightMargin = 1f
private val topMargin = 1f
private val bottomMargin = 1f
private val interRowSpacing = 0f
private val tmOverlayDepthOffset = -0.0002f
private val slotBrightnessMultiplier = 0.65f
private val tmBaseTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_base.png")
private val tmOverlayTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_overlay.png")
private val musicDiscUnknownTexture = cobblemonResource("textures/block/disc_shelf/music_disc_unknown.png")
override fun render(
entity: DiscShelfBlockEntity,
@@ -77,7 +78,6 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
val slotWidth = slotWidthPixels / textureSize
val slotHeight = slotHeightPixels / textureSize
val verticalSpacing = (slotHeightPixels + interRowSpacing) / textureSize
val totalHeight = slotHeight * 7 + interRowSpacing * 6 / textureSize
val startY = topMargin / textureSize
for ((index, item) in entity.items.withIndex()) {
@@ -188,6 +188,13 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private fun getItemTexture(itemStack: ItemStack): ResourceLocation {
val id = BuiltInRegistries.ITEM.getKey(itemStack.item)
return cobblemonResource("textures/block/disc_shelf/${id.path}.png")
val resource = cobblemonResource("textures/block/disc_shelf/${id.path}.png")
val resourceManager = Minecraft.getInstance().resourceManager
if (resourceManager.getResource(resource).isEmpty) {
return musicDiscUnknownTexture
}
return resource
}
}
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.player.Player
*
* @author whatsy
*/
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement() {
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement {
override fun checkPlayer(
pokemon: Pokemon,
@@ -16,7 +16,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
*
* @property possibilities A collection of possible [Requirement]s that can allow this requirement to be valid.
*/
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement() {
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement {
override fun check(pokemon: Pokemon) = this.possibilities.any { it.check(pokemon) }
companion object {
const val ADAPTER_VARIANT = "any"
@@ -21,7 +21,7 @@ import net.minecraft.world.phys.Vec3
* @author Licious
* @since March 21st, 2022
*/
class AreaRequirement : EntityQueryRequirement() {
class AreaRequirement : EntityQueryRequirement {
companion object {
const val ADAPTER_VARIANT = "area"
}
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class AttackDefenceRatioRequirement : Requirement() {
class AttackDefenceRatioRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "attack_defence_ratio"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHit
* @since October 2nd, 2022
*/
@Suppress("unused", "CanBePrimaryConstructorProperty")
class BattleCriticalHitsRequirement(amount: Int) : Requirement() {
class BattleCriticalHitsRequirement(amount: Int) : Requirement {
constructor() : this(0)
@@ -24,7 +24,7 @@ import net.minecraft.world.level.biome.Biome
* @author Licious
* @since March 21st, 2022
*/
class BiomeRequirement : EntityQueryRequirement() {
class BiomeRequirement : EntityQueryRequirement {
val biomeCondition: RegistryLikeCondition<Biome>? = null
val biomeAnticondition: RegistryLikeCondition<Biome>? = null
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since January 28th, 2023
*/
class BlocksTraveledRequirement(amount: Int) : Requirement() {
class BlocksTraveledRequirement(amount: Int) : Requirement {
constructor() : this(0)
@@ -22,7 +22,7 @@ import kotlin.random.Random
* @author Hiroku
* @since January 30th, 2026
*/
class ChanceRequirement : Requirement() {
class ChanceRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "chance"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionP
* @author Licious
* @since January 27th, 2022
*/
class DamageTakenRequirement(amount: Int) : Requirement() {
class DamageTakenRequirement(amount: Int) : Requirement {
constructor() : this(0)
@@ -22,7 +22,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgre
* @author Licious
* @since January 28th, 2022
*/
class DefeatRequirement(target: PokemonProperties, amount: Int) : Requirement() {
class DefeatRequirement(target: PokemonProperties, amount: Int) : Requirement {
constructor() : this(PokemonProperties(), 0)
@@ -18,7 +18,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class FriendshipRequirement : Requirement() {
class FriendshipRequirement : Requirement {
val amount = 0
override fun check(pokemon: Pokemon) = pokemon.friendship >= this.amount
@@ -20,7 +20,7 @@ import net.minecraft.world.item.Items
* @author Licious
* @since March 21st, 2022
*/
class HeldItemRequirement(val itemCondition: ItemPredicate) : Requirement() {
class HeldItemRequirement(val itemCondition: ItemPredicate) : Requirement {
constructor() : this(ItemPredicate.Builder.item().of(Items.EGG).build())
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class LevelRequirement : Requirement() {
class LevelRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "level"
}
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since January 25th, 2023
*/
class MoonPhaseRequirement(moonPhase: MoonPhase) : EntityQueryRequirement() {
class MoonPhaseRequirement(moonPhase: MoonPhase) : EntityQueryRequirement {
constructor() : this(MoonPhase.FULL_MOON)
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class MoveSetRequirement : Requirement() {
class MoveSetRequirement : Requirement {
val move: MoveTemplate = Moves.getByNameOrDummy("tackle")
override fun check(pokemon: Pokemon) = pokemon.moveSet.getMoves().any { move -> move.name.equals(this.move.name, true) }
companion object {
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.Pokemon
class MoveTypeRequirement : Requirement() {
class MoveTypeRequirement : Requirement {
val type: ElementalType = ElementalTypes.NORMAL
override fun check(pokemon: Pokemon) = pokemon.moveSet.getMoves().any { move -> move.type == type }
companion object {
@@ -24,7 +24,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
*/
class OwnerHoldsItemRequirement(val itemCondition: ItemPredicate)
: OwnerQueryRequirement() {
: OwnerQueryRequirement {
override fun checkPlayer(
pokemon: Pokemon,
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class PartyMemberRequirement : Requirement() {
class PartyMemberRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "party_member"
}
@@ -19,7 +19,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 26th, 2022
*/
class PokemonPropertiesRequirement : Requirement() {
class PokemonPropertiesRequirement : Requirement {
val target = PokemonProperties()
override fun check(pokemon: Pokemon) = this.target.matches(pokemon)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class PropertyRangeRequirement : Requirement() {
class PropertyRangeRequirement : Requirement {
val range = IntRange(0, 256)
val feature: String = ""
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgre
* @author Licious
* @since January 27th, 2022
*/
class RecoilRequirement(amount: Int) : Requirement() {
class RecoilRequirement(amount: Int) : Requirement {
constructor() : this(0)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class StatCompareRequirement : Requirement() {
class StatCompareRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "stat_compare"
}
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class StatEqualRequirement : Requirement() {
class StatEqualRequirement : Requirement {
companion object {
const val ADAPTER_VARIANT = "stat_equal"
}
@@ -22,7 +22,7 @@ import net.minecraft.world.level.levelgen.structure.Structure
* @author whatsy
* @since December 5th, 2023
*/
class StructureRequirement : EntityQueryRequirement() {
class StructureRequirement : EntityQueryRequirement {
val structureCondition: RegistryLikeCondition<Structure>? = null
val structureAnticondition: RegistryLikeCondition<Structure>? = null
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
@@ -20,7 +20,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 26th, 2022
*/
class TimeRangeRequirement : EntityQueryRequirement() {
class TimeRangeRequirement : EntityQueryRequirement {
val range = TimeRange(0..23999)
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity) = this.range.contains((queriedEntity.level().dayTime() % DAY_DURATION).toInt())
companion object {
@@ -23,7 +23,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgr
* @author Licious
* @since January 25th, 2023
*/
class UseMoveRequirement(move: MoveTemplate, amount: Int) : Requirement() {
class UseMoveRequirement(move: MoveTemplate, amount: Int) : Requirement {
constructor() : this(Moves.getByNameOrDummy(""), 1)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.entity.LivingEntity
class WeatherRequirement : EntityQueryRequirement() {
class WeatherRequirement : EntityQueryRequirement {
companion object {
const val ADAPTER_VARIANT = "weather"
}
@@ -21,7 +21,7 @@ import net.minecraft.world.level.Level
* @author Licious
* @since March 21st, 2022
*/
class WorldRequirement : EntityQueryRequirement() {
class WorldRequirement : EntityQueryRequirement {
companion object {
const val ADAPTER_VARIANT = "world"
}
@@ -274,11 +274,9 @@ object DataKeys {
// Habitat Blocks
const val HABITAT_SPAWNING_STYLE = "SpawningStyle"
const val HABITAT_MIMIC = "MimicId"
const val HABITAT_PHASE_COUNT = "PhaseCount"
const val HABITAT_PHASE_ORDER = "PhaseOrder"
const val HABITAT_LEVEL_RANGE = "LevelRange"
const val HABITAT_MODIFIERS = "Modifiers"
const val HABITAT_POOL = "Pool"
// --- Pools
const val HABITAT_POOL_ID = "PoolId"
@@ -281,7 +281,7 @@
},
"animation.luvdisc.ground_faint": {
"loop": true,
"animation_length": 2.5,
"animation_length": 3,
"bones": {
"body": {
"rotation": {
@@ -39,11 +39,11 @@
]
},
{
"name": "locator_seat1",
"name": "locator_seat_1",
"parent": "thorax",
"pivot": [0, 11, 0],
"locators": {
"seat1": [0, 11, 1]
"seat_1": [0, 11, 1]
}
},
{
@@ -79,7 +79,7 @@
"parent": "torso",
"pivot": [0, 21, 3.75],
"locators": {
"seat_2": [0, 21, 3.75]
"seat_1": [0, 21, 3.75]
}
},
{
@@ -78,7 +78,7 @@
"parent": "torso",
"pivot": [0, 21, 3.75],
"locators": {
"seat_2": [0, 21, 3.75]
"seat_1": [0, 21, 3.75]
}
},
{
@@ -377,11 +377,11 @@
]
},
{
"name": "locator_seat1",
"name": "locator_seat_1",
"parent": "saddle",
"pivot": [0, 23.525, 0],
"locators": {
"seat1": [0, 23.525, 0]
"seat_1": [0, 23.525, 0]
}
},
{
@@ -30,6 +30,14 @@
"parent": "body_rotation",
"pivot": [0, 8.5, 0]
},
{
"name": "locator_seat_1",
"parent": "waist_rotation",
"pivot": [0, 36, 0],
"locators": {
"seat_1": [0, 35.75, 8.5]
}
},
{
"name": "waist_scale",
"parent": "waist_rotation",
@@ -188,12 +188,10 @@
"parent": "eyes",
"pivot": [-1.51, 13.3, -1],
"cubes": [
{"origin": [-1.51, 12.8, -2], "size": [0, 1, 2], "uv": [60, 14]},
{"origin": [-1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [56, 14]},
{"origin": [-1.51, 11.3, -2], "size": [0, 1, 2], "uv": [60, 16]},
{"origin": [-1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [56, 16]},
{"origin": [-1.51, 11.8, -2], "size": [0, 1, 2], "uv": [60, 15]},
{"origin": [-1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [56, 15]}
{"origin": [-1.52, 12.8, -2], "size": [0, 1, 1], "uv": [62, 15]},
{"origin": [-1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [56, 13]},
{"origin": [-1.51, 11.3, -2], "size": [0, 2, 3], "uv": [56, 14]},
{"origin": [-1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [62, 16]}
]
},
{
@@ -201,8 +199,8 @@
"parent": "eye_right",
"pivot": [-1.51, 13.8, -0.25],
"cubes": [
{"origin": [-1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [56, 13]},
{"origin": [-1.51, 13.8, -2], "size": [0, 1, 2], "uv": [60, 13]}
{"origin": [-1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [56, 12]},
{"origin": [-1.52, 13.8, -2], "size": [0, 1, 1], "uv": [62, 14]}
]
},
{
@@ -223,7 +221,7 @@
"parent": "pupil_right",
"pivot": [-1.52, 13, -0.25],
"cubes": [
{"origin": [-1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
{"origin": [-1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
]
},
{
@@ -240,7 +238,7 @@
"parent": "pupil_right",
"pivot": [-1.42, 13, -1.25],
"cubes": [
{"origin": [-1.42, 12.5, -1.75], "size": [0, 1, 1], "uv": [1, 1]}
{"origin": [-1.44, 12.5, -1.75], "size": [0, 1, 1], "uv": [1, 1]}
]
},
{
@@ -248,7 +246,7 @@
"parent": "pupil_right",
"pivot": [-1.42, 13, 0.75],
"cubes": [
{"origin": [-1.42, 12.5, 0.25], "size": [0, 1, 1], "uv": [1, 2]}
{"origin": [-1.44, 12.5, 0.25], "size": [0, 1, 1], "uv": [1, 2]}
]
},
{
@@ -272,12 +270,10 @@
"parent": "eyes",
"pivot": [1.51, 13.3, -1],
"cubes": [
{"origin": [1.51, 12.8, -2], "size": [0, 1, 2], "uv": [52, 14], "mirror": true},
{"origin": [1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [48, 14], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 1, 2], "uv": [52, 16], "mirror": true},
{"origin": [1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [48, 16], "mirror": true},
{"origin": [1.51, 11.8, -2], "size": [0, 1, 2], "uv": [52, 15], "mirror": true},
{"origin": [1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [48, 15], "mirror": true}
{"origin": [1.52, 12.8, -2], "size": [0, 1, 1], "uv": [54, 15], "mirror": true},
{"origin": [1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [48, 13], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 2, 3], "uv": [48, 14], "mirror": true},
{"origin": [1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [54, 16], "mirror": true}
]
},
{
@@ -285,8 +281,8 @@
"parent": "eye_left",
"pivot": [1.51, 13.8, -0.25],
"cubes": [
{"origin": [1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [48, 13], "mirror": true},
{"origin": [1.51, 13.8, -2], "size": [0, 1, 2], "uv": [52, 13], "mirror": true}
{"origin": [1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [48, 12], "mirror": true},
{"origin": [1.52, 13.8, -2], "size": [0, 1, 1], "uv": [54, 14], "mirror": true}
]
},
{
@@ -307,7 +303,7 @@
"parent": "pupil_left",
"pivot": [1.52, 13, -0.25],
"cubes": [
{"origin": [1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
{"origin": [1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
]
},
{
@@ -324,7 +320,7 @@
"parent": "pupil_left",
"pivot": [1.42, 13, -1.25],
"cubes": [
{"origin": [1.42, 12.5, -1.75], "size": [0, 1, 1], "uv": [3, 1], "mirror": true}
{"origin": [1.44, 12.5, -1.75], "size": [0, 1, 1], "uv": [3, 1], "mirror": true}
]
},
{
@@ -332,7 +328,7 @@
"parent": "pupil_left",
"pivot": [1.42, 13, 0.75],
"cubes": [
{"origin": [1.42, 12.5, 0.25], "size": [0, 1, 1], "uv": [3, 2], "mirror": true}
{"origin": [1.44, 12.5, 0.25], "size": [0, 1, 1], "uv": [3, 2], "mirror": true}
]
},
{
@@ -188,12 +188,10 @@
"parent": "eyes",
"pivot": [-1.51, 13.3, -1],
"cubes": [
{"origin": [-1.51, 12.8, -2], "size": [0, 1, 2], "uv": [60, 12]},
{"origin": [-1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [56, 12]},
{"origin": [-1.51, 11.3, -2], "size": [0, 1, 2], "uv": [60, 14]},
{"origin": [-1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [56, 14]},
{"origin": [-1.51, 11.8, -2], "size": [0, 1, 2], "uv": [60, 13]},
{"origin": [-1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [56, 13]}
{"origin": [-1.52, 12.8, -2], "size": [0, 1, 1], "uv": [62, 13]},
{"origin": [-1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [56, 11]},
{"origin": [-1.51, 11.3, -2], "size": [0, 2, 3], "uv": [56, 12]},
{"origin": [-1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [62, 14]}
]
},
{
@@ -201,8 +199,8 @@
"parent": "eye_right",
"pivot": [-1.51, 13.8, -0.25],
"cubes": [
{"origin": [-1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [56, 11]},
{"origin": [-1.51, 13.8, -2], "size": [0, 1, 2], "uv": [60, 11]}
{"origin": [-1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [56, 10]},
{"origin": [-1.52, 13.8, -2], "size": [0, 1, 1], "uv": [62, 12]}
]
},
{
@@ -211,7 +209,7 @@
"pivot": [-1.31, 11.6, 1.3],
"cubes": [
{"origin": [-1.81, 10.6, 0.3], "size": [1, 2, 2], "inflate": -0.3, "uv": [58, 17]},
{"origin": [-1.61, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 19]}
{"origin": [-1.62, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 19]}
]
},
{
@@ -224,7 +222,7 @@
"parent": "pupil_right",
"pivot": [-1.52, 13, -0.25],
"cubes": [
{"origin": [-1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
{"origin": [-1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
]
},
{
@@ -257,12 +255,10 @@
"parent": "eyes",
"pivot": [1.51, 13.3, -1],
"cubes": [
{"origin": [1.51, 12.8, -2], "size": [0, 1, 2], "uv": [52, 12], "mirror": true},
{"origin": [1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [48, 12], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 1, 2], "uv": [52, 14], "mirror": true},
{"origin": [1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [48, 14], "mirror": true},
{"origin": [1.51, 11.8, -2], "size": [0, 1, 2], "uv": [52, 13], "mirror": true},
{"origin": [1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [48, 13], "mirror": true}
{"origin": [1.52, 12.8, -2], "size": [0, 1, 1], "uv": [54, 13], "mirror": true},
{"origin": [1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [48, 11], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 2, 3], "uv": [48, 12], "mirror": true},
{"origin": [1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [54, 14], "mirror": true}
]
},
{
@@ -270,8 +266,8 @@
"parent": "eye_left",
"pivot": [1.51, 13.8, -0.25],
"cubes": [
{"origin": [1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [48, 11], "mirror": true},
{"origin": [1.51, 13.8, -2], "size": [0, 1, 2], "uv": [52, 11], "mirror": true}
{"origin": [1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [48, 10], "mirror": true},
{"origin": [1.52, 13.8, -2], "size": [0, 1, 1], "uv": [54, 12], "mirror": true}
]
},
{
@@ -280,7 +276,7 @@
"pivot": [1.31, 11.6, 1.3],
"cubes": [
{"origin": [0.81, 10.6, 0.3], "size": [1, 2, 2], "inflate": -0.3, "uv": [52, 17], "mirror": true},
{"origin": [0.61, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 17], "mirror": true}
{"origin": [0.62, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 17], "mirror": true}
]
},
{
@@ -293,7 +289,7 @@
"parent": "pupil_left",
"pivot": [1.52, 13, -0.25],
"cubes": [
{"origin": [1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
{"origin": [1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
]
},
{
@@ -274,6 +274,14 @@
"parent": "lower_gear_rotation",
"pivot": [0, 9, -6]
},
{
"name": "locator_seat_1",
"parent": "lower_gear_rotation",
"pivot": [0, 10.5, -4.5],
"locators": {
"seat_1": [0, 10.5, -4.5]
}
},
{
"name": "gear4",
"parent": "lower_gear",
@@ -447,6 +447,14 @@
"cubes": [
{"origin": [0, -24.5, -8], "size": [0, 12, 7], "uv": [98, 109]}
]
},
{
"name": "locator_seat_1",
"parent": "body",
"pivot": [0, 54, -10],
"locators": {
"seat_1": [0, 54, -10]
}
}
]
}
@@ -474,6 +474,67 @@
"cubes": [
{"origin": [27, 10.5, 5], "size": [15, 19, 0], "uv": [223, 39]}
]
},
{
"name": "locator_seat_1",
"parent": "torso",
"pivot": [0, 30, -19],
"locators": {
"seat_1": [0, 30, -19]
}
},
{
"name": "locator_seat_2",
"parent": "torso",
"pivot": [13, 30, -14],
"rotation": [0, -90, 0],
"locators": {
"seat_2": [13, 30, -14]
}
},
{
"name": "locator_seat_3",
"parent": "torso",
"pivot": [-13, 30, -14],
"rotation": [0, 90, 0],
"locators": {
"seat_3": [-13, 30, -14]
}
},
{
"name": "locator_seat_4",
"parent": "torso",
"pivot": [0, 34, -3],
"locators": {
"seat_4": [0, 34, -3]
}
},
{
"name": "locator_seat_5",
"parent": "torso",
"pivot": [13, 30, 2],
"rotation": [0, -90, 0],
"locators": {
"seat_5": [13, 30, 2]
}
},
{
"name": "locator_seat_6",
"parent": "torso",
"pivot": [-13, 30, 2],
"rotation": [0, 90, 0],
"locators": {
"seat_6": [-13, 30, 2]
}
},
{
"name": "locator_seat_7",
"parent": "torso",
"pivot": [0, 33, 7],
"rotation": [0, 180, 0],
"locators": {
"seat_7": [0, 33, 7]
}
}
]
}
@@ -1137,7 +1137,6 @@
"cobblemon.container.tm_machine": "TM Machine",
"cobblemon.ui.edit.habitat": "Habitat Editor",
"cobblemon.ui.edit.habitat.mimic_id": "Mimic Block ID",
"cobblemon.ui.edit.habitat.phase_number": "Number of Phases",
"cobblemon.ui.edit.habitat.phase_order": "Phase Order: %s",
"cobblemon.ui.edit.habitat.level_range": "Level Range (Min - Max)",
"cobblemon.ui.edit.habitat.mode": "Mode: %s",
@@ -1187,7 +1186,7 @@
"cobblemon.ui.edit.habitat.validation.species": "Species must be a valid Pokemon name.",
"cobblemon.ui.edit.habitat.validation.weight": "Weight must be greater than 0.",
"cobblemon.ui.edit.habitat.validation.modifiers": "Modifiers format is invalid.",
"cobblemon.ui.edit.habitat.validation.phases_list": "Phases must use valid moon phases (0-7), e.g. 1-3 or 1, 3-5, 6.",
"cobblemon.ui.edit.habitat.validation.phases_list": "Phases must use a valid format for integer ranges, e.g. 1-3 or 1, 3-5, 6.",
"cobblemon.ui.edit.habitat.validation.min_light": "Min Light must be between 0 and 15.",
"cobblemon.ui.edit.habitat.validation.max_light": "Max Light must be between 0 and 15.",
@@ -1349,8 +1348,6 @@
"cobblemon.ui.pokedex.info.drops_range": "%1$s-%2$s×",
"cobblemon.ui.pokedex.info.drops_percentage": "%1$s%%",
"cobblemon.ui.pokedex.info.drops_empty": "No drops available.",
"cobblemon.ui.pokedex.info.evolution_tree": "Evolution Tree",
"cobblemon.ui.pokedex.info.variation": "Variation",
"cobblemon.ui.pokedex.info.form": "Form",
"cobblemon.ui.pokedex.info.form.normal": "Standard",
@@ -1462,59 +1459,6 @@
"cobblemon.ui.pokedex.unknown": "???",
"cobblemon.ui.pokedex.weight": "Weight: %1$skg",
"cobblemon.ui.pokedex.height": "Height: %1$sm",
"cobblemon.ui.pokedex.evolution.item_interact.label": "Item",
"cobblemon.ui.pokedex.evolution.item_interact.tooltip": "Needs %1$s item to evolve",
"cobblemon.ui.pokedex.evolution.trade.label": "Trade",
"cobblemon.ui.pokedex.evolution.trade.tooltip.with_species": "Evolves when traded with %1$s",
"cobblemon.ui.pokedex.evolution.trade.tooltip.with_any_species": "Evolves when traded",
"cobblemon.ui.pokedex.requirement.advancement.tooltip": "Player must have %1$s advancement",
"cobblemon.ui.pokedex.requirement.battle_critical_hits.tooltip": "Must hit %1$s critical-hits in battle",
"cobblemon.ui.pokedex.requirement.blocks_traveled.tooltip": "Must travel %1$s blocks",
"cobblemon.ui.pokedex.requirement.damage_taken.tooltip": "Must take %1$s damage in battle without fainting",
"cobblemon.ui.pokedex.requirement.defeat.tooltip": "Must defeat %1$s in battle to evolve",
"cobblemon.ui.pokedex.requirement.friendship.label": "Frien.",
"cobblemon.ui.pokedex.requirement.friendship.tooltip": "Requires at least %1$s friendship",
"cobblemon.ui.pokedex.requirement.held_item.tooltip": "Must be holding %1$s",
"cobblemon.ui.pokedex.requirement.level.label": "Lv. %1$s",
"cobblemon.ui.pokedex.requirement.level.tooltip.min": "Evolves starting at level %1$s",
"cobblemon.ui.pokedex.requirement.moon_phase.tooltip": "Must evolve in %1$s moon phase",
"cobblemon.ui.pokedex.requirement.level.tooltip.between": "Evolves between levels %1$s and %2$s",
"cobblemon.ui.pokedex.requirement.has_move.tooltip": "Must know move %1$s",
"cobblemon.ui.pokedex.requirement.has_move_type.tooltip": "Must know a move of type %1$s",
"cobblemon.ui.pokedex.requirement.has_move_type.label": "Has Move",
"cobblemon.ui.pokedex.requirement.owner_held_item.label": "Owner must be holding %1$s",
"cobblemon.ui.pokedex.requirement.recoil.tooltip": "Must suffer %1$s units of recoil in battle",
"cobblemon.ui.pokedex.requirement.stat_compare.tooltip": "Must have its %1$s higher than its %2$s",
"cobblemon.ui.pokedex.requirement.stat_equal.tooltip": "Must have its %1$s equals to its %2$s",
"cobblemon.ui.pokedex.requirement.time_range.tooltip": "Must evolve during the %1$s",
"cobblemon.ui.pokedex.requirement.use_move.tooltip": "Must use move %1$s in battle",
"cobblemon.ui.pokedex.requirement.weather.tooltip.raining": "Must be in rain to evolve",
"cobblemon.ui.pokedex.requirement.weather.tooltip.thundering": "Must be in a thunderstorm to evolve",
"cobblemon.ui.moon_phase.full_moon": "Full Moon",
"cobblemon.ui.moon_phase.waning_gibbous": "Waning Gibbous",
"cobblemon.ui.moon_phase.third_quarter": "Third Quarter",
"cobblemon.ui.moon_phase.waning_crescent": "Waning Crescent",
"cobblemon.ui.moon_phase.new_moon": "New Moon",
"cobblemon.ui.moon_phase.waxing_crescent": "Waxing Crescent",
"cobblemon.ui.moon_phase.first_quarter": "First Quarter",
"cobblemon.ui.moon_phase.waxing_gibbous": "Waxing Gibbous",
"cobblemon.ui.time_range.any": "Any",
"cobblemon.ui.time_range.day": "Day",
"cobblemon.ui.time_range.night": "Night",
"cobblemon.ui.time_range.noon": "Noon",
"cobblemon.ui.time_range.midnight": "Midnight",
"cobblemon.ui.time_range.dawn": "Dawn",
"cobblemon.ui.time_range.dusk": "Dusk",
"cobblemon.ui.time_range.twilight": "Twilight",
"cobblemon.ui.time_range.morning": "Morning",
"cobblemon.ui.time_range.afternoon": "Afternoon",
"cobblemon.ui.time_range.predawn": "Predawn",
"cobblemon.ui.time_range.evening": "Evening",
"cobblemon.pokedex.variation.cream": "Cream",
"cobblemon.pokedex.variation.decoration": "Decoration",
"cobblemon.pokedex.variation.flower": "Flower",
@@ -9351,11 +9351,11 @@
"cobblemon.habitat.natural_lightning_rod.name": "Pararrayos natural",
"cobblemon.habitat.quartz_spikes.name": "Picos de Cuarzo",
"cobblemon.subtitle.tm.use": "Máquina Técnica usada",
"cobblemon.subtitle.block.tm_machine.craft": "Máquina MT imprime MT",
"cobblemon.subtitle.block.tm_machine.craft": "Máquina MT termina de imprimir la MT",
"cobblemon.subtitle.block.tm_machine.off": "Máquina MT desactivada",
"cobblemon.subtitle.block.tm_machine.on": "Máquina MT activada",
"cobblemon.subtitle.block.tm_machine.open": "La tapa de la Máquina MT se abre",
"cobblemon.subtitle.block.tm_machine.close": "Ma tapa de la Máquina MT se cierra",
"cobblemon.subtitle.block.tm_machine.close": "La tapa de la Máquina MT se cierra",
"cobblemon.subtitle.block.tm_machine.place_disc": "MT en blanco insertada en la Máquina MT",
"cobblemon.ui.exp.number": "+%1$s §oEXP",
"cobblemon.config.ui.award_experience_to_fainted_pokemon": "Da Exp. a Pokémon derrotados",
@@ -9511,5 +9511,9 @@
"advancements.cobblemon.cook_poke_snack": "Un aroma tentador",
"advancements.cobblemon.cook_poke_snack.description": "Hornea un Poké Señuelo, un delicioso pastel que atrae a ciertos Pokémon según las bayas que uses",
"advancements.cobblemon.register_all_tms": "Discografía completa",
"advancements.cobblemon.plant_tumblestone.description": "Coloca un guijarro cerca de lava o de magma para que crezca a lo largo del tiempo"
"advancements.cobblemon.plant_tumblestone.description": "Coloca un guijarro cerca de lava o de magma para que crezca a lo largo del tiempo",
"cobblemon.subtitle.block.tm_machine.burn_loop": "Máquina MT imprime MT",
"cobblemon.subtitle.block.tm_machine.start": "Maquina MT empieza a imprimir MT",
"cobblemon.subtitle.block.tm_machine.tm_insert": "MT en blanco colocada en la Máquina MT",
"cobblemon.subtitle.block.tm_machine.tm_retrieve": "MT retirada de la Máquina MT"
}
@@ -819,7 +819,7 @@
"advancements.cobblemon.first_catch.description": "モンスターボールを投げて、ポケモンを捕まえる",
"advancements.cobblemon.full_party": "フルハウス",
"advancements.cobblemon.full_party.description": "ポケモンをもっとゲットし、手持ちを6匹にする",
"advancements.cobblemon.first_evolution": "てれ てれん",
"advancements.cobblemon.first_evolution": "新たなる姿",
"advancements.cobblemon.first_evolution.description": "進化条件を満たし、ポケモンを進化させる",
"advancements.cobblemon.first_battle_victory": "勝利は目の前?",
"advancements.cobblemon.first_battle_victory.description": "他のトレーナーに勝利する",
@@ -831,7 +831,7 @@
"advancements.cobblemon.obtain_leek.description": "淡水で育つ野草、クスリソウを手に入れる",
"advancements.cobblemon.medicinal_brew": "町のジョーイさん",
"advancements.cobblemon.medicinal_brew.description": "クスリソウを醸造して溶媒のクスリチャを作る",
"advancements.cobblemon.brew_potion": "そんな装備で大丈夫か?",
"advancements.cobblemon.brew_potion": "お砂糖ひとさじ",
"advancements.cobblemon.brew_potion.description": "クスリチャを溶媒にオレンのみを醸造してキズぐすりを作る",
"advancements.cobblemon.brew_full_restore": "チャンピオン御用達",
"advancements.cobblemon.brew_full_restore.description": "まんたんのくすりを溶媒にラムのみを醸造してかいふくのくすりを作る",
@@ -1235,10 +1235,10 @@
"cobblemon.battle.fail.healblock": "%1$sは かいふくふうじで 回復できない!",
"cobblemon.battle.fail.darkvoid": "しかし %1$sは 使うことが できなかった!",
"cobblemon.battle.fail.teatime": "しかし 何も 起こらなかった!",
"cobblemon.battle.fail.slp": "%1$sは すでに 眠っている",
"cobblemon.battle.fail.par": "%1$sは すでに まひしている",
"cobblemon.battle.fail.slp": "しかし %1$sは 眠らない!",
"cobblemon.battle.fail.par": "しかし %1$sは まひにならない!",
"cobblemon.battle.fail.tox": "%1$sは すでに 毒を あびている",
"cobblemon.battle.fail.psn": "%1$sは すでに 毒を あびている",
"cobblemon.battle.fail.psn": "しかし %1$sは 毒にならない!",
"cobblemon.battle.fail.brn": "%1$sは すでに やけどを 負っている",
"cobblemon.battle.fail.frz": "%1$sは すでに 凍っている",
"cobblemon.battle.fail.uproar": "%1$sは 騒いでいて 眠れない!",
@@ -9237,7 +9237,7 @@
"cobblemon.ui.edit.habitat.validation.species": "種族名は有効なポケモン名でなければなりません。",
"cobblemon.ui.edit.habitat.validation.weight": "重量は0より大きくなければなりません。",
"cobblemon.ui.edit.habitat.validation.modifiers": "修飾子の形式が無効です。",
"cobblemon.ui.edit.habitat.validation.phases_list": "フェーズには有効な月の満ち欠け(0-7)を指定する必要があります。例:1-3、または1、3-5、6。",
"cobblemon.ui.edit.habitat.validation.phases_list": "フェーズでは、整数の範囲を表す際に有効な形式を使用する必要があります。例:1-3、または1、3-5、6。",
"cobblemon.ui.edit.habitat.validation.min_light": "最小明るさ度の値は0から15の間でなければなりません。",
"cobblemon.ui.edit.habitat.validation.max_light": "最大明るさ度の値は0から15の間でなければなりません。",
"cobblemon.ui.moves.learnset.tm.discovered": "発見済み",
@@ -9302,5 +9302,81 @@
"cobblemon.habitat.pinkflowerbed_clearing.name": "ピンクフラワーベッドの開拓地",
"cobblemon.habitat.sandpit_clearing.name": "砂場の開拓地",
"cobblemon.habitat.sunflowerbed_clearing.name": "ヒマワリベッドの開拓地",
"cobblemon.habitat.sunscorched_clearing.name": "日差しに焼かれた開拓地"
"cobblemon.habitat.sunscorched_clearing.name": "日差しに焼かれた開拓地",
"cobblemon.habitat.quartz_spikes.name": "クォーツスパイク",
"cobblemon.habitat.reclaimed_desert_monument.name": "再生された砂漠の記念碑",
"cobblemon.habitat.reclaimed_lush_monument.name": "再生された繁茂した記念碑",
"cobblemon.habitat.rocky_outcrop.name": "岩の露頭",
"cobblemon.habitat.rocky_tide_pool.name": "岩場の潮だまり",
"cobblemon.habitat.root_nursery.name": "根苗圃",
"cobblemon.habitat.sandy_tide_pool.name": "砂地の潮だまり",
"cobblemon.habitat.skeletal_fall.name": "骸骨の墓場",
"cobblemon.habitat.snowy_burrow.name": "雪に覆われた巣穴",
"cobblemon.habitat.snowy_grotto.name": "雪に覆われた洞窟",
"cobblemon.habitat.snowy_thermal_vents.name": "雪に覆われた熱水噴出孔",
"cobblemon.habitat.thermal_crevices.name": "熱の裂け目",
"cobblemon.habitat.treasure_hoard.name": "秘宝の宝庫",
"cobblemon.habitat.volcanic_plume.name": "火山噴出柱",
"cobblemon.habitat.zen_garden.name": "思念の庭園",
"cobblemon.subtitle.tm.use": "わざマシン使用済み",
"cobblemon.subtitle.block.tm_machine.burn_loop": "わざマシンマシンでわざマシンをプリントする",
"cobblemon.subtitle.block.tm_machine.start": "わざマシンマシンがわざマシンのプリントを開始しました",
"cobblemon.subtitle.block.tm_machine.craft": "わざマシンマシンがわざマシンのプリントを完了しました",
"cobblemon.subtitle.block.tm_machine.open": "わざマシンマシンの蓋が開きます",
"cobblemon.subtitle.block.tm_machine.close": "わざマシンマシンの蓋が閉じます",
"cobblemon.subtitle.block.tm_machine.tm_insert": "わざマシンマシンに空のわざマシンをセットする",
"cobblemon.subtitle.block.tm_machine.tm_retrieve": "わざマシンをわざマシンマシンから入手",
"cobblemon.subtitle.block.tm_machine.item_insert": "アイテムをわざマシンマシンに配置しました",
"cobblemon.subtitle.block.tm_machine.item_retrieve": "わざマシンマシンからアイテムを取り出した",
"cobblemon.ui.exp.number": "+%1$s §o経験値",
"cobblemon.config.ui.award_experience_to_fainted_pokemon": "倒れたポケモンにも経験値を与える",
"cobblemon.config.ui.award_experience_to_fainted_pokemon.tooltip": "バトル中ひんしになったポケモンは、ひんしになる前に倒すのに貢献した相手から経験値を獲得できるか。",
"cobblemon.config.ui.award_experience_on_battle_loss": "戦闘敗北時の経験値",
"cobblemon.config.ui.award_experience_on_battle_loss.tooltip": "バトルに負けた場合でも、倒した相手からポケモンは経験値を獲得できるか。ひんしになったポケモンが経験値を獲得するには、「倒れたポケモンにも経験値を与える」が有効になっている必要がある。",
"cobblemon.config.ui.fossil_machine_alpha_chance": "化石マシンのオヤブン出現確率",
"cobblemon.config.ui.fossil_machine_alpha_chance.tooltip": "化石マシンから入手できるポケモンがオヤブンになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.fossil_machine_shiny_chance.tooltip": "ふくげんマシンから入手できるポケモンが色違いになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.honey_slather_alpha_chance.tooltip": "ミツ塗りの木から入手できるポケモンがオヤブンになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.honey_slather_shiny_chance.tooltip": "ミツ塗りの木から入手できるポケモンが色違いになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.fossil_machine_shiny_chance": "化石マシンの色違い出現確率",
"cobblemon.config.ui.honey_slather_alpha_chance": "ミツ塗りの木のオヤブン出現確率",
"cobblemon.config.ui.honey_slather_shiny_chance": "ミツ塗りの木の色違い出現確率",
"cobblemon.config.ui.data_monitor_alpha_rate": "データモニターのオヤブン出現確率",
"cobblemon.config.ui.data_monitor_alpha_rate.tooltip": "データモニターから入手できるポケモンがオヤブンになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.data_monitor_shiny_rate": "データモニターの色違い出現確率",
"cobblemon.config.ui.data_monitor_shiny_rate.tooltip": "データモニターから入手できるポケモンが色違いになる確率。\"[入力した数値]分の1\"として計算される。",
"cobblemon.config.ui.pokemon_intrinsic_size_min.tooltip": "出現するポケモンの最小固有サイズ倍率。",
"cobblemon.config.ui.pokemon_intrinsic_size_min": "ポケモンの最小固有サイズ",
"cobblemon.config.ui.pokemon_intrinsic_size_max": "ポケモンの最大固有サイズ",
"cobblemon.config.ui.pokemon_intrinsic_size_max.tooltip": "出現するポケモンの最大固有サイズ倍率。",
"cobblemon.config.ui.alpha_pokemon_size_small_multiplier.tooltip": "当たり判定が0.5ブロック未満のポケモンに対するオヤブンサイズ倍率。",
"cobblemon.config.ui.alpha_pokemon_size_small_multiplier": "小さいオヤブンサイズ倍率",
"cobblemon.config.ui.alpha_pokemon_size_medium_multiplier": "中くらいのオヤブンサイズ倍率",
"cobblemon.config.ui.alpha_pokemon_size_medium_multiplier.tooltip": "当たり判定が0.5ブロックから1.5ブロックの間のポケモンに対するオヤブンサイズ倍率。",
"cobblemon.config.ui.alpha_pokemon_size_large_multiplier": "大きいオヤブンサイズ倍率",
"cobblemon.config.ui.alpha_pokemon_size_large_multiplier.tooltip": "当たり判定が1.5ブロックから10ブロックの間のポケモンに対するオヤブンサイズ倍率。",
"cobblemon.config.ui.alpha_pokemon_size_extra_large_multiplier.tooltip": "当たり判定が10ブロック以上のポケモンに対するオヤブンサイズ倍率。",
"cobblemon.config.ui.alpha_pokemon_size_extra_large_multiplier": "とても大きいオヤブンサイズ倍率",
"cobblemon.config.ui.baby_pokemon_level_duration": "ベイビィポケモン期間レベル",
"cobblemon.config.ui.baby_pokemon_level_duration.tooltip": "ポケモンが通常よりも小さく見える「ベイビィポケモン」とみなされるレベル数。",
"cobblemon.config.ui.baby_pokemon_size_multiplier": "ベイビィポケモンの最小サイズ",
"cobblemon.config.ui.baby_pokemon_size_multiplier.tooltip": "レベル1のポケモンに適用されるサイズ倍率。",
"cobblemon.config.ui.minimum_riding_scale": "ライドするための最低限のポケモンスケール値",
"cobblemon.config.ui.minimum_riding_scale.tooltip": "ポケモンに乗れなくなる限界のスケール。",
"cobblemon.config.ui.unlock_all_move_dex_moves_by_default.tooltip": "この機能を有効にすると、わざマシンやレベルアップで覚える技が解放され、わざマシンマシンやポケモン図鑑の技一覧で確認できるようになります。",
"cobblemon.config.ui.unlock_all_move_dex_moves_by_default": "全ての技をアンロック",
"cobblemon.config.ui.infinite_tm_uses": "わざマシン無限化",
"cobblemon.config.ui.infinite_tm_uses.tooltip": "わざマシンで技を教える際、わざマシンが消費されなくなります。",
"advancements.cobblemon.use_healing_machine.description": "かいふく装置のチャージを待ち、使用して手持ちのポケモンを回復させる",
"advancements.cobblemon.use_healing_machine": "てん てん てれれん",
"advancements.cobblemon.plant_all_apricorn_sprouts.description": "あらゆる色のぼんぐりの新芽を植える",
"advancements.cobblemon.plant_all_apricorn_sprouts": "ぼんぐりころころぼんぐりこ",
"advancements.cobblemon.use_mint.description": "ミントを使ってポケモンのステータスの得意不得意を変える",
"advancements.cobblemon.use_mint": "結果にコミント!",
"advancements.cobblemon.brew_medicinal_brew.description": "クスリソウを煎じて、薬の基礎となるものを作る",
"advancements.cobblemon.brew_medicinal_brew": "ネギらうおくすり",
"advancements.cobblemon.brew_all_potions.description": "クスリソウを使って、ありとあらゆるアイテムを作成する",
"advancements.cobblemon.brew_all_potions": "一番良いのを頼む",
"advancements.cobblemon.use_exp_candy.description": "ポケモンにけいけんアメを使う",
"advancements.cobblemon.use_exp_candy": "甘美な経験"
}
@@ -5936,14 +5936,14 @@
"block.cobblemon.red_apricorn": "红球果",
"block.cobblemon.yellow_apricorn": "黄球果",
"block.cobblemon.lectern": "讲台",
"cobblemon.fishing_bait_effects.nature.tooltip": "%1$s%%-%2$s↑性格出现率",
"cobblemon.fishing_bait_effects.iv.tooltip": "%1$s%%-%2$s个体值+%3$s",
"cobblemon.fishing_bait_effects.ev.tooltip": "%1$s%%-%2$s基础点数出现率",
"cobblemon.fishing_bait_effects.bite_time.tooltip": "%1$s%% - 上钩时间缩短 %3$s%%",
"cobblemon.fishing_bait_effects.gender_chance.tooltip": "%1$s%%-%2$s性别出现率",
"cobblemon.fishing_bait_effects.level_raise.tooltip": "%1$s%% - 等级 +%3$s",
"cobblemon.fishing_bait_effects.nature.tooltip": "%1$s%% - %2$s↑性格出现率",
"cobblemon.fishing_bait_effects.iv.tooltip": "%1$s%% - %2$s个体值+%3$s",
"cobblemon.fishing_bait_effects.ev.tooltip": "%1$s%% - %2$s基础点数出现率",
"cobblemon.fishing_bait_effects.bite_time.tooltip": "%1$s%% - 上钩时间缩短%3$s%%",
"cobblemon.fishing_bait_effects.gender_chance.tooltip": "%1$s%% - %2$s性别出现率",
"cobblemon.fishing_bait_effects.level_raise.tooltip": "%1$s%% - 等级+%3$s",
"cobblemon.fishing_bait_effects.tera.tooltip": "%1$s%% - 吸引 %2$s 太晶属性",
"cobblemon.fishing_bait_effects.shiny_reroll.tooltip": "%1$s%% - 异色概率 ×%3$s",
"cobblemon.fishing_bait_effects.shiny_reroll.tooltip": "%1$s%% - 发光概率×%3$s",
"cobblemon.fishing_bait_effects.ha_chance.tooltip": "%1$s%% - 隐藏特性出现率",
"cobblemon.fishing_bait_effects.pokemon_chance.tooltip": "%1$s%% - 上钩一只宝可梦",
"cobblemon.fishing_bait_effects.friendship.tooltip": "%1$s%% - 亲密度 +%3$s",
@@ -6179,7 +6179,7 @@
"cobblemon.species.ironjugulis.desc": "它与超自然杂志曾报道过的宝可梦很相似。报道中的宝可梦是爱上机器人的三首恶龙所生的孩子。",
"cobblemon.species.pecharunt.desc": "会让对手吃下能提升欲望和能力的毒粘糕,然后通过锁链控制对手。",
"cobblemon.ability.teraformzero.desc": "太乐巴戈斯变为星晶形态时,蕴藏在它身上的力量会将天气和场地的影响全部归零。",
"cobblemon.subtitle.pokemon.shiny_shine": "被捕获的异色宝可梦闪闪发光",
"cobblemon.subtitle.pokemon.shiny_shine": "被捕获的发光宝可梦闪闪发光",
"cobblemon.battle.heal.bagitemrevive": "%1$s 恢复了活力!",
"cobblemon.battle.detailschange.noice": "%1$s的样子发生了变化!",
"cobblemon.battle.detailschange.eiscue": "%1$s的样子发生了变化!",
@@ -6206,9 +6206,9 @@
"cobblemon.ability.hospitality": "款待",
"cobblemon.ability.poisonpuppeteer": "毒傀儡",
"cobblemon.ability.supersweetsyrup": "甘露之蜜",
"cobblemon.subtitle.pokemon.wild_shiny_shine": "野生的异色宝可梦!",
"cobblemon.subtitle.pokemon.owned_shiny_ambient": "周围的异色宝可梦闪闪发光",
"cobblemon.subtitle.pokemon.shiny_ambient": "野生的异色宝可梦闪闪发光!",
"cobblemon.subtitle.pokemon.wild_shiny_shine": "野生的发光宝可梦!",
"cobblemon.subtitle.pokemon.owned_shiny_ambient": "周围的发光宝可梦闪闪发光",
"cobblemon.subtitle.pokemon.shiny_ambient": "野生的发光宝可梦闪闪发光!",
"cobblemon.battle.withdraw.self": "%1$s ,回来!",
"cobblemon.battle.withdraw.other": "%1$s换下了%2$s!",
"cobblemon.type.suffix": "%1$s 属性",
@@ -6399,34 +6399,34 @@
"cobblemon.pokerod.remove": "右键移除饵料",
"item.cobblemon.galarica_nuts": "伽勒豆蔻枝",
"item.cobblemon.npc_editor": "NPC的训练家证",
"item.cobblemon.dragon_scale.tooltip": "在连接交换时携带,可使海刺龙进化为刺龙王",
"item.cobblemon.link_cable.tooltip": "使需要通过交换进化的宝可梦进化",
"item.cobblemon.dragon_scale.tooltip": "当海刺龙携带进行连接交换时,可使其进化为刺龙王",
"item.cobblemon.link_cable.tooltip": "可使需要连接交换的宝可梦进化",
"item.cobblemon.kings_rock.tooltip_2": "在交换时携带,可使蚊香君进化为蚊香蛙皇,呆呆兽进化为呆呆王",
"item.cobblemon.metal_coat.tooltip_1": "携带后,钢属性的招式威力就会增强",
"item.cobblemon.kings_rock.tooltip_1": "携带该道具的宝可梦造成伤害时,有概率使目标陷入畏缩状态",
"item.cobblemon.metal_coat.tooltip_2": "在连接交换时携带,可使大岩蛇进化为大钢蛇,使飞天螳螂进化为巨钳螳螂",
"item.cobblemon.upgrade.tooltip": "在连接交换时携带,可使多边兽进化为多边兽2型",
"item.cobblemon.dubious_disc.tooltip": "在连接交换时携带,可使多边兽2型进化为多边兽乙型",
"item.cobblemon.metal_coat.tooltip_2": "在连接交换时携带,可使大岩蛇进化为大钢蛇,飞天螳螂进化为巨钳螳螂",
"item.cobblemon.upgrade.tooltip": "当多边兽携带进行连接交换时,可使其进化为多边兽2型",
"item.cobblemon.dubious_disc.tooltip": "当多边兽2型携带进行连接交换时,可使其进化为多边兽乙型",
"item.cobblemon.deep_sea_scale.tooltip_1": "大幅提升珍珠贝的特防",
"item.cobblemon.deep_sea_scale.tooltip_2": "在连接交换时携带,可使珍珠贝进化为樱花鱼",
"item.cobblemon.deep_sea_tooth.tooltip_2": "在连接交换时携带,可使珍珠贝进化为猎斑鱼",
"item.cobblemon.electirizer.tooltip": "在连接交换时携带,可使电击兽进化为电击魔兽",
"item.cobblemon.magmarizer.tooltip": "当鸭嘴火兽携带进行连接进化时,会使其进化为鸭嘴炎兽",
"item.cobblemon.oval_stone.tooltip": "当小福蛋携带进行连接交换时,会使其进化为吉利蛋",
"item.cobblemon.protector.tooltip": "当钻角犀兽携带进行连接交换时,会使其进化为超甲狂犀",
"item.cobblemon.prism_scale.tooltip": "当丑丑鱼携带进行连接交换时,会使其进化为美纳斯",
"item.cobblemon.sachet.tooltip": "当粉香香携带进行连接交换时,会使其进化为芳香精",
"item.cobblemon.whipped_dream.tooltip": "当绵绵泡芙携带进行连接交换时,会使其进化为胖甜妮",
"item.cobblemon.love_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的爱心形态",
"item.cobblemon.berry_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的野莓形态",
"item.cobblemon.flower_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的花朵形态",
"item.cobblemon.ribbon_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的蝴蝶结形态",
"item.cobblemon.cracked_pot.tooltip": "当对赝品来悲茶使用时,会使其进化为怖思壶",
"item.cobblemon.unremarkable_teacup.tooltip": "当对斯魔茶(冒牌货的样子)使用时,会使其进化为来悲粗茶(凡作的样子)",
"item.cobblemon.sweet_apple.tooltip": "当对啃果虫使用时,会使其进化为丰蜜龙",
"item.cobblemon.tart_apple.tooltip": "当对啃果虫使用时,会使其进化为苹裹龙",
"item.cobblemon.galarica_wreath.tooltip": "当对呆呆兽(伽勒尔的样子)使用时,会使其进化为呆呆王(伽勒尔的样子)",
"item.cobblemon.black_augurite.tooltip": "当对飞天螳螂使用,会使其进化为劈斧螳螂",
"item.cobblemon.deep_sea_scale.tooltip_2": "当珍珠贝携带进行连接交换时,可使其进化为樱花鱼",
"item.cobblemon.deep_sea_tooth.tooltip_2": "当珍珠贝携带进行连接交换时,可使其进化为猎斑鱼",
"item.cobblemon.electirizer.tooltip": "当电击兽携带进行连接交换时,可使其进化为电击魔兽",
"item.cobblemon.magmarizer.tooltip": "当鸭嘴火兽携带进行连接交换时,可使其进化为鸭嘴炎兽",
"item.cobblemon.oval_stone.tooltip": "当小福蛋携带并处于白天时,可使其进化为吉利蛋",
"item.cobblemon.protector.tooltip": "当钻角犀兽携带进行连接交换时,可使其进化为超甲狂犀",
"item.cobblemon.prism_scale.tooltip": "当丑丑鱼携带进行连接交换时,可使其进化为美纳斯",
"item.cobblemon.sachet.tooltip": "当粉香香携带进行连接交换时,可使其进化为芳香精",
"item.cobblemon.whipped_dream.tooltip": "当绵绵泡芙携带进行连接交换时,可使其进化为胖甜妮",
"item.cobblemon.love_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的爱心形态",
"item.cobblemon.berry_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的野莓形态",
"item.cobblemon.flower_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的花朵形态",
"item.cobblemon.ribbon_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的蝴蝶结形态",
"item.cobblemon.cracked_pot.tooltip": "当对赝品来悲茶使用时,可使其进化为怖思壶",
"item.cobblemon.unremarkable_teacup.tooltip": "当对斯魔茶(冒牌货的样子)使用时,可使其进化为来悲粗茶(凡作的样子)",
"item.cobblemon.sweet_apple.tooltip": "当对啃果虫使用时,可使其进化为丰蜜龙",
"item.cobblemon.tart_apple.tooltip": "当对啃果虫使用时,可使其进化为苹裹龙",
"item.cobblemon.galarica_wreath.tooltip": "当对呆呆兽(伽勒尔的样子)使用时,可使其进化为呆呆王(伽勒尔的样子)",
"item.cobblemon.black_augurite.tooltip": "当对飞天螳螂使用,可使其进化为劈斧螳螂",
"item.cobblemon.moon_stone.tooltip": "进化特定宝可梦",
"item.cobblemon.dawn_stone.tooltip": "进化特定宝可梦",
"item.cobblemon.fire_stone.tooltip": "进化特定宝可梦",
@@ -6480,8 +6480,8 @@
"item.cobblemon.absorb_bulb.tooltip_2": "使用后消耗",
"item.cobblemon.air_balloon.tooltip_1": "携带后,会浮在空中",
"item.cobblemon.assault_vest.tooltip": "虽然携带后特防会提高,但会无法使出变化招式",
"item.cobblemon.auspicious_armor.tooltip": "当对炭小侍使用时,会使其进化为红莲铠骑",
"item.cobblemon.malicious_armor.tooltip": "当对炭小侍使用时,会使其进化为苍炎刃鬼",
"item.cobblemon.auspicious_armor.tooltip": "当对炭小侍使用时,可使其进化为红莲铠骑",
"item.cobblemon.malicious_armor.tooltip": "当对炭小侍使用时,可使其进化为苍炎刃鬼",
"item.cobblemon.binding_band.tooltip": "携带后,绑紧招式的威力会变强",
"item.cobblemon.black_belt.tooltip": "携带后,格斗属性的招式威力就会提高",
"item.cobblemon.black_sludge.tooltip": "携带后,毒属性的宝可梦会缓缓回复HP。其他属性的话,HP则会减少",
@@ -6532,7 +6532,7 @@
"item.cobblemon.shed_shell.tooltip": "携带后,必定可以和后备的宝可梦进行替换",
"item.cobblemon.shell_bell.tooltip": "携带后,攻击对手并造成伤害时,能回复少量HP",
"item.cobblemon.shell_helmet": "硬壳头盔",
"item.cobblemon.shell_helmet.tooltip": "当对盖盖虫使用时,会使其进化为骑士蜗牛",
"item.cobblemon.shell_helmet.tooltip": "当对盖盖虫使用时,可使其进化为骑士蜗牛",
"item.cobblemon.silver_powder.tooltip": "携带后,虫属性的招式威力就会提高",
"item.cobblemon.soft_sand.tooltip": "携带后,地面属性的招式威力就会提高",
"item.cobblemon.soothe_bell.tooltip": "携带后,会变得容易和训练家亲密",
@@ -6604,13 +6604,13 @@
"item.cobblemon.flying_gem.tooltip_1": "携带后,飞行属性的招式威力会增强一次",
"item.cobblemon.flying_gem.tooltip_2": "使用后消耗",
"block.cobblemon.big_root.tooltip": "携带后,吸取HP的招式可以比平时更多地回复自己的HP",
"item.cobblemon.clover_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的幸运草形态",
"item.cobblemon.clover_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的幸运草形态",
"item.cobblemon.water_stone.tooltip": "进化特定宝可梦",
"item.cobblemon.jolly_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为爽朗性格",
"item.cobblemon.cell_battery.tooltip_1": "携带它的宝可梦如果受到电属性招式的伤害,攻击就会提高",
"item.cobblemon.dragon_fang.tooltip": "携带后,龙属性的招式威力就会提高",
"item.cobblemon.eject_button.tooltip_1": "携带它的宝可梦如果受到招式的伤害,就能逃脱战斗",
"item.cobblemon.razor_fang.tooltip_2": "当天蝎携带在夜晚进行等级升级时,会使其进化为天蝎王",
"item.cobblemon.razor_fang.tooltip_2": "当天蝎携带在夜晚进行等级升级时,可使其进化为天蝎王",
"item.cobblemon.ring_target.tooltip": "携带后,原本因属性相克关系而无效的招式现在会变得能够击中自己",
"item.cobblemon.wise_glasses.tooltip": "携带后,特殊招式的威力就会少量提高",
"item.cobblemon.power_bracer.tooltip": "携带后,在战斗中获得经验值时,会获得8点攻击基础点数",
@@ -6618,9 +6618,9 @@
"item.cobblemon.x_special_defence.tooltip": "在战斗中使用时,会使目标的特防提升一级",
"item.cobblemon.full_heal.tooltip": "治愈一只宝可梦的所有异常状态",
"item.cobblemon.paralyze_heal.tooltip": "治愈一只宝可梦的麻痹状态",
"item.cobblemon.reaper_cloth.tooltip": "当彷徨夜灵携带进行连接交换时,会使其进化为黑夜魔灵",
"item.cobblemon.masterpiece_teacup.tooltip": "当对斯魔茶(高档货的样子)使用时,会使其进化为来悲粗茶(杰作的样子)",
"item.cobblemon.galarica_cuff.tooltip": "当对呆呆兽(伽勒尔的样子)使用时,会使其进化为呆壳兽(伽勒尔的样子)",
"item.cobblemon.reaper_cloth.tooltip": "当彷徨夜灵携带进行连接交换时,可使其进化为黑夜魔灵",
"item.cobblemon.masterpiece_teacup.tooltip": "当对斯魔茶(高档货的样子)使用时,可使其进化为来悲粗茶(杰作的样子)",
"item.cobblemon.galarica_cuff.tooltip": "当对呆呆兽(伽勒尔的样子)使用时,可使其进化为呆壳兽(伽勒尔的样子)",
"item.cobblemon.ability_capsule.tooltip": "当对宝可梦使用后,会使其特性改变为另一种常见特性",
"item.cobblemon.lonely_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为怕寂寞性格",
"item.cobblemon.brave_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为勇敢性格",
@@ -6636,13 +6636,13 @@
"item.cobblemon.burn_heal.tooltip": "治愈一只宝可梦的灼伤状态",
"item.cobblemon.dragon_gem.tooltip_2": "使用后消耗",
"item.cobblemon.ground_gem.tooltip_1": "携带后,地面属性的招式威力会增强一次",
"item.cobblemon.peat_block.tooltip": "当在满月对圈圈熊使用时,会使其进化为月月熊",
"item.cobblemon.strawberry_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的草莓形态",
"item.cobblemon.chipped_pot.tooltip": "当对真品来悲茶使用时,会使其进化为怖思壶",
"item.cobblemon.peat_block.tooltip": "当在满月对圈圈熊使用时,可使其进化为月月熊",
"item.cobblemon.strawberry_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的草莓形态",
"item.cobblemon.chipped_pot.tooltip": "当对真品来悲茶使用时,可使其进化为怖思壶",
"item.cobblemon.focus_band.tooltip": "携带后,即便受到可能会导致昏厥的招式,有时也能仅以1HP撑过去",
"item.cobblemon.light_clay.tooltip": "携带后,使出像光墙和反射壁一样的保护招式时,效果会比平时持续得更长",
"item.cobblemon.red_card.tooltip_1": "携带后,能让对自己造成伤害的对手退场",
"item.cobblemon.medicinal_leek.tooltip_1": "能用来调制成药品",
"item.cobblemon.medicinal_leek.tooltip_1": "可调制成药品",
"item.cobblemon.remedy.tooltip": "使一只宝可梦回复20HP,同时小幅降低它的亲密度",
"item.cobblemon.fine_remedy.tooltip": "使一只宝可梦回复60HP,同时小幅降低它的亲密度",
"item.cobblemon.superb_remedy.tooltip": "使一只宝可梦回复120HP,同时小幅降低它的亲密度",
@@ -6653,7 +6653,7 @@
"item.cobblemon.ghost_gem.tooltip_1": "携带后,幽灵属性的招式威力会增强一次",
"item.cobblemon.rock_gem.tooltip_1": "携带后,岩石属性的招式威力会增强一次",
"item.cobblemon.psychic_gem.tooltip_2": "使用后消耗",
"item.cobblemon.star_sweet.tooltip": "当小仙奶携带时,会使其进化为霜奶仙的星星形态",
"item.cobblemon.star_sweet.tooltip": "当小仙奶携带时,可使其进化为霜奶仙的星星形态",
"item.cobblemon.relaxed_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为悠闲性格",
"item.cobblemon.quiet_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为冷静性格",
"item.cobblemon.careful_mint.tooltip": "当对宝可梦使用后,会使其性格影响改变为慎重性格",
@@ -6678,8 +6678,8 @@
"item.cobblemon.bug_gem.tooltip_1": "携带后,虫属性的招式威力会增强一次",
"item.cobblemon.deep_sea_tooth.tooltip_1": "大幅提升珍珠贝的特攻",
"cobblemon.fishing.no_bite": "甚至连一口都没有。",
"cobblemon.fishing_bait_effects.typing.tooltip": "%1$s%%-%2$s属性出现率×%3$s",
"cobblemon.fishing_bait_effects.egg_group.tooltip": "%1$s%%-%2$s蛋群出现率×%3$s",
"cobblemon.fishing_bait_effects.typing.tooltip": "%1$s%% - %2$s属性出现率×%3$s",
"cobblemon.fishing_bait_effects.egg_group.tooltip": "%1$s%% - %2$s蛋群出现率×%3$s",
"cobblemon.egg_group.monster": "怪兽",
"cobblemon.egg_group.water_1": "水中1",
"cobblemon.egg_group.bug": "虫",
@@ -6712,7 +6712,7 @@
"cobblemon.ui.interact.ride": "骑乘",
"cobblemon.ui.interact.request_already_expired": "该请求已过期!",
"cobblemon.ui.pokedex.search.search_by": "搜索 %1$s 中",
"cobblemon.ui.pokedex.search.type.species": "物种名称",
"cobblemon.ui.pokedex.search.type.species": "宝可梦名称",
"cobblemon.ui.pokedex.search.type.abilities": "特性",
"cobblemon.ui.pokedex.search.type.drops": "掉落物",
"cobblemon.cosmetic.held_logs.crimson": "绯红菌柄",
@@ -6911,10 +6911,10 @@
"cobblemon.config.ui.display_entity_name_label": "显示宝可梦的名字",
"cobblemon.config.ui.display_entity_level_label": "显示宝可梦的等级",
"cobblemon.config.ui.display_entity_labels_when_crouching_only.tooltip": "控制是否只在蹲下时显示宝可梦的标签。",
"cobblemon.config.ui.shiny_rate": "异色概率",
"cobblemon.config.ui.shiny_rate.tooltip": "生成的宝可梦为异色的概率。若设为0,则生成的宝可梦不会出现异色。该概率以1/x的形式计算。",
"cobblemon.config.ui.shiny_notice_particles_distance": "异色粒子的显示距离",
"cobblemon.config.ui.shiny_notice_particles_distance.tooltip": "宝可梦异色粒子效果开始显示的距离。",
"cobblemon.config.ui.shiny_rate": "发光概率",
"cobblemon.config.ui.shiny_rate.tooltip": "生成发光宝可梦的概率。若设为0,则发光宝可梦不会生成。该概率以1/x的形式计算。",
"cobblemon.config.ui.shiny_notice_particles_distance": "发光粒子的显示距离",
"cobblemon.config.ui.shiny_notice_particles_distance.tooltip": "宝可梦发光粒子效果开始显示的距离。",
"cobblemon.config.ui.capture_calculator": "捕获计算器",
"cobblemon.config.ui.player_damage_pokemon": "玩家攻击宝可梦",
"cobblemon.config.ui.player_damage_pokemon.tooltip": "控制玩家是否可以攻击一般实体一样攻击宝可梦。",
@@ -7073,7 +7073,7 @@
"cobblemon.battle.block.aromaveil": "%1$s 正受到芳香幕的保护!",
"cobblemon.species.mimikyu-busted.desc": "因正身就要暴露而很悲痛。绝不原谅折断了它脖子的对手,会向对方报仇。",
"item.cobblemon.syrupy_apple": "蜜汁苹果",
"item.cobblemon.syrupy_apple.tooltip": "当啃果虫使用时,会使其进化为裹蜜虫",
"item.cobblemon.syrupy_apple.tooltip": "当啃果虫使用时,可使其进化为裹蜜虫",
"cobblemon.command.unlockablepcboxwallpaper.invalid-wallpaper": "无效的壁纸标识",
"cobblemon.ui.pc.wallpaper": "壁纸",
"cobblemon.ui.pc.filter": "筛选",
@@ -8577,9 +8577,9 @@
"cobblemon.ui.pokedex.info.form.dartrix-hisuibias": "洗翠趋异的样子",
"block.cobblemon.potted_saccharine_sapling": "蜜露树苗盆栽",
"item.cobblemon.saccharine_sapling": "蜜露树苗",
"item.cobblemon.metal_alloy.tooltip": "当对铝钢龙使用时,会使其进化为铝钢桥龙",
"item.cobblemon.metal_alloy.tooltip": "当对铝钢龙使用时,可使其进化为铝钢桥龙",
"item.cobblemon.health_mochi": "体力粘糕",
"item.cobblemon.scroll_of_waters.tooltip": "当对熊徒弟使用时,会使其进化为武道熊师(连击流)",
"item.cobblemon.scroll_of_waters.tooltip": "当对熊徒弟使用时,可使其进化为武道熊师(连击流)",
"item.cobblemon.potato_mochi": "马铃薯粘糕",
"item.cobblemon.aprijuice_black": "黑球果汁",
"item.cobblemon.health_mochi.tooltip": "提升宝可梦的HP基础点数4点",
@@ -8592,7 +8592,7 @@
"item.cobblemon.metal_alloy": "复合金属",
"item.cobblemon.scroll_of_darkness": "恶之挂轴",
"item.cobblemon.scroll_of_waters": "水之挂轴",
"item.cobblemon.scroll_of_darkness.tooltip": "当对熊徒弟使用时,会使其进化为武道熊师(一击流)",
"item.cobblemon.scroll_of_darkness.tooltip": "当对熊徒弟使用时,可使其进化为武道熊师(一击流)",
"item.cobblemon.fried_rice": "炒饭",
"item.cobblemon.candied_apple": "蜜饯苹果",
"item.cobblemon.moomoo_milk": "哞哞鲜奶",
@@ -8673,13 +8673,13 @@
"item.cobblemon.ponigiri": "宝可饭团",
"item.cobblemon.poke_puff.frosted": "珍奇 %s 宝芙蕾",
"tooltip.cobblemon.poke_puff.nature.neutral": "中性",
"item.cobblemon.health_candy.tooltip_1": "提升宝可梦HP的有效个体值1点",
"item.cobblemon.brittle_candy.tooltip_1": "降低宝可梦防御的有效个体值1点",
"item.cobblemon.numb_candy.tooltip_1": "降低宝可梦特攻的有效个体值1点",
"item.cobblemon.health_candy.tooltip_1": "提升宝可梦的HP有效个体值1点",
"item.cobblemon.brittle_candy.tooltip_1": "降低宝可梦的防御有效个体值1点",
"item.cobblemon.numb_candy.tooltip_1": "降低宝可梦的特攻有效个体值1点",
"cobblemon.ui.info.gender": "性别",
"item.cobblemon.courage_candy.tooltip_1": "提升宝可梦特防的有效个体值1点",
"item.cobblemon.courage_candy.tooltip_1": "提升宝可梦的特防有效个体值1点",
"cobblemon.command.behaviouredit.non_scriptable": "您并没有看着一个可执行MoLang脚本的实体。",
"cobblemon.command.pcsearch.tooltip.shiny": "这只宝可梦已经是异色了!",
"cobblemon.command.pcsearch.tooltip.shiny": "这只是发光宝可梦!",
"cobblemon.command.pcsearch.entry": "- %1$s %2$s",
"block.cobblemon.campfire": "营火",
"block.cobblemon.campfire_pot_black": "黑色营火锅",
@@ -8711,20 +8711,20 @@
"cobblemon.tooltip.poke_puff.friendship_effects": "亲密度影响",
"item.cobblemon.health_candy": "元气糖果",
"item.cobblemon.mighty_candy": "力量糖果",
"item.cobblemon.mighty_candy.tooltip_1": "提升宝可梦攻击的有效个体值1点",
"item.cobblemon.mighty_candy.tooltip_1": "提升宝可梦的攻击有效个体值1点",
"item.cobblemon.tough_candy": "守护糖果",
"item.cobblemon.tough_candy.tooltip_1": "提升宝可梦防御的有效个体值1点",
"item.cobblemon.tough_candy.tooltip_1": "提升宝可梦的防御有效个体值1点",
"item.cobblemon.smart_candy": "知识糖果",
"item.cobblemon.smart_candy.tooltip_1": "提升宝可梦特攻的有效个体值1点",
"item.cobblemon.smart_candy.tooltip_1": "提升宝可梦的特攻有效个体值1点",
"item.cobblemon.courage_candy": "心灵糖果",
"item.cobblemon.quick_candy": "敏捷糖果",
"item.cobblemon.quick_candy.tooltip_1": "提升宝可梦速度的有效个体值1点",
"item.cobblemon.quick_candy.tooltip_1": "提升宝可梦的速度有效个体值1点",
"item.cobblemon.sickly_candy": "虚弱糖果",
"item.cobblemon.sickly_candy.tooltip_1": "降低宝可梦HP的有效个体值1点",
"item.cobblemon.weak_candy.tooltip_1": "降低宝可梦攻击的有效个体值1点",
"item.cobblemon.sickly_candy.tooltip_1": "降低宝可梦的HP有效个体值1点",
"item.cobblemon.weak_candy.tooltip_1": "降低宝可梦的攻击有效个体值1点",
"item.cobblemon.weak_candy": "软弱糖果",
"item.cobblemon.coward_candy.tooltip_1": "降低宝可梦特防的有效个体值1点",
"item.cobblemon.slow_candy.tooltip_1": "降低宝可梦速度的有效个体值1点",
"item.cobblemon.coward_candy.tooltip_1": "降低宝可梦的特防有效个体值1点",
"item.cobblemon.slow_candy.tooltip_1": "降低宝可梦的速度有效个体值1点",
"item.cobblemon.brittle_candy": "脆弱糖果",
"item.cobblemon.numb_candy": "迟钝糖果",
"item.cobblemon.coward_candy": "胆怯糖果",
@@ -9106,7 +9106,7 @@
"item.cobblemon.eggant_berry": "子茄果",
"cobblemon.entity.variable.look_at_entity_types.desc": "该实体将看向的实体类型。",
"cobblemon.entity.variable.look_at_entity_types.name": "看向实体类型",
"cobblemon.fishing_bait_effects.drops_reroll.tooltip": "%1$s%% - %3$s× 额外掉落",
"cobblemon.fishing_bait_effects.drops_reroll.tooltip": "%1$s%% - %3$s×额外掉落",
"cobblemon.requires_debug_keys": "必须在服务器上启用调试键才能使用此功能。",
"cobblemon.ui.stats.blocks_traveled": "步数",
"cobblemon.requires_permission": "你没有执行此操作的权限。",
@@ -9213,5 +9213,131 @@
"cobblemon.behaviour.defend_owner.desc": "在主人受到攻击时保护他们。",
"stat.cobblemon.riding_land": "骑着宝可梦在陆地移动距离",
"stat.cobblemon.riding_air": "骑着宝可梦在空中移动距离",
"stat.cobblemon.riding_liquid": "骑着宝可梦在水域移动距离"
"stat.cobblemon.riding_liquid": "骑着宝可梦在水域移动距离",
"item.cobblemon.sweet_heart.tooltip": "非常甜腻的巧克力",
"item.cobblemon.sweet_heart": "心形甜点",
"item.cobblemon.technical_machine": "招式学习器",
"item.cobblemon.blank_tm": "空白招式学习器",
"block.cobblemon.deepslate_crystal_core": "深层水晶母岩",
"block.cobblemon.normal_gem_block": "一般宝石块",
"block.cobblemon.fire_gem_block": "火之宝石块",
"block.cobblemon.water_gem_block": "水之宝石块",
"block.cobblemon.electric_gem_block": "草之宝石块",
"block.cobblemon.grass_gem_block": "电之宝石块",
"block.cobblemon.ice_gem_block": "冰之宝石块",
"block.cobblemon.fighting_gem_block": "格斗宝石块",
"block.cobblemon.poison_gem_block": "毒之宝石块",
"block.cobblemon.ground_gem_block": "地面宝石块",
"block.cobblemon.flying_gem_block": "飞行宝石块",
"block.cobblemon.psychic_gem_block": "超能力宝石块",
"block.cobblemon.bug_gem_block": "虫之宝石块",
"block.cobblemon.rock_gem_block": "岩石宝石块",
"block.cobblemon.ghost_gem_block": "幽灵宝石块",
"block.cobblemon.dragon_gem_block": "龙之宝石块",
"block.cobblemon.dark_gem_block": "恶之宝石块",
"block.cobblemon.steel_gem_block": "钢之宝石块",
"block.cobblemon.fairy_gem_block": "妖精宝石块",
"block.cobblemon.normal_gem_cluster": "一般宝石簇",
"block.cobblemon.fire_gem_cluster": "火之宝石簇",
"block.cobblemon.water_gem_cluster": "水之宝石簇",
"block.cobblemon.electric_gem_cluster": "电之宝石簇",
"block.cobblemon.grass_gem_cluster": "草之宝石簇",
"block.cobblemon.ice_gem_cluster": "冰之宝石簇",
"block.cobblemon.fighting_gem_cluster": "格斗宝石簇",
"block.cobblemon.poison_gem_cluster": "毒之宝石簇",
"block.cobblemon.ground_gem_cluster": "地面宝石簇",
"block.cobblemon.flying_gem_cluster": "飞行宝石簇",
"block.cobblemon.psychic_gem_cluster": "超能力宝石簇",
"block.cobblemon.bug_gem_cluster": "虫之宝石簇",
"block.cobblemon.rock_gem_cluster": "岩石宝石簇",
"block.cobblemon.ghost_gem_cluster": "幽灵宝石簇",
"block.cobblemon.dragon_gem_cluster": "龙之宝石簇",
"block.cobblemon.dark_gem_cluster": "恶之宝石簇",
"block.cobblemon.steel_gem_cluster": "钢之宝石簇",
"block.cobblemon.fairy_gem_cluster": "妖精宝石簇",
"cobblemon.item_class.technical_machine": "招式学习器",
"block.cobblemon.damaged_monitor": "损坏的数据显示器",
"block.cobblemon.tm_machine": "招式学习器机",
"block.cobblemon.disc_shelf": "光盘架",
"cobblemon.fishing_bait_effects.mark_chance.tooltip": "%1$s%% - 证章出现率+%3$s%%",
"cobblemon.fishing_bait_effects.alpha_chance.tooltip": "%1$s%% - 头目宝可梦出现率",
"cobblemon.fishing_bait_effects.size.tooltip": "%1$s%% - 体型%3$s%%",
"cobblemon.technical_machine_effect_header": "招式学习器机信息:",
"cobblemon.command.technicalmachine.invalid-tm": "无效招式学习器",
"cobblemon.ui.generic.question_marks": "???",
"cobblemon.container.tm_machine": "招式学习器机",
"cobblemon.ui.edit.habitat": "栖息地编辑器",
"cobblemon.ui.edit.habitat.mimic_id": "模仿方块ID",
"cobblemon.ui.edit.habitat.level_range": "等级范围(最小—最大)",
"cobblemon.ui.edit.habitat.mode": "模式:%s",
"cobblemon.ui.edit.habitat.mode.activated": "已激活",
"cobblemon.ui.edit.habitat.mode.natural": "自然",
"cobblemon.ui.edit.habitat.trigger": "触发器:%s",
"cobblemon.ui.edit.habitat.phase_number": "阶段数",
"cobblemon.ui.edit.habitat.phase_order": "阶段顺序:%s",
"cobblemon.ui.edit.habitat.spawn_range": "生成范围(方块数)",
"cobblemon.ui.edit.habitat.cancelled_range": "取消自然生成的范围(方块数)",
"cobblemon.ui.edit.habitat.max_spawns": "最大生成数量(-1为无限)",
"cobblemon.ui.edit.habitat.replace_spawns": "替换正常生成:%s",
"cobblemon.ui.edit.habitat.influence_range": "影响范围(方块数)",
"cobblemon.ui.edit.habitat.pool": "生成池:%s",
"cobblemon.ui.edit.habitat.pool.custom": "自定义",
"cobblemon.ui.edit.habitat.view_pool": "查看生成池",
"cobblemon.ui.edit.habitat.edit_pool": "编辑生成池",
"cobblemon.ui.edit.habitat.pool.title": "生成池编辑器",
"cobblemon.ui.edit.habitat.pool.species": "宝可梦",
"cobblemon.ui.edit.habitat.spawn.species_name": "宝可梦名称",
"cobblemon.ui.edit.habitat.pool.levels": "等级",
"cobblemon.ui.edit.habitat.pool.phases": "阶段",
"cobblemon.ui.edit.habitat.pool.position": "位置",
"cobblemon.ui.edit.habitat.pool.weight": "权重",
"cobblemon.ui.edit.habitat.pool.bucket": "稀有度档位",
"cobblemon.ui.edit.habitat.pool.add_spawn": "增加生成",
"cobblemon.ui.edit.habitat.pool.back": "返回",
"cobblemon.ui.edit.habitat.pool.select": "选择生成池",
"cobblemon.ui.edit.habitat.spawn": "生成编辑器",
"cobblemon.ui.edit.habitat.spawn.position_type": "位置类型:%s",
"cobblemon.ui.edit.habitat.spawn.bucket": "稀有度档位:%s",
"cobblemon.ui.edit.habitat.spawn.weight": "权重",
"cobblemon.ui.edit.habitat.spawn.level_range": "等级范围(最小—最大)",
"cobblemon.ui.edit.habitat.spawn.modifiers": "修饰词(例如:shiny gender=male)",
"cobblemon.ui.edit.habitat.spawn.phases": "阶段(例如:1-3, 5)",
"cobblemon.ui.edit.habitat.spawn.time_of_day": "时段",
"cobblemon.ui.edit.habitat.spawn.time_of_day.value": "时段:%s",
"cobblemon.ui.edit.habitat.spawn.time_of_day.any": "所有",
"cobblemon.ui.edit.habitat.spawn.min_light": "最低光照度(0-15,可选)",
"cobblemon.ui.edit.habitat.spawn.max_light": "最高光照度(0-15, 可选)",
"cobblemon.ui.edit.habitat.spawn.back": "返回",
"cobblemon.ui.edit.habitat.validation.mimic": "模仿方块必须是被允许且有效的方块ID(查看 habitat_mimics.json)。",
"cobblemon.ui.edit.habitat.validation.phases": "阶段数必须大于0。",
"cobblemon.ui.edit.habitat.validation.level_range": "等级范围必须处于1到100之间,且最小值不能大于最大值。",
"cobblemon.ui.edit.habitat.validation.spawn_range": "生成范围必须为0或更高。",
"cobblemon.ui.edit.habitat.validation.cancelled_range": "被取消的自然生成范围必须为 -1(不取消)或在 0 到 64 之间。",
"cobblemon.ui.edit.habitat.validation.max_spawns": "最大生成数必须是-1或更高。",
"cobblemon.ui.edit.habitat.validation.influence_range": "影响范围必须为0或更高。",
"cobblemon.ui.edit.habitat.validation.species": "必须为一个有效的宝可梦。",
"cobblemon.ui.edit.habitat.validation.weight": "权重必须大于0。",
"cobblemon.ui.edit.habitat.validation.modifiers": "修饰词的格式无效。",
"cobblemon.ui.edit.habitat.validation.min_light": "最低光照度必须处于0到15之间。",
"cobblemon.ui.edit.habitat.validation.max_light": "最高光照度必须处于0到15之间。",
"cobblemon.ui.moves.learnset.tm.discovered": "发现了",
"cobblemon.ui.moves.level": "等级提升",
"cobblemon.ui.moves.egg": "蛋",
"cobblemon.ui.moves.tm": "招式学习器",
"cobblemon.ui.tm_machine.can_learn": "能学习",
"cobblemon.ui.tm_machine.cannot_learn": "不能学",
"cobblemon.ui.tm_machine.learned": "已学会",
"cobblemon.tms.unknown_move": "未知招式",
"cobblemon.tms.already_known": "%1$s 已经学会了 %2$s!",
"cobblemon.tms.teach_move": "%1$s 学会了 %2$s!",
"cobblemon.tms.cannot_learn": "%1$s 不能学习 %2$s!",
"cobblemon.tms.unlock_tm": "你解锁了 %1$s 招式学习器!",
"cobblemon.tms.new_tms_learned": "学会了新的招式学习器!",
"cobblemon.tms.check_tmm": "查看招式学习器机",
"cobblemon.ui.party.party_select_title": "更改同行队伍选中",
"cobblemon.ui.party.party_select_description": "按下 %1$s/%2$s 或长按 %3$s 滑动鼠标滚轮。",
"cobblemon.ui.category": "分类",
"cobblemon.ui.pp": "PP",
"cobblemon.ui.pokemon.alpha": "头目",
"cobblemon.ui.edit.habitat.validation.phases_list": "阶段的格式必须使用有效的整数范围,例如:1-3或者1,3-5,6。"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 274 B

@@ -8,19 +8,9 @@
"texture": "cobblemon:textures/pokemon/0102_exeggcute/exeggcute_alola_bias.png",
"layers": []
},
{
"aspects": ["alolan"],
"model": "cobblemon:exeggcute_alola_bias.geo",
"texture": "cobblemon:textures/pokemon/0102_exeggcute/exeggcute_alola_bias.png",
"layers": []
},
{
"aspects": ["shiny", "region-bias-alola"],
"texture": "cobblemon:textures/pokemon/0102_exeggcute/exeggcute_alola_bias_shiny.png"
},
{
"aspects": ["shiny", "alolan"],
"texture": "cobblemon:textures/pokemon/0102_exeggcute/exeggcute_alola_bias_shiny.png"
}
]
}