mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 22:26:24 -04:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dcee2b8f3 | ||
|
|
224c3faa4c | ||
|
|
c42a2a6933 | ||
|
|
40af1f0bdf | ||
|
|
bb8dffdf50 | ||
|
|
952fdd8541 | ||
|
|
c30789cea4 | ||
|
|
0ada2265ff | ||
|
|
9aacff4051 | ||
|
|
3b72b558f6 | ||
|
|
ba0d7299ef | ||
|
|
f0ef34f435 | ||
|
|
646ed14146 | ||
|
|
e8d8499462 | ||
|
|
7656d1e0d8 | ||
|
|
f6d298f228 | ||
|
|
44a2f9e859 |
@@ -1,4 +1,15 @@
|
||||
# Changelog
|
||||
## [1.?.?]()
|
||||
### Developer
|
||||
- Various breaking changes have been made to ElementalTypes, Moves and other registries, Cobblemon has migrated to make use of proper Minecraft registries.
|
||||
- DamageCategory is now an Enum.
|
||||
- Gender has been moved to an API package.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- Pokémon types can now be created via datapacks. Data path is ``your_mod_namespace/cobblemon/elemental_types/path_to_your_file``.
|
||||
- Custom moves are now possible via datapacks, these require JavaScript/TypeScript programming knowledge. Data path is ``your_mod_namespace/cobblemon/moves/path_to_your_file``.
|
||||
- Pokémon species data path has been changed to ``your_mod_namespace/cobblemon/species/path_to_your_file``.
|
||||
|
||||
## [1.4.0](#1-4-0)
|
||||
### Additions
|
||||
- Added nicknaming.
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
@@ -29,6 +31,7 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculators
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
|
||||
@@ -40,6 +43,7 @@ import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
@@ -59,6 +63,7 @@ import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -161,6 +166,7 @@ object Cobblemon {
|
||||
|
||||
fun preInitialize(implementation: CobblemonImplementation) {
|
||||
this.implementation = implementation
|
||||
this.queueRegistryCreation()
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerBlocks()
|
||||
@@ -188,6 +194,8 @@ object Cobblemon {
|
||||
|
||||
ShoulderEffectRegistry.register()
|
||||
|
||||
EvolutionRegistry.init()
|
||||
|
||||
DATA_SYNCHRONIZED.subscribe {
|
||||
storage.onPlayerDataSync(it)
|
||||
playerData.get(it).sendToPlayer(it)
|
||||
@@ -472,4 +480,8 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
|
||||
}
|
||||
|
||||
private fun queueRegistryCreation() {
|
||||
this.implementation.createRegistry(CobblemonRegistryKeys.ELEMENTAL_TYPE, ElementalType.CODEC, ElementalType.NETWORK_CODEC)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.advancement.criterion.Criterion
|
||||
import net.minecraft.command.argument.serialize.ArgumentSerializer
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||
import net.minecraft.network.packet.Packet
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.resource.ResourceManager
|
||||
@@ -31,6 +33,7 @@ import net.minecraft.world.GameRules
|
||||
import net.minecraft.world.biome.Biome
|
||||
import net.minecraft.world.gen.GenerationStep
|
||||
import net.minecraft.world.gen.feature.PlacedFeature
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
interface CobblemonImplementation {
|
||||
val modAPI: ModAPI
|
||||
@@ -169,6 +172,34 @@ interface CobblemonImplementation {
|
||||
* @param manager The [ResourceManager] to reload from.
|
||||
*/
|
||||
fun <T> reloadJsonRegistry(registry: JsonDataRegistry<T>, manager: ResourceManager): HashMap<Identifier, T>
|
||||
/**
|
||||
* Queue the creation of a registry in the implementation.
|
||||
* This registry will not be immediately available for access.
|
||||
*
|
||||
* @param T The type of the registry entries.
|
||||
* @param registryKey The [RegistryKey] of this registry.
|
||||
* @param codec The [Codec] used for this registry entries to be parsed on the server.
|
||||
* @param networkCodec The [Codec] used when the client is synchronizing this registry from the server. If this is null the client will not require the registry aka not load any data.
|
||||
*
|
||||
* @see getRegistry
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun <T> createRegistry(registryKey: RegistryKey<Registry<T>>, codec: Codec<T>, networkCodec: Codec<T>? = null)
|
||||
|
||||
/**
|
||||
* Fetches a registry.
|
||||
* This is intended for Cobblemon registries but can be used for any.
|
||||
*
|
||||
* @param T The type of the registry.
|
||||
* @param registryKey The [RegistryKey] of the registry being fetched.
|
||||
* @return The registry if present.
|
||||
*
|
||||
* @throws Exception If the registry doesn't exist or isn't loaded yet.
|
||||
* @see createRegistry
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
fun <T> getRegistry(registryKey: RegistryKey<Registry<T>>): Registry<T>
|
||||
|
||||
}
|
||||
|
||||
enum class ModAPI {
|
||||
|
||||
@@ -55,11 +55,8 @@ import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
|
||||
+6
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -30,7 +31,11 @@ class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPred
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
super.fromJson(json)
|
||||
type = json.get("type")?.asString ?: "any"
|
||||
var stored = json.get("type")?.asString
|
||||
if (stored != null && stored != "any") {
|
||||
stored = stored.asIdentifierDefaultingNamespace().toString()
|
||||
}
|
||||
type = stored ?: "any"
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.PrioritizedList
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
|
||||
/**
|
||||
* A pool of potential abilities, as a [PrioritizedList]. The added logic of this subclass
|
||||
@@ -35,4 +37,22 @@ open class AbilityPool : PrioritizedList<PotentialAbility>() {
|
||||
Exception().printStackTrace()
|
||||
return Abilities.first().create() to Priority.LOWEST
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<AbilityPool> = Codec.list(Codec.STRING)
|
||||
.comapFlatMap(
|
||||
{ raw ->
|
||||
val pool = AbilityPool()
|
||||
if (raw.isEmpty()) {
|
||||
return@comapFlatMap DataResult.error { "Cannot create ability pool from an empty list" }
|
||||
}
|
||||
raw.forEach { }
|
||||
DataResult.success(pool)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,9 +10,12 @@ package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.google.gson.JsonElement
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
interface PotentialAbilityType<T : PotentialAbility> {
|
||||
fun parseFromJSON(element: JsonElement): T?
|
||||
|
||||
fun codec(): Codec<out PotentialAbilityType<*>>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,6 +48,10 @@ object CommonAbilityType : PotentialAbilityType<CommonAbility> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun codec(): Codec<out PotentialAbilityType<*>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
open class CommonAbility(override val template: AbilityTemplate) : PotentialAbility {
|
||||
|
||||
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.serialization.StringIdentifiedObjectAdapter
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import net.minecraft.entity.ai.TargetPredicate
|
||||
import net.minecraft.util.math.Box
|
||||
|
||||
@@ -44,6 +46,11 @@ interface SleepDepth {
|
||||
"normal" to normal
|
||||
)
|
||||
val adapter = StringIdentifiedObjectAdapter { depths[it] ?: throw IllegalArgumentException("Unknown sleep depth: $it") }
|
||||
|
||||
val CODEC: Codec<SleepDepth> = Codec.STRING.flatXmap(
|
||||
{ string -> depths[string]?.let { DataResult.success(it) } ?: DataResult.error { "Cannot find a SleepDepth with the ID $string" } },
|
||||
{ depth -> depths.entries.firstOrNull { it.value == depth }?.let { DataResult.success(it.key) } ?: DataResult.error { "Cannot resolve a ID for the SleepDepth $depth" } }
|
||||
)
|
||||
}
|
||||
|
||||
fun canSleep(pokemonEntity: PokemonEntity): Boolean
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.conditional
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class RegistryElementCondition<T>(val element: T, private val source: Identifier) : RegistryLikeCondition<T> {
|
||||
|
||||
override fun fits(value: T, registry: Registry<T>): Boolean = value == this.element
|
||||
|
||||
override fun pretty(): String = this.source.toString()
|
||||
|
||||
}
|
||||
-31
@@ -1,31 +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.conditional
|
||||
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* Adapter for [RegistryLikeCondition]s. Its logic is that the implementation of this adapter must
|
||||
* provide a list of resolvers, and the deserializer will find the first resolver that returns a non-null
|
||||
* value for the [JsonElement].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 17th, 2022
|
||||
*/
|
||||
interface RegistryLikeAdapter<B> : JsonDeserializer<RegistryLikeCondition<B>> {
|
||||
val registryLikeConditions: MutableList<(JsonElement) -> RegistryLikeCondition<B>?>
|
||||
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): RegistryLikeCondition<B> {
|
||||
return registryLikeConditions.firstNotNullOfOrNull { it(json) }
|
||||
?: throw IllegalArgumentException("Unable to deserialize $json")
|
||||
}
|
||||
}
|
||||
+43
-2
@@ -8,7 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.conditional
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition which applies to an entry in some [Registry].
|
||||
@@ -16,6 +20,43 @@ import net.minecraft.registry.Registry
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
interface RegistryLikeCondition<T> {
|
||||
fun fits(t: T, registry: Registry<T>): Boolean
|
||||
sealed interface RegistryLikeCondition<T> {
|
||||
|
||||
/**
|
||||
* Checks if a given [value] matches this condition.
|
||||
*
|
||||
* @param value The value being matched against this condition.
|
||||
* @param registry The [Registry] of type [T] being queried.
|
||||
* @return If the condition is fulfilled.
|
||||
*/
|
||||
fun fits(value: T, registry: Registry<T>): Boolean
|
||||
|
||||
/**
|
||||
* Generates a string like human-friendly representation used by the Codec when serializing.
|
||||
*
|
||||
* @return The string like human-friendly representation.
|
||||
*/
|
||||
fun pretty(): String
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun <T> createCodec(registryAccessor: () -> Registry<T>): Codec<RegistryLikeCondition<T>> = Codec.STRING.comapFlatMap(
|
||||
{ string ->
|
||||
val registry = registryAccessor.invoke()
|
||||
val isTag = string.startsWith("#")
|
||||
val rawIdentifier = if (isTag) string.substringAfter("#") else string
|
||||
val identifier = Identifier.tryParse(rawIdentifier) ?: return@comapFlatMap DataResult.error { "Cannot resolve identifier/tag from the string $string" }
|
||||
if (isTag) {
|
||||
val tag = TagKey.of(registry.key, identifier)
|
||||
return@comapFlatMap DataResult.success(RegistryTagCondition(tag))
|
||||
}
|
||||
val element = registry.get(identifier) ?: return@comapFlatMap DataResult.error { "Cannot find an element in registry ${registry.key.value} with the ID $identifier" }
|
||||
return@comapFlatMap DataResult.success(RegistryElementCondition(element, identifier))
|
||||
},
|
||||
{ it.pretty() }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +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.conditional
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition for some registry type which asserts that the entry must have the given [Identifier].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
open class RegistryLikeIdentifierCondition<T>(val identifier: Identifier) : RegistryLikeCondition<T> {
|
||||
companion object {
|
||||
fun <T> resolver(
|
||||
constructor: (Identifier) -> RegistryLikeIdentifierCondition<T>
|
||||
): (JsonElement) -> RegistryLikeIdentifierCondition<T>? = { constructor(Identifier(it.asString)) }
|
||||
}
|
||||
override fun fits(t: T, registry: Registry<T>) = registry.getId(t) == identifier
|
||||
}
|
||||
-54
@@ -1,54 +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.conditional
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A condition for some registry type that asserts that the entry must be inside the given [TagKey]. This is presented
|
||||
* in JSONs as an identifier prefixed with a hash.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since July 16th, 2022
|
||||
*/
|
||||
open class RegistryLikeTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
|
||||
|
||||
companion object {
|
||||
const val PREFIX = "#"
|
||||
fun <T> resolver(
|
||||
registryKey: RegistryKey<Registry<T>>,
|
||||
constructor: (TagKey<T>) -> RegistryLikeTagCondition<T>
|
||||
): (JsonElement) -> RegistryLikeTagCondition<T>? = {
|
||||
val firstSymbol = it.asString.substring(0, 1)
|
||||
if (firstSymbol == PREFIX) {
|
||||
val identifier = Identifier(it.asString.substring(1))
|
||||
constructor(TagKey.of(registryKey, identifier))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun fits(t: T, registry: Registry<T>): Boolean {
|
||||
// val registryHasTag = registry.containsTag(tag)
|
||||
// if (!registryHasTag) {
|
||||
//// LOGGER.warn("No tag in registry: ${tag.id}")
|
||||
// return false
|
||||
// }
|
||||
|
||||
return registry.getKey(t)
|
||||
.flatMap(registry::getEntry)
|
||||
.map { entry -> entry.isIn(tag) }
|
||||
.orElse(false)
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.conditional
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
|
||||
class RegistryTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
|
||||
|
||||
override fun fits(value: T, registry: Registry<T>): Boolean = registry.getEntry(value).isIn(this.tag)
|
||||
|
||||
override fun pretty(): String = "#${this.tag.id}"
|
||||
|
||||
}
|
||||
@@ -8,11 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events
|
||||
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPostEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.*
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
|
||||
@@ -43,6 +39,7 @@ import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
@Suppress("unused")
|
||||
object CobblemonEvents {
|
||||
|
||||
@JvmField
|
||||
@@ -105,6 +102,7 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val ENTITY_SPAWN = CancelableObservable<SpawnEvent<*>>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@JvmField
|
||||
val POKEMON_ENTITY_SPAWN = ENTITY_SPAWN
|
||||
.pipe(
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.moves
|
||||
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the damage category of a [MoveTemplate]/[Move].
|
||||
*
|
||||
* @see MoveTemplate
|
||||
* @see Move
|
||||
*/
|
||||
enum class DamageCategory : StringIdentifiable {
|
||||
|
||||
PHYSICAL,
|
||||
SPECIAL,
|
||||
STATUS;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Resolves the display name of this damage category.
|
||||
*
|
||||
* @return The generated text.
|
||||
*/
|
||||
fun displayName(): MutableText = lang("move.category.${this.name.lowercase()}")
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<DamageCategory> = StringIdentifiable.createCodec(DamageCategory::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
|
||||
@@ -8,14 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.math.random.Random
|
||||
|
||||
/**
|
||||
* This class represents the base of a Move.
|
||||
@@ -48,6 +49,27 @@ open class MoveTemplate(
|
||||
val effectChances: Array<Double>
|
||||
) {
|
||||
|
||||
companion object {
|
||||
fun dummy(name: String) = Dummy(name)
|
||||
|
||||
val CODEC: Codec<MoveTemplate> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.fieldOf("name").forGetter(MoveTemplate::name),
|
||||
Codec.INT.fieldOf("num").forGetter(MoveTemplate::num),
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.codec.fieldOf("type").forGetter(MoveTemplate::elementalType),
|
||||
DamageCategory.CODEC.fieldOf("damageCategory").forGetter(MoveTemplate::damageCategory),
|
||||
Codec.DOUBLE.fieldOf("power").forGetter(MoveTemplate::power),
|
||||
MoveTarget.CODEC.fieldOf("target").forGetter(MoveTemplate::target),
|
||||
Codec.DOUBLE.fieldOf("accuracy").forGetter(MoveTemplate::accuracy),
|
||||
Codec.INT.fieldOf("pp").forGetter(MoveTemplate::pp),
|
||||
Codec.INT.fieldOf("priority").forGetter(MoveTemplate::priority),
|
||||
Codec.DOUBLE.fieldOf("critRatio").forGetter(MoveTemplate::critRatio),
|
||||
Codec.list(Codec.DOUBLE).fieldOf("effectChances").xmap({ e -> e.toTypedArray() }, { e -> e.toList() }).forGetter(MoveTemplate::effectChances)
|
||||
).apply(builder, ::MoveTemplate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val displayName: MutableText
|
||||
get() = lang("move.$name")
|
||||
val description: MutableText
|
||||
@@ -57,8 +79,8 @@ open class MoveTemplate(
|
||||
class Dummy(name: String) : MoveTemplate(
|
||||
name = name,
|
||||
num = -1,
|
||||
elementalType = ElementalTypes.NORMAL,
|
||||
damageCategory = DamageCategories.STATUS,
|
||||
elementalType = CobblemonRegistries.ELEMENTAL_TYPE.getRandom(Random.create()).orElseThrow().value(),
|
||||
damageCategory = DamageCategory.STATUS,
|
||||
power = 0.0,
|
||||
target = MoveTarget.all,
|
||||
accuracy = 100.0,
|
||||
@@ -68,10 +90,6 @@ open class MoveTemplate(
|
||||
effectChances = emptyArray()
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun dummy(name: String) = Dummy(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Move with full PP
|
||||
*/
|
||||
@@ -92,4 +110,5 @@ open class MoveTemplate(
|
||||
template = this
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,9 +10,8 @@ package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
@@ -44,8 +43,8 @@ object Moves : DataRegistry {
|
||||
val id = jsMove.get("id").asString
|
||||
try {
|
||||
val num = jsMove.get("num").asInt
|
||||
val elementalType = ElementalTypes.getOrException(jsMove.get("type").asString)
|
||||
val damageCategory = DamageCategories.getOrException(jsMove.get("category").asString)
|
||||
val elementalType = CobblemonRegistries.ELEMENTAL_TYPE.first { it.showdownId() == jsMove.get("type").asString }
|
||||
val damageCategory = DamageCategory.valueOf(jsMove.get("category").asString.uppercase())
|
||||
val power = jsMove.get("basePower").asDouble
|
||||
val target = MoveTarget.fromShowdownId(jsMove.get("target").asString)
|
||||
// If not a double it's always true
|
||||
|
||||
-30
@@ -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.moves.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object DamageCategoryAdapter: JsonSerializer<DamageCategory>, JsonDeserializer<DamageCategory> {
|
||||
|
||||
override fun serialize(src: DamageCategory, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.name)
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): DamageCategory {
|
||||
return DamageCategories.getOrException(json.asString)
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +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.moves.categories
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object DamageCategories {
|
||||
private val allCategories = mutableListOf<DamageCategory>()
|
||||
|
||||
val PHYSICAL = register(
|
||||
name = "physical",
|
||||
displayName = Text.translatable("cobblemon.move.category.physical"),
|
||||
textureXMultiplier = 0
|
||||
)
|
||||
val SPECIAL = register(
|
||||
name = "special",
|
||||
displayName = Text.translatable("cobblemon.move.category.special"),
|
||||
textureXMultiplier = 1
|
||||
)
|
||||
val STATUS = register(
|
||||
name = "status",
|
||||
displayName = Text.translatable("cobblemon.move.category.status"),
|
||||
textureXMultiplier = 2
|
||||
)
|
||||
|
||||
fun register(
|
||||
name: String,
|
||||
displayName: Text,
|
||||
resourceLocation: Identifier = cobblemonResource("textures/gui/categories.png"),
|
||||
textureXMultiplier: Int
|
||||
): DamageCategory {
|
||||
return DamageCategory(
|
||||
name = name,
|
||||
displayName = displayName,
|
||||
textureXMultiplier = textureXMultiplier,
|
||||
resourceLocation = resourceLocation
|
||||
).also {
|
||||
allCategories.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun register(damageCategory: DamageCategory): DamageCategory {
|
||||
allCategories.add(damageCategory)
|
||||
return damageCategory
|
||||
}
|
||||
|
||||
fun get(name: String): DamageCategory? {
|
||||
return allCategories.firstOrNull { cat -> cat.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun getOrException(name: String): DamageCategory {
|
||||
return allCategories.first { cat -> cat.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun count() = allCategories.size
|
||||
}
|
||||
-28
@@ -1,28 +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.moves.categories
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Representing a DamageCategory from the Pokemon Game
|
||||
*
|
||||
* @param name: The English name used to load / find it (spaces -> _)
|
||||
* @param displayName: A Component used to display the name, normally a TranslatableText
|
||||
* @param resourceLocation: The location of the resource used in the GUI
|
||||
*/
|
||||
class DamageCategory(
|
||||
val name: String,
|
||||
val displayName: Text,
|
||||
val textureXMultiplier: Int,
|
||||
val resourceLocation: Identifier = cobblemonResource("textures/gui/categories.png")
|
||||
) {
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.CobblemonElementalTypeTags
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
@@ -136,13 +136,13 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
|
||||
createDefault("level_ball", CatchRateModifiers.LEVEL)
|
||||
// ToDo we will need fishing context here once fishing is implemented for a multiplier
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, ElementalTypes.WATER))
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, CobblemonElementalTypeTags.LURE_BALL_BOOSTING))
|
||||
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
|
||||
createDefault("love_ball", CatchRateModifiers.LOVE)
|
||||
createDefault("friend_ball", effects = listOf(CaptureEffects.friendshipSetter(150)))
|
||||
createDefault("moon_ball", CatchRateModifiers.MOON_PHASES)
|
||||
createDefault("sport_ball", MultiplierModifier(1.5F))
|
||||
createDefault("net_ball", CatchRateModifiers.typeBoosting(3F, ElementalTypes.BUG, ElementalTypes.WATER))
|
||||
createDefault("net_ball", CatchRateModifiers.typeBoosting(3F, CobblemonElementalTypeTags.NET_BALL_BOOSTING))
|
||||
createDefault("dive_ball", CatchRateModifiers.SUBMERGED_IN_WATER, waterDragValue = 0.99F)
|
||||
createDefault("nest_ball", CatchRateModifiers.NEST)
|
||||
// ToDo implement effect once pokedex is implemented, we have a custom multiplier of 2.5 instead of the official pokeball
|
||||
|
||||
+5
-4
@@ -14,7 +14,8 @@ import com.cobblemon.mod.common.api.pokemon.status.Status
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBiomeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
|
||||
/**
|
||||
* A collection of some default usages of [CatchRateModifier]s.
|
||||
@@ -139,11 +140,11 @@ object CatchRateModifiers {
|
||||
* Used by [PokeBalls.NET_BALL].
|
||||
* Boosts the catch rate if the target is of the given types.
|
||||
*
|
||||
* @param multiplier The multiplier to be applied if the target has any of the accepted [types].
|
||||
* @param types The [ElementalType]s that will trigger the multiplier.
|
||||
* @param multiplier The multiplier to be applied if the target has any of the accepted [typeTag].
|
||||
* @param typeTag The [ElementalType] [TagKey] that will trigger the multiplier.
|
||||
* @return The multiplier modifier.
|
||||
*/
|
||||
fun typeBoosting(multiplier: Float, vararg types: ElementalType): CatchRateModifier = MultiplierModifier(multiplier) { _, pokemon -> pokemon.types.any { type -> types.contains(type) } }
|
||||
fun typeBoosting(multiplier: Float, typeTag: TagKey<ElementalType>): CatchRateModifier = MultiplierModifier(multiplier) { _, pokemon -> pokemon.types.any { type -> type.isIn(typeTag) } }
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.DREAM_BALL].
|
||||
|
||||
@@ -12,13 +12,14 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
@@ -30,10 +31,12 @@ import com.cobblemon.mod.common.util.splitMap
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import kotlin.random.Random
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -91,7 +94,7 @@ open class PokemonProperties {
|
||||
props.ability = parseStringOfRegistry(keyPairs, listOf("ability")) { Abilities.get(it)?.name }
|
||||
props.status = parseStringOfRegistry(keyPairs, listOf("status")) { (Statuses.getStatus(it) ?: Statuses.getStatus(it.asIdentifierDefaultingNamespace()))?.showdownName }
|
||||
props.nickname = parseText(keyPairs, listOf("nickname", "nick"))
|
||||
props.teraType = parseStringOfRegistry(keyPairs, listOf("tera_type", "tera")) { ElementalTypes.get(it)?.name }
|
||||
props.teraType = parseRegistryValue(CobblemonRegistries.ELEMENTAL_TYPE, keyPairs, "tera_type", "tera")
|
||||
props.dmaxLevel = parseIntProperty(keyPairs, listOf("dmax_level", "dmax"))?.coerceIn(0, Cobblemon.config.maxDynamaxLevel)
|
||||
props.gmaxFactor = parseBooleanProperty(keyPairs, listOf("gmax_factor", "gmax"))
|
||||
props.tradeable = parseBooleanProperty(keyPairs, listOf("tradeable", "tradable"))
|
||||
@@ -196,6 +199,17 @@ open class PokemonProperties {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> parseRegistryValue(registry: Registry<T>, keyPairs: MutableList<Pair<String, String?>>, vararg labels: String): T? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels.asIterable()) ?: return null
|
||||
val rawId = matchingKeyPair.second ?: return null
|
||||
return try {
|
||||
val id = Identifier(rawId)
|
||||
registry.get(id)
|
||||
} catch (_: InvalidIdentifierException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseForm(keyPairs: MutableList<Pair<String, String?>>): String? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, listOf("form")) ?: return null
|
||||
keyPairs.remove(matchingKeyPair)
|
||||
@@ -240,6 +254,9 @@ open class PokemonProperties {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val CODEC: Codec<PokemonProperties> = Codec.STRING.xmap(PokemonProperties::parse, PokemonProperties::asString)
|
||||
|
||||
}
|
||||
|
||||
var originalString: String = ""
|
||||
@@ -256,7 +273,7 @@ open class PokemonProperties {
|
||||
var ability: String? = null
|
||||
var aspects: Set<String> = emptySet()
|
||||
var status: String? = null
|
||||
var teraType: String? = null
|
||||
var teraType: ElementalType? = null
|
||||
var dmaxLevel: Int? = null
|
||||
var gmaxFactor: Boolean? = null
|
||||
var tradeable: Boolean? = null
|
||||
@@ -309,7 +326,7 @@ open class PokemonProperties {
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemon.teraType = type } }
|
||||
teraType?.let { type -> pokemon.teraType = type }
|
||||
dmaxLevel?.let { pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemon.tradeable = it }
|
||||
@@ -349,7 +366,7 @@ open class PokemonProperties {
|
||||
pokemonEntity.pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemonEntity.pokemon.teraType = type } }
|
||||
teraType?.let { type -> pokemonEntity.pokemon.teraType = type }
|
||||
dmaxLevel?.let { pokemonEntity.pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemonEntity.pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemonEntity.pokemon.tradeable = it }
|
||||
@@ -387,7 +404,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemon.teraType.name }?.let { return false }
|
||||
teraType?.takeIf { it != pokemon.teraType }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemon.tradeable }?.let { return false }
|
||||
@@ -408,7 +425,7 @@ open class PokemonProperties {
|
||||
if (pokemonEntity.pokemon.species != species) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != pokemonEntity.pokemon.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemonEntity.pokemon.form.name, true) }?.let { return false }
|
||||
@@ -423,7 +440,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType.name }?.let { return false }
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemonEntity.pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemonEntity.pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemonEntity.pokemon.tradeable }?.let { return false }
|
||||
@@ -444,7 +461,7 @@ open class PokemonProperties {
|
||||
if (properties.species != species.toString()) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != properties.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
|
||||
@@ -488,7 +505,7 @@ open class PokemonProperties {
|
||||
if (this.shiny == null) pokemon.shiny = Cobblemon.config.shinyRate.checkRate()
|
||||
if (this.gmaxFactor == null) pokemon.gmaxFactor = Cobblemon.config.gigantamaxFactorRate.checkRate()
|
||||
if (this.teraType == null) pokemon.teraType =
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) ElementalTypes.all().filter { !baseTypes.contains(it) }.random()
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) CobblemonRegistries.ELEMENTAL_TYPE.filter { !baseTypes.contains(it) }.random()
|
||||
else baseTypes.random()
|
||||
}
|
||||
|
||||
@@ -515,7 +532,7 @@ open class PokemonProperties {
|
||||
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, it.saveToNBT(NbtCompound())) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, it.saveToNBT(NbtCompound())) }
|
||||
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it.id().toString()) }
|
||||
dmaxLevel?.let { nbt.putInt(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
gmaxFactor?.let { nbt.putBoolean(DataKeys.POKEMON_GMAX_FACTOR, it) }
|
||||
tradeable?.let { nbt.putBoolean(DataKeys.POKEMON_TRADEABLE, it) }
|
||||
@@ -540,7 +557,7 @@ open class PokemonProperties {
|
||||
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) ivs?.loadFromNBT(tag.getCompound(DataKeys.POKEMON_IVS)) as IVs? else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) evs?.loadFromNBT(tag.getCompound(DataKeys.POKEMON_EVS)) as EVs? else null
|
||||
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) tag.getString(DataKeys.POKEMON_TERA_TYPE) else null
|
||||
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) CobblemonRegistries.ELEMENTAL_TYPE.get(Identifier(tag.getString(DataKeys.POKEMON_TERA_TYPE))) else null
|
||||
dmaxLevel = if (tag.contains(DataKeys.POKEMON_DMAX_LEVEL)) tag.getInt(DataKeys.POKEMON_DMAX_LEVEL) else null
|
||||
gmaxFactor = if (tag.contains(DataKeys.POKEMON_GMAX_FACTOR)) tag.getBoolean(DataKeys.POKEMON_GMAX_FACTOR) else null
|
||||
tradeable = if (tag.contains(DataKeys.POKEMON_TRADEABLE)) tag.getBoolean(DataKeys.POKEMON_TRADEABLE) else null
|
||||
@@ -567,7 +584,7 @@ open class PokemonProperties {
|
||||
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, it.saveToJSON(JsonObject())) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, it.saveToJSON(JsonObject())) }
|
||||
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it.id().toString()) }
|
||||
dmaxLevel?.let { json.addProperty(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
gmaxFactor?.let { json.addProperty(DataKeys.POKEMON_GMAX_FACTOR, it) }
|
||||
tradeable?.let { json.addProperty(DataKeys.POKEMON_TRADEABLE, it) }
|
||||
@@ -593,7 +610,9 @@ open class PokemonProperties {
|
||||
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
|
||||
ivs?.loadFromJSON(json.getAsJsonObject(DataKeys.POKEMON_IVS))
|
||||
evs?.loadFromJSON(json.getAsJsonObject(DataKeys.POKEMON_EVS))
|
||||
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString
|
||||
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString?.let { CobblemonRegistries.ELEMENTAL_TYPE.get(
|
||||
Identifier(it)
|
||||
) }
|
||||
dmaxLevel = json.get(DataKeys.POKEMON_DMAX_LEVEL)?.asInt
|
||||
gmaxFactor = json.get(DataKeys.POKEMON_GMAX_FACTOR)?.asBoolean
|
||||
tradeable = json.get(DataKeys.POKEMON_TRADEABLE)?.asBoolean
|
||||
@@ -623,7 +642,7 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
pieces.add("${stat.key}_ev=${stat.value}")
|
||||
}
|
||||
teraType?.let { pieces.add("tera_type=$it") }
|
||||
teraType?.let { pieces.add("tera_type=${it.id()}") }
|
||||
dmaxLevel?.let { pieces.add("dmax_level=$it") }
|
||||
gmaxFactor?.let { pieces.add("gmax_factor=$it") }
|
||||
tradeable?.let { pieces.add("tradeable=$it") }
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
|
||||
@@ -38,14 +37,14 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.common.collect.HashBasedTable
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -56,6 +55,7 @@ import net.minecraft.entity.effect.StatusEffect
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -76,11 +76,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(ExperienceGroup::class.java, ExperienceGroupAdapter)
|
||||
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
|
||||
.registerTypeAdapter(Learnset::class.java, LearnsetAdapter)
|
||||
.registerTypeAdapter(Evolution::class.java, CobblemonEvolutionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(AbilityPool::class.java, AbilityPoolAdapter)
|
||||
.registerTypeAdapter(EvolutionRequirement::class.java, CobblemonRequirementAdapter)
|
||||
.registerTypeAdapter(PreEvolution::class.java, CobblemonPreEvolutionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Set::class.java, Evolution::class.java).type, LazySetAdapter(Evolution::class))
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
@@ -90,9 +87,9 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(SleepDepth::class.java, SleepDepth.adapter)
|
||||
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
|
||||
.registerTypeAdapter(NbtCompound::class.java, NbtCompoundAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, RegistryLikeCondition.createCodec { Registries.ITEM }.toTypeAdapter())
|
||||
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
|
||||
.registerTypeAdapter(StatusEffect::class.java, RegistryElementAdapter<StatusEffect> { Registries.STATUS_EFFECT })
|
||||
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
|
||||
@@ -211,7 +208,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
"H" to "No Ability",
|
||||
"S" to "No Ability"
|
||||
)
|
||||
val types = (form?.types ?: species.types).map { it.name.replaceFirstChar(Char::uppercase) }
|
||||
val types = (form?.types ?: species.types).map { it.showdownId() }
|
||||
val preevo: String? = (form?.preEvolution ?: species.preEvolution)?.let { if (it.form == it.species.standardForm) createShowdownName(it.species) else "${createShowdownName(it.species)}-${it.form.name}" }
|
||||
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
|
||||
val evos = if ((form?.evolutions ?: species.evolutions).isEmpty()) emptyList() else arrayListOf("")
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.egg
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* These represent categories which determine which Pokémon are able to interbreed.
|
||||
*
|
||||
@@ -15,7 +18,7 @@ package com.cobblemon.mod.common.api.pokemon.egg
|
||||
*
|
||||
* @property showdownID used for data synchronization with Showdown data format.
|
||||
*/
|
||||
enum class EggGroup(internal val showdownID: String) {
|
||||
enum class EggGroup(internal val showdownID: String) : StringIdentifiable {
|
||||
|
||||
MONSTER("Monster"),
|
||||
WATER_1("Water 1"),
|
||||
@@ -31,6 +34,15 @@ enum class EggGroup(internal val showdownID: String) {
|
||||
WATER_2("Water 2"),
|
||||
DITTO("Ditto"),
|
||||
DRAGON("Dragon"),
|
||||
UNDISCOVERED("Undiscovered")
|
||||
UNDISCOVERED("Undiscovered");
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<EggGroup> = StringIdentifiable.createCodec(EggGroup::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,12 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
|
||||
import com.cobblemon.mod.common.api.moves.BenchedMove
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.Variant
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.sound.SoundCategory
|
||||
|
||||
@@ -61,6 +62,11 @@ interface Evolution : EvolutionLike {
|
||||
*/
|
||||
val learnableMoves: MutableSet<MoveTemplate>
|
||||
|
||||
/**
|
||||
* The [Variant] of this [Evolution].
|
||||
*/
|
||||
val variant: Variant<Evolution>
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] passes all the conditions and is ready to evolve.
|
||||
*
|
||||
@@ -120,4 +126,12 @@ interface Evolution : EvolutionLike {
|
||||
fun applyTo(pokemon: Pokemon) {
|
||||
result.apply(pokemon)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun codec(): Codec<out Evolution> = this.variant.codec
|
||||
|
||||
}
|
||||
+8
-8
@@ -8,9 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.StandardPreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Represents the previous stage in the evolutionary line of a given Pokémon.
|
||||
@@ -19,15 +20,14 @@ import com.cobblemon.mod.common.pokemon.evolution.StandardPreEvolution
|
||||
* @author Licious
|
||||
* @since March 22nd, 2022
|
||||
*/
|
||||
interface PreEvolution {
|
||||
class PreEvolution internal constructor(private val speciesKey: Identifier){
|
||||
|
||||
val species: Species
|
||||
|
||||
val form: FormData
|
||||
val species: Species by lazy { CobblemonRegistries.SPECIES.get(this.speciesKey)!! }
|
||||
|
||||
companion object {
|
||||
|
||||
fun of(species: Species, form: FormData = species.standardForm): PreEvolution = StandardPreEvolution(species, form)
|
||||
@JvmField
|
||||
val CODEC: Codec<PreEvolution> = Identifier.CODEC.xmap(::PreEvolution, PreEvolution::speciesKey)
|
||||
|
||||
}
|
||||
|
||||
|
||||
-35
@@ -1,35 +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.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [Evolution]s with JSON.
|
||||
* For the default implementation see [CobblemonEvolutionAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 20th, 2022
|
||||
*/
|
||||
interface EvolutionAdapter : JsonDeserializer<Evolution>, JsonSerializer<Evolution> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [Evolution] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [Evolution].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : Evolution> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.*
|
||||
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.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Lifecycle
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.SimpleRegistry
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
object EvolutionRegistry {
|
||||
|
||||
private val EVOLUTION_REGISTRY = SimpleRegistry<Variant<Evolution>>(RegistryKey.ofRegistry(cobblemonResource("evolution_variants")), Lifecycle.stable())
|
||||
private val REQUIREMENT_REGISTRY = SimpleRegistry<Variant<EvolutionRequirement>>(RegistryKey.ofRegistry(cobblemonResource("evolution_requirements")), Lifecycle.stable())
|
||||
|
||||
/**
|
||||
* A [Codec] for [Evolution].
|
||||
* If you wish to register more variants see [registerEvolutionVariant].
|
||||
*/
|
||||
@JvmField
|
||||
val EVOLUTION_CODEC: Codec<Evolution> = EVOLUTION_REGISTRY.codec.dispatch("variant", Evolution::variant) { variant -> variant.codec }
|
||||
|
||||
/**
|
||||
* A [Codec] for [EvolutionRequirement].
|
||||
* If you wish to register more variants see [registerRequirementVariant].
|
||||
*/
|
||||
@JvmField
|
||||
val REQUIREMENT_CODEC: Codec<EvolutionRequirement> = REQUIREMENT_REGISTRY.codec.dispatch("variant", EvolutionRequirement::variant) { variant -> variant.codec }
|
||||
|
||||
/**
|
||||
* Registers an [Evolution] type.
|
||||
*
|
||||
* @param variant The [Variant] of an [Evolution] being registered.
|
||||
*
|
||||
* @throws IllegalStateException If the backing registry already contains an entry with the [Variant.identifier].
|
||||
* @throws AssertionError If the registry is missing an intrusive holder.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerEvolutionVariant(variant: Variant<Evolution>) {
|
||||
EVOLUTION_REGISTRY.add(RegistryKey.of(EVOLUTION_REGISTRY.key, variant.identifier), variant, Lifecycle.stable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an [EvolutionRequirement] type.
|
||||
*
|
||||
* @param variant The [Variant] of an [EvolutionRequirement] being registered.
|
||||
*
|
||||
* @throws IllegalStateException If the backing registry already contains an entry with the [Variant.identifier].
|
||||
* @throws AssertionError If the registry is missing an intrusive holder.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerRequirementVariant(variant: Variant<EvolutionRequirement>) {
|
||||
REQUIREMENT_REGISTRY.add(RegistryKey.of(REQUIREMENT_REGISTRY.key, variant.identifier), variant, Lifecycle.stable())
|
||||
}
|
||||
|
||||
internal fun init() {
|
||||
this.registerDefaultEvolutions()
|
||||
this.registerDefaultRequirements()
|
||||
}
|
||||
|
||||
private fun registerDefaultEvolutions() {
|
||||
this.registerEvolutionVariant(BlockClickEvolution.VARIANT)
|
||||
this.registerEvolutionVariant(ItemInteractionEvolution.VARIANT)
|
||||
this.registerEvolutionVariant(LevelUpEvolution.MAIN_VARIANT)
|
||||
this.registerEvolutionVariant(LevelUpEvolution.ALTERNATIVE_VARIANT)
|
||||
this.registerEvolutionVariant(TradeEvolution.VARIANT)
|
||||
}
|
||||
|
||||
private fun registerDefaultRequirements() {
|
||||
this.registerRequirementVariant(AllOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AnyOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AreaRequirement.VARIANT)
|
||||
this.registerRequirementVariant(AttackDefenceRatioRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BattleCriticalHitsRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BiomeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(BlocksTraveledRequirement.VARIANT)
|
||||
this.registerRequirementVariant(DamageTakenRequirement.VARIANT)
|
||||
this.registerRequirementVariant(DefeatRequirement.VARIANT)
|
||||
this.registerRequirementVariant(FriendshipRequirement.VARIANT)
|
||||
this.registerRequirementVariant(HeldItemRequirement.VARIANT)
|
||||
this.registerRequirementVariant(LevelRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoonPhaseRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoveSetRequirement.VARIANT)
|
||||
this.registerRequirementVariant(MoveTypeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(NoneOfRequirement.VARIANT)
|
||||
this.registerRequirementVariant(NotRequirement.VARIANT)
|
||||
this.registerRequirementVariant(PartyMemberRequirement.VARIANT)
|
||||
this.registerRequirementVariant(PokemonPropertiesRequirement.VARIANT)
|
||||
this.registerRequirementVariant(RecoilRequirement.VARIANT)
|
||||
this.registerRequirementVariant(TimeRangeRequirement.VARIANT)
|
||||
this.registerRequirementVariant(UseMoveRequirement.VARIANT)
|
||||
this.registerRequirementVariant(WeatherRequirement.VARIANT)
|
||||
this.registerRequirementVariant(WorldRequirement.VARIANT)
|
||||
}
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +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.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [EvolutionRequirement]s with JSON.
|
||||
* For the default implementation see [CobblemonRequirementAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 21st, 2022
|
||||
*/
|
||||
interface RequirementAdapter : JsonDeserializer<EvolutionRequirement>, JsonSerializer<EvolutionRequirement> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [EvolutionRequirement] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [EvolutionRequirement].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : EvolutionRequirement> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
+8
-6
@@ -6,10 +6,12 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
enum class Gender(val showdownName: String) {
|
||||
MALE("M"),
|
||||
FEMALE("F"),
|
||||
GENDERLESS("N")
|
||||
}
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
data class Variant<T>(
|
||||
val identifier: Identifier,
|
||||
val codec: Codec<out T>
|
||||
)
|
||||
+22
-1
@@ -10,7 +10,10 @@ package com.cobblemon.mod.common.api.pokemon.evolution.requirement
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.Variant
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
/**
|
||||
* Represents a requirement for an evolution.
|
||||
@@ -22,7 +25,12 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
fun interface EvolutionRequirement {
|
||||
interface EvolutionRequirement {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
val variant: Variant<EvolutionRequirement>
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] satisfies the requirement.
|
||||
@@ -32,4 +40,17 @@ fun interface EvolutionRequirement {
|
||||
*/
|
||||
fun check(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun codec(): Codec<out EvolutionRequirement> = this.variant.codec
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<EvolutionRequirement> = EvolutionRegistry.REQUIREMENT_CODEC
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -18,6 +18,7 @@ import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import com.mojang.serialization.Codec
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.math.max
|
||||
import net.minecraft.text.MutableText
|
||||
@@ -74,6 +75,10 @@ interface ExperienceGroup : LevelCurve {
|
||||
override fun getExperience(level: Int) = 0
|
||||
override fun getLevel(experience: Int) = 1
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CODEC: Codec<ExperienceGroup> = Codec.STRING.xmap(ExperienceGroups::findByName, ExperienceGroup::name)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.gender
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Represents the [Gender] of a [Pokemon].
|
||||
* This is taken into account by [Species] when generating the [Pokemon].
|
||||
*
|
||||
* @property showdownId The ID of the [Gender] in Showdown.
|
||||
*
|
||||
* @see Species.genderSelector
|
||||
* @see Pokemon.gender
|
||||
* @see GenderSelector
|
||||
*/
|
||||
enum class Gender(private val showdownId: String) : ShowdownIdentifiable {
|
||||
|
||||
MALE("M"),
|
||||
FEMALE("F"),
|
||||
GENDERLESS("N");
|
||||
|
||||
override fun showdownId(): String = this.showdownId
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* The [Gender]s when a ratio is attached to a [GenderSelector].
|
||||
*
|
||||
* @see GenderSelector.maleRatio
|
||||
*/
|
||||
@JvmField
|
||||
val RATIO_BASED_GENDERS: Set<Gender> = EnumSet.of(MALE, FEMALE)
|
||||
|
||||
/**
|
||||
* The [Gender]s when no ratio is attached to a [GenderSelector].
|
||||
*
|
||||
* @see GenderSelector.maleRatio
|
||||
*/
|
||||
@JvmField
|
||||
val NO_RATIO_GENDERS: Set<Gender> = EnumSet.of(GENDERLESS)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.gender
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Class responsible for querying possible [Gender]s of [Species] and assigning them randomly to generated [Pokemon].
|
||||
*
|
||||
* @property maleRatio The raw ratio for the [Gender.MALE] despite the naming this is able to cover all possible genders.
|
||||
*
|
||||
* @see Species.genderSelector
|
||||
*
|
||||
* @throws IllegalArgumentException If male ratio is greater than 1.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class GenderSelector internal constructor(private val maleRatio: Float) {
|
||||
|
||||
init {
|
||||
if (this.maleRatio < 1F) {
|
||||
throw IllegalArgumentException("Male ratio cannot be greater than 1.0")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all the possible [Gender]s from [generate].
|
||||
*
|
||||
* @return The possible [Gender]s.
|
||||
*/
|
||||
fun possibleGenders(): Set<Gender> = if (this.maleRatio < 0F) Gender.NO_RATIO_GENDERS else Gender.RATIO_BASED_GENDERS
|
||||
|
||||
/**
|
||||
* Randomly picks a [Gender] using the [maleRatio].
|
||||
*
|
||||
* @return The generated [Gender].
|
||||
*/
|
||||
fun generate(): Gender = when {
|
||||
this.maleRatio < 0F -> Gender.GENDERLESS
|
||||
this.maleRatio == 1F || Random.nextFloat() < this.maleRatio -> Gender.MALE
|
||||
else -> Gender.FEMALE
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [gender] is a possible selection of [generate].
|
||||
*
|
||||
* @param gender The [Gender] being checked.
|
||||
* @return If the [gender] is possible with the context in this [GenderSelector].
|
||||
*/
|
||||
fun isValid(gender: Gender): Boolean = this.possibleGenders().contains(gender)
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for [GenderSelector].
|
||||
* This will (de)serialize from a primitive float.
|
||||
* It will error if the value is not between [Float.MIN_VALUE] and 1F.
|
||||
*/
|
||||
@JvmField
|
||||
val CODEC: Codec<GenderSelector> = Codec.floatRange(Float.MIN_VALUE, 1F).xmap(::GenderSelector, GenderSelector::maleRatio)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.species
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Additional data only present in species that are a variation of an existing species.
|
||||
* This is commonly referred to as a Pokémon form.
|
||||
* In the context of Cobblemon aspects are used when a form is purely cosmetic.
|
||||
* This is only present if a [Species] has actual stat related differences from the "base".
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Variant_Pok%C3%A9mon">Bulbapedias entry on variant Pokémon</a>
|
||||
*/
|
||||
class FormData internal constructor(
|
||||
private var baseSpeciesIdentifier: Identifier,
|
||||
private var battleOnly: Boolean
|
||||
) {
|
||||
|
||||
/**
|
||||
* Resolves the base species of this form.
|
||||
*
|
||||
* @return The [Species] that is the base of this form.
|
||||
*/
|
||||
fun baseSpecies(): Species = CobblemonRegistries.SPECIES.get(this.baseSpeciesIdentifier)!!
|
||||
|
||||
/**
|
||||
* Checks if this [FormData] can only exist in battles.
|
||||
*
|
||||
* @return True if this [FormData] can only exist in battles.
|
||||
*/
|
||||
fun isBattleOnly(): Boolean = this.battleOnly
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<FormData> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Identifier.CODEC.fieldOf("baseSpecies").forGetter(FormData::baseSpeciesIdentifier),
|
||||
Codec.BOOL.fieldOf("battleOnly").forGetter(FormData::battleOnly)
|
||||
).apply(builder, ::FormData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.species
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.GenderSelector
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
|
||||
import com.cobblemon.mod.common.api.pokemon.species.internal.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatMap
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryElement
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonBehaviour
|
||||
import com.cobblemon.mod.common.util.codec.ExtraCodecs
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.*
|
||||
|
||||
@Suppress("unused")
|
||||
class Species internal constructor(
|
||||
nationalPokedexNumber: Int,
|
||||
types: Pair<ElementalType, Optional<ElementalType>>,
|
||||
abilities: AbilityPool,
|
||||
baseStats: StatMap,
|
||||
catchRate: Int,
|
||||
genderSelector: GenderSelector,
|
||||
private val experienceData: ExperienceData,
|
||||
private val eggData: EggData,
|
||||
learnset: Learnset,
|
||||
private val behaviourData: BehaviourData,
|
||||
private val evolutionData: EvolutionData,
|
||||
baseFriendship: Int,
|
||||
evYield: StatMap,
|
||||
private val cosmeticData: CosmeticData,
|
||||
formData: Optional<FormData>
|
||||
): CobblemonRegistryElement<Species>, ShowdownIdentifiable {
|
||||
|
||||
companion object {
|
||||
|
||||
private val TYPES_CODEC = ExtraCodecs.ENTITY_DIMENSIONS
|
||||
|
||||
val codec = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("nationalPokedexNumber").forGetter(Species::nationalPokedexNumber),
|
||||
ExtraCodecs.DUAL_TYPE_CODEC.fieldOf("types").forGetter(Species::types),
|
||||
// ToDo: abilities
|
||||
StatMap.BASE_STATS_CODEC.fieldOf("baseStats").forGetter(Species::baseStats),
|
||||
Codec.INT.fieldOf("catchRate").forGetter(Species::catchRate),
|
||||
GenderSelector.CODEC.fieldOf("genderSelector").forGetter(Species::genderSelector),
|
||||
ExperienceData.MAP_CODEC.forGetter(Species::experienceData),
|
||||
EggData.MAP_CODEC.fieldOf("eggData").forGetter(Species::eggData),
|
||||
// ToDo: learnset
|
||||
BehaviourData.MAP_CODEC.forGetter(Species::behaviourData),
|
||||
EvolutionData.MAP_CODEC.forGetter(Species::evolutionData),
|
||||
Codec.INT.fieldOf("baseFriendship").forGetter(Species::baseFriendship),
|
||||
StatMap.BASE_STATS_CODEC.fieldOf("evYield").forGetter(Species::evYield),
|
||||
CosmeticData.MAP_CODEC.forGetter(Species::cosmeticData),
|
||||
FormData.CODEC.optionalFieldOf("formData").forGetter(Species::formData)
|
||||
).apply(builder, ::Species)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val displayName: MutableText by lazy { Text.translatable("${this.id().namespace}.species.${this.id().path.replace("/", ".")}.name") }
|
||||
|
||||
var nationalPokedexNumber: Int = nationalPokedexNumber
|
||||
private set
|
||||
|
||||
var types: Pair<ElementalType, Optional<ElementalType>> = types
|
||||
private set
|
||||
|
||||
val primaryType: ElementalType get() = this.types.first
|
||||
|
||||
val secondaryType: Optional<ElementalType> get() = this.types.second
|
||||
|
||||
var abilities: AbilityPool = abilities
|
||||
private set
|
||||
|
||||
var baseStats: StatMap = baseStats
|
||||
private set
|
||||
|
||||
var catchRate: Int = catchRate
|
||||
private set
|
||||
|
||||
/**
|
||||
* Responsible for picking a [Gender] for this [Species] on [create].
|
||||
*/
|
||||
var genderSelector: GenderSelector = genderSelector
|
||||
private set
|
||||
|
||||
val shoulderMountable: Boolean get() = this.behaviourData.shoulderMountable
|
||||
|
||||
val baseExperienceYield: Int get() = this.experienceData.baseExperienceYield
|
||||
|
||||
val experienceGroup: ExperienceGroup get() = this.experienceData.experienceGroup
|
||||
|
||||
val eggCycles: Int get() = this.eggData.eggCycles
|
||||
|
||||
val eggGroups: Set<EggGroup> get() = this.eggData.eggGroups
|
||||
|
||||
var learnset: Learnset = learnset
|
||||
private set
|
||||
|
||||
val behaviour: PokemonBehaviour get() = this.behaviourData.pokemonBehaviour
|
||||
|
||||
val evolutions: Set<Evolution> get() = this.evolutionData.evolutions
|
||||
|
||||
val preEvolution: Optional<PreEvolution> get() = this.evolutionData.preEvolution
|
||||
|
||||
val baseScale: Float get() = this.cosmeticData.baseScale
|
||||
|
||||
val hitbox: EntityDimensions get() = this.cosmeticData.hitbox
|
||||
|
||||
var baseFriendship: Int = baseFriendship
|
||||
private set
|
||||
|
||||
var evYield: StatMap = evYield
|
||||
private set
|
||||
|
||||
val weight: Float get() = this.cosmeticData.weight
|
||||
|
||||
val height: Float get() = this.cosmeticData.height
|
||||
|
||||
val aspects: Set<String> get() = this.cosmeticData.aspects
|
||||
|
||||
val features: Set<String> get() = this.behaviourData.features
|
||||
|
||||
val standingEyeHeight: Float get() = this.cosmeticData.standingEyeHeight
|
||||
|
||||
val swimmingEyeHeight: Float get() = this.cosmeticData.swimmingEyeHeight
|
||||
|
||||
val flyingEyeHeight: Float get() = this.cosmeticData.flyingEyeHeight
|
||||
|
||||
var formData: Optional<FormData> = formData
|
||||
private set
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param level
|
||||
* @return
|
||||
*/
|
||||
fun create(level: Int): Pokemon {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks a randomly generated [Gender] using the [genderSelector].
|
||||
*
|
||||
* @return The picked [Gender].
|
||||
*/
|
||||
fun pickGender(): Gender = this.genderSelector.generate()
|
||||
|
||||
/**
|
||||
* Checks if this [Species] can be of the given [gender].
|
||||
* This is checked against the [genderSelector].
|
||||
*
|
||||
* @param gender The [Gender] being checked.
|
||||
* @return If the given [gender] is possible for this [Species].
|
||||
*/
|
||||
fun canBeOfGender(gender: Gender): Boolean = this.genderSelector.isValid(gender)
|
||||
|
||||
override fun showdownId(): String {
|
||||
val id = this.id()
|
||||
val showdownId = ShowdownIdentifiable.REGEX.replace(id.path, "")
|
||||
if (id.namespace == Cobblemon.MODID) {
|
||||
return showdownId
|
||||
}
|
||||
return id.namespace + showdownId
|
||||
}
|
||||
|
||||
override fun id(): Identifier = this.registry().getId(this)!!
|
||||
|
||||
override fun registryEntry(): RegistryEntry<Species> = this.registry().getEntry(this)
|
||||
|
||||
override fun registry(): Registry<Species> = Cobblemon.implementation.getRegistry(CobblemonRegistryKeys.SPECIES)
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonBehaviour
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class BehaviourData(
|
||||
var pokemonBehaviour: PokemonBehaviour,
|
||||
var shoulderMountable: Boolean,
|
||||
var features: Set<String>,
|
||||
var dynamaxBlocked: Boolean,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<BehaviourData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
PokemonBehaviour.CODEC.fieldOf("pokemonBehaviour").forGetter(BehaviourData::pokemonBehaviour),
|
||||
Codec.BOOL.fieldOf("shoulderMountable").forGetter(BehaviourData::shoulderMountable),
|
||||
setCodec(Codec.STRING).fieldOf("features").forGetter(BehaviourData::features),
|
||||
Codec.BOOL.optionalFieldOf("dynamaxBlocked", false).forGetter(BehaviourData::dynamaxBlocked)
|
||||
).apply(builder, ::BehaviourData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<BehaviourData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.ExtraCodecs
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class CosmeticData(
|
||||
var baseScale: Float,
|
||||
var hitbox: EntityDimensions,
|
||||
var weight: Float,
|
||||
var height: Float,
|
||||
var aspects: Set<String>,
|
||||
var standingEyeHeight: Float,
|
||||
var swimmingEyeHeight: Float,
|
||||
var flyingEyeHeight: Float,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<CosmeticData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.FLOAT.fieldOf("baseScale").forGetter(CosmeticData::baseScale),
|
||||
ExtraCodecs.ENTITY_DIMENSIONS.fieldOf("hitbox").forGetter(CosmeticData::hitbox),
|
||||
Codec.FLOAT.fieldOf("weight").forGetter(CosmeticData::weight),
|
||||
Codec.FLOAT.fieldOf("height").forGetter(CosmeticData::height),
|
||||
setCodec(Codec.STRING).fieldOf("aspects").forGetter(CosmeticData::aspects),
|
||||
Codec.FLOAT.optionalFieldOf("standingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::standingEyeHeight),
|
||||
Codec.FLOAT.optionalFieldOf("swimmingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::swimmingEyeHeight),
|
||||
Codec.FLOAT.optionalFieldOf("flyingEyeHeight", VANILLA_DEFAULT_EYE_HEIGHT).forGetter(CosmeticData::flyingEyeHeight),
|
||||
).apply(builder, ::CosmeticData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<CosmeticData> = MAP_CODEC.codec()
|
||||
|
||||
private const val VANILLA_DEFAULT_EYE_HEIGHT = 0.85F
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class EggData(
|
||||
var eggCycles: Int,
|
||||
var eggGroups: EnumSet<EggGroup>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<EggData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("eggCycles").forGetter(EggData::eggCycles),
|
||||
setCodec(EggGroup.CODEC).fieldOf("eggGroups").xmap({ set -> EnumSet.copyOf(set) }, { enumSet -> enumSet }).forGetter { eggData -> eggData.eggGroups }
|
||||
).apply(builder, ::EggData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<EggData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class EvolutionData(
|
||||
var evolutions: Set<Evolution>,
|
||||
var preEvolution: Optional<PreEvolution>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<EvolutionData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
setCodec(EvolutionRegistry.EVOLUTION_CODEC).optionalFieldOf("evolutions", emptySet()).forGetter(EvolutionData::evolutions),
|
||||
PreEvolution.CODEC.optionalFieldOf("preEvolution").forGetter(EvolutionData::preEvolution)
|
||||
).apply(builder, ::EvolutionData)
|
||||
}
|
||||
|
||||
val CODEC: Codec<EvolutionData> = MAP_CODEC.codec()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.species.internal
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* Intermediate for [Species] data.
|
||||
*/
|
||||
internal data class ExperienceData(
|
||||
var baseExperienceYield: Int,
|
||||
var experienceGroup: ExperienceGroup
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val MAP_CODEC: MapCodec<ExperienceData> = RecordCodecBuilder.mapCodec { builder ->
|
||||
builder.group(
|
||||
Codec.INT.fieldOf("baseExperienceYield").forGetter(ExperienceData::baseExperienceYield),
|
||||
ExperienceGroup.CODEC.fieldOf("experienceGroup").forGetter(ExperienceData::experienceGroup),
|
||||
).apply(builder, ::ExperienceData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.stats
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* An implementation of [StatMap] aimed solely at the EV data structure.
|
||||
* This exists due to a few extra constraints present in EVs regarding the total value of the structure.
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">Effort values Bulbapedia entry</a>
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class EvMap internal constructor(stats: HashMap<Stat, Int>) : StatMap(Variant.EV, stats) {
|
||||
|
||||
init {
|
||||
if (this.values.sum() > MAX_TOTAL) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} with values total exceeding $MAX_TOTAL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits the logic of [StatMap.validateValue].
|
||||
* This has the added constraint of the maximum possible total value being [MAX_TOTAL].
|
||||
*
|
||||
* @see StatMap.validateValue
|
||||
*/
|
||||
override fun validateValue(key: Stat, value: Int) {
|
||||
super.validateValue(key, value)
|
||||
val existing = this[key]
|
||||
val current = this.values.sum() - existing
|
||||
if (current + value > MAX_TOTAL) {
|
||||
throw IllegalArgumentException("The total of the values of an ${this::class.simpleName} cannot exceed $MAX_TOTAL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being added to.
|
||||
* @param amount The amount being added. This value will be sanitized with [Int.absoluteValue].
|
||||
* @param coerceSafe Should the value be coerced to be safe to add?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see subtract
|
||||
* @see mutate
|
||||
*/
|
||||
fun add(stat: Stat, amount: Int, coerceSafe: Boolean): Int = this.mutate(stat, amount.absoluteValue, coerceSafe)
|
||||
|
||||
/**
|
||||
* Subtracts from the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being subtracted from.
|
||||
* @param amount The amount being subtracted. This value will be sanitized with [Int.absoluteValue].
|
||||
* @param coerceSafe Should the value be coerced to be safe to subtract?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see add
|
||||
* @see mutate
|
||||
*/
|
||||
fun subtract(stat: Stat, amount: Int, coerceSafe: Boolean): Int = this.mutate(stat, amount.absoluteValue, coerceSafe)
|
||||
|
||||
/**
|
||||
* Mutates the given [stat].
|
||||
*
|
||||
* @param stat The [Stat] being mutated.
|
||||
* @param amount The amount being used in the mutation operation.
|
||||
* @param coerceSafe Should the value be coerced to be safe to operate with?
|
||||
* @return The new resulting value of [stat].
|
||||
*
|
||||
* @throws IllegalArgumentException if [validateValue] fails.
|
||||
*
|
||||
* @see add
|
||||
* @see subtract
|
||||
*/
|
||||
fun mutate(stat: Stat, amount: Int, coerceSafe: Boolean): Int {
|
||||
var result = this[stat] + amount
|
||||
if (coerceSafe) {
|
||||
result = result.coerceIn(this.variant.minValue, min(this.variant.maxValue, this.remaining()))
|
||||
}
|
||||
this.put(stat, result)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves how many EVs can still be allocated to this structure.
|
||||
*
|
||||
* @return How many EVs can still be allocated.
|
||||
*/
|
||||
fun remaining(): Int = MAX_TOTAL - this.values.sum()
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for a [EvMap].
|
||||
*/
|
||||
@JvmField
|
||||
val EV_STATS_CODEC: Codec<EvMap> = Codec.unboundedMap(Stat.CODEC, Codec.intRange(Variant.EV.minValue, Variant.EV.maxValue))
|
||||
.xmap({ map -> EvMap(HashMap(map)) }, { evMap -> evMap })
|
||||
|
||||
/**
|
||||
* The maximum total EV values.
|
||||
*/
|
||||
const val MAX_TOTAL = 510
|
||||
|
||||
/**
|
||||
* Creates a [EvMap] with the given params.
|
||||
*
|
||||
* @param map The base map to take values from.
|
||||
* @return The generated [EvMap].
|
||||
*
|
||||
* @throws IllegalArgumentException If the constraints seen in [StatMap.create] are not fulfilled or if the total of the values exceeds [MAX_TOTAL].
|
||||
*/
|
||||
fun create(map: Map<Stat, Int>): EvMap = EvMap(HashMap(map))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -61,4 +63,10 @@ interface Stat {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<Stat> = Identifier.CODEC.xmap(Cobblemon.statProvider::fromIdentifierOrThrow, Stat::identifier)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* 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.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.serialization.BufferSerializer
|
||||
import com.cobblemon.mod.common.api.serialization.DataSerializer
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.JsonOps
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import kotlin.jvm.optionals.getOrDefault
|
||||
|
||||
/**
|
||||
* Represents a map-like structure that is used solely for the purpose of various stat-like Pokémon data structures.
|
||||
*
|
||||
* @property variant The [Variant] of this map.
|
||||
* @property stats The base map used for this map.
|
||||
*
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Base_stats">Base stats Bulbapedia entry</a>
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Effort_values">Effort values Bulbapedia entry</a>
|
||||
* @see <a href="https://bulbapedia.bulbagarden.net/wiki/Individual_values">Individual values Bulbapedia entry</a>
|
||||
*
|
||||
*/
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
open class StatMap internal constructor(
|
||||
val variant: Variant,
|
||||
protected val stats: HashMap<Stat, Int>
|
||||
) : Map<Stat, Int>, DataSerializer<NbtCompound, JsonObject>, BufferSerializer {
|
||||
|
||||
init {
|
||||
if (!Cobblemon.statProvider.ofType(Stat.Type.PERMANENT).all(this.stats::containsKey)) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} without all ${Stat.Type.PERMANENT.name} ${Stat::class.simpleName}")
|
||||
}
|
||||
if (!this.stats.values.any { value -> this.variant.fits(value) }) {
|
||||
throw IllegalArgumentException("Cannot instance ${this::class.simpleName} with values not in range [${this.variant.minValue}-${this.variant.maxValue}]")
|
||||
}
|
||||
}
|
||||
|
||||
override val entries: Set<Map.Entry<Stat, Int>>
|
||||
get() = this.stats.entries
|
||||
override val keys: Set<Stat>
|
||||
get() = this.stats.keys
|
||||
override val size: Int
|
||||
get() = this.stats.size
|
||||
override val values: Collection<Int>
|
||||
get() = this.stats.values
|
||||
|
||||
/**
|
||||
* A constraint of implementing [Map].
|
||||
* This is impossible to be false.
|
||||
*
|
||||
* @return Always true.
|
||||
*/
|
||||
override fun isEmpty(): Boolean = false
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given [key].
|
||||
* Due to implementation details unlike a typical [Map.get] this will never return null.
|
||||
*
|
||||
* @param key The [Stat] being checked.
|
||||
* @return The value attached to the [key].
|
||||
*/
|
||||
override fun get(key: Stat): Int = this.stats[key]!!
|
||||
|
||||
override fun containsValue(value: Int): Boolean = this.stats.containsValue(value)
|
||||
|
||||
override fun containsKey(key: Stat): Boolean = this.stats.containsKey(key)
|
||||
|
||||
override fun loadFromNBT(nbt: NbtCompound) {
|
||||
this.codec().decode(NbtOps.INSTANCE, nbt)
|
||||
.result()
|
||||
.ifPresent { pair -> this.putAll(pair.first) }
|
||||
}
|
||||
|
||||
override fun saveToNBT(): NbtCompound {
|
||||
val result = this.codec().encodeStart(NbtOps.INSTANCE, this)
|
||||
.result()
|
||||
.getOrDefault(NbtCompound())
|
||||
// It's safe to cast it will always result in a NbtCompound
|
||||
return result as NbtCompound
|
||||
}
|
||||
|
||||
override fun loadFromJson(json: JsonObject) {
|
||||
this.codec().decode(JsonOps.INSTANCE, json)
|
||||
.result()
|
||||
.ifPresent { pair -> this.putAll(pair.first) }
|
||||
}
|
||||
|
||||
override fun saveToJson(): JsonObject {
|
||||
val result = this.codec().encodeStart(JsonOps.INSTANCE, this)
|
||||
.result()
|
||||
.getOrDefault(JsonObject())
|
||||
// It's safe to cast it will always result in a JsonObject
|
||||
return result as JsonObject
|
||||
}
|
||||
|
||||
override fun saveToBuffer(buffer: PacketByteBuf, toClient: Boolean) {
|
||||
buffer.writeMap(this.stats, { pb, stat -> pb.writeIdentifier(stat.identifier) }, PacketByteBuf::writeInt)
|
||||
}
|
||||
|
||||
override fun loadFromBuffer(buffer: PacketByteBuf) {
|
||||
// This is safe to do as the server will have sanitized the values.
|
||||
this.stats.clear()
|
||||
this.stats.putAll(buffer.readMap({ pb -> Cobblemon.statProvider.decode(pb) }, PacketByteBuf::readInt))
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the value for the given [key] to the [Variant.minValue] of [variant].
|
||||
*
|
||||
* @param key The [Stat] being reset.
|
||||
* @return The previous attached value.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [key] fails [validateKey].
|
||||
*/
|
||||
fun reset(key: Stat): Int {
|
||||
this.validateKey(key)
|
||||
val existing = this.stats[key]!!
|
||||
this.stats[key] = this.variant.minValue
|
||||
return existing
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all values of this map to the [Variant.minValue] of [variant].
|
||||
*/
|
||||
fun reset() {
|
||||
Cobblemon.statProvider.ofType(Stat.Type.PERMANENT).forEach(this::reset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges key-value pairs from a map into this [StatMap].
|
||||
*
|
||||
* @param from The map being merged.
|
||||
*
|
||||
* @throws IllegalArgumentException If any value of [from] fails [validateValue].
|
||||
*/
|
||||
fun putAll(from: Map<out Stat, Int>) {
|
||||
from.forEach(this::put)
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given [value] on the given [key] [Stat] of this [StatMap].
|
||||
*
|
||||
* @param key The [Stat] being set.
|
||||
* @param value The value being set to the [key].
|
||||
* @return The previously attached value.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [value] fails [validateValue].
|
||||
*/
|
||||
fun put(key: Stat, value: Int): Int {
|
||||
this.validateValue(key, value)
|
||||
val existing = this.stats[key]!!
|
||||
this.stats[key] = value
|
||||
return existing
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the [Codec] for this instance.
|
||||
* This is done based on the [variant].
|
||||
*
|
||||
* @return The [Codec] for this specific [StatMap] setup.
|
||||
*
|
||||
* @see StatMap.BASE_STATS_CODEC
|
||||
* @see StatMap.EV_STATS_CODEC
|
||||
* @see StatMap.IV_STATS_CODEC
|
||||
*/
|
||||
fun codec(): Codec<StatMap> = when (this.variant) {
|
||||
Variant.BASE_STATS -> BASE_STATS_CODEC
|
||||
Variant.IV -> IV_STATS_CODEC
|
||||
Variant.EV -> EV_STATS_CODEC
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a [Stat.Type] is [Stat.Type.PERMANENT].
|
||||
*
|
||||
* @param stat The [Stat] being checked.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [Stat.Type] is not [Stat.Type.PERMANENT].
|
||||
*/
|
||||
protected open fun validateKey(stat: Stat) {
|
||||
if (stat.type != Stat.Type.PERMANENT) {
|
||||
throw IllegalArgumentException("Unsupported stat type of ${stat.type.name} for ${stat.identifier}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is possible for this map.
|
||||
*
|
||||
* @param key The key having the [value] assigned.
|
||||
* @param value The value being assigned.
|
||||
*
|
||||
* @throws IllegalArgumentException If the [value] doesn't fulfill [Variant.fits] of the [variant].
|
||||
*/
|
||||
protected open fun validateValue(key: Stat, value: Int) {
|
||||
if (!this.variant.fits(value)) {
|
||||
throw IllegalArgumentException("Cannot accept $value, a value must be in range [${this.variant.minValue}-${this.variant.maxValue}]")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a type of data collected inside [StatMap].
|
||||
*
|
||||
* @property minValue The minimum possible value for a value of a [StatMap].
|
||||
* @property maxValue The maximum possible value for a value of a [StatMap].
|
||||
*/
|
||||
enum class Variant(val minValue: Int, val maxValue: Int) {
|
||||
|
||||
/**
|
||||
* Used to represent [base stats](https://bulbapedia.bulbagarden.net/wiki/Base_stats).
|
||||
*/
|
||||
BASE_STATS(1, Int.MAX_VALUE),
|
||||
|
||||
/**
|
||||
* Used to represent [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values).
|
||||
*/
|
||||
EV(0, EVs.MAX_STAT_VALUE),
|
||||
|
||||
/**
|
||||
* Used to represent [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values).
|
||||
*/
|
||||
IV(0, IVs.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* Checks if the given [value] fits within the range created by [minValue] & [maxValue].
|
||||
*
|
||||
* @param value The value being checked.
|
||||
* @return If the value can fit in this variant.
|
||||
*/
|
||||
fun fits(value: Int): Boolean = value >= this.minValue && value <= this.maxValue
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.BASE_STATS] variant.
|
||||
*/
|
||||
@JvmField
|
||||
val BASE_STATS_CODEC: Codec<StatMap> = this.createCodec(Variant.BASE_STATS)
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.EV] variant.
|
||||
* For the [EvMap] typed Codec see [EvMap.EV_STATS_CODEC].
|
||||
* The result as far as instance types go is the same this is just a constraint of [Codec].
|
||||
*
|
||||
* @see EvMap.EV_STATS_CODEC
|
||||
*/
|
||||
@JvmField
|
||||
val EV_STATS_CODEC: Codec<StatMap> = EvMap.EV_STATS_CODEC.xmap({ evMap -> this.create(Variant.EV, evMap) }, EvMap::create)
|
||||
|
||||
/**
|
||||
* A [Codec] for a [StatMap] of the [Variant.IV] variant.
|
||||
*/
|
||||
@JvmField
|
||||
val IV_STATS_CODEC: Codec<StatMap> = this.createCodec(Variant.IV)
|
||||
|
||||
/**
|
||||
* Creates a [StatMap] with the given params.
|
||||
*
|
||||
* @param variant The [StatMap] [Variant].
|
||||
* @param map The base map to take values from.
|
||||
* @return The generated [StatMap].
|
||||
*
|
||||
* @throws IllegalArgumentException If map doesn't contain every possible key with type [Stat.Type.PERMANENT] or if any value doesn't respect [Variant.fits] for the given [variant].
|
||||
*/
|
||||
fun create(variant: Variant, map: Map<Stat, Int>): StatMap = when (variant) {
|
||||
Variant.BASE_STATS -> StatMap(variant, HashMap(map))
|
||||
Variant.EV -> EvMap(HashMap(map))
|
||||
Variant.IV -> StatMap(variant, HashMap(map))
|
||||
}
|
||||
|
||||
private fun createCodec(variant: Variant): Codec<StatMap> = Codec.unboundedMap(Stat.CODEC, Codec.intRange(variant.minValue, variant.maxValue))
|
||||
.xmap({ map -> StatMap(variant, HashMap(map)) }, { statMap -> statMap })
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,11 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.registry
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
|
||||
object CobblemonRegistries {
|
||||
|
||||
val ELEMENTAL_TYPE: Registry<ElementalType> get() = this.get(CobblemonRegistryKeys.ELEMENTAL_TYPE)
|
||||
|
||||
val SPECIES: Registry<Species> get() = this.get(CobblemonRegistryKeys.SPECIES)
|
||||
|
||||
private fun <T> get(key: RegistryKey<Registry<T>>): Registry<T> = Cobblemon.implementation.getRegistry(key)
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.registry
|
||||
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
interface CobblemonRegistryElement<T : CobblemonRegistryElement<T>> {
|
||||
|
||||
fun isIn(tag: TagKey<T>): Boolean = this.registryEntry().isIn(tag)
|
||||
|
||||
fun id(): Identifier
|
||||
|
||||
fun registryEntry(): RegistryEntry<T>
|
||||
|
||||
fun registry(): Registry<T>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.registry
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.pokemon.species.Species
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
|
||||
/**
|
||||
* Contains the various [RegistryKey]s for Cobblemon.
|
||||
*/
|
||||
object CobblemonRegistryKeys {
|
||||
|
||||
val ELEMENTAL_TYPE: RegistryKey<Registry<ElementalType>> = this.create("elemental_types")
|
||||
|
||||
val SPECIES: RegistryKey<Registry<Species>> = this.create("species")
|
||||
|
||||
private fun <T> create(key: String): RegistryKey<Registry<T>> = RegistryKey.ofRegistry(cobblemonResource(key))
|
||||
|
||||
}
|
||||
@@ -19,12 +19,15 @@ import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
|
||||
import com.cobblemon.mod.common.api.spawning.preset.SpawnDetailPreset
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.resource.ResourceType
|
||||
@@ -48,9 +51,9 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, RegistryLikeCondition.createCodec { Registries.FLUID }.toTypeAdapter())
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
Either::class.java,
|
||||
|
||||
@@ -17,12 +17,15 @@ import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PossibleHeldItem
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.codec.toTypeAdapter
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -41,9 +44,9 @@ object SpawnLoader {
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping()
|
||||
.setLenient()
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, RegistryLikeCondition.createCodec { server()!!.registryManager.get(RegistryKeys.BIOME) }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, RegistryLikeCondition.createCodec { Registries.BLOCK }.toTypeAdapter())
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, RegistryLikeCondition.createCodec { Registries.FLUID }.toTypeAdapter())
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
Either::class.java,
|
||||
|
||||
@@ -10,6 +10,8 @@ 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.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
|
||||
/**
|
||||
* A range of time ticks for a world mainly to be used in [SpawningCondition]s. A time range
|
||||
@@ -41,6 +43,12 @@ class TimeRange : IntRanges {
|
||||
"morning" to TimeRange(0..4999),
|
||||
"afternoon" to TimeRange(7000..12039)
|
||||
)
|
||||
|
||||
val CODEC: Codec<TimeRange> = Codec.STRING.flatXmap(
|
||||
{ string -> timeRanges[string]?.let { DataResult.success(it) } ?: DataResult.error { "Can't find a time range with ID $string" } },
|
||||
{ timeRange -> timeRanges.entries.firstOrNull { (_, range) -> range == timeRange }?.let { DataResult.success(it.key) } ?: DataResult.error { "Couldn't resolve a time range ID for $timeRange" } }
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
@@ -17,7 +18,7 @@ import net.minecraft.world.World
|
||||
* @author Licious
|
||||
* @since January 25th, 2023
|
||||
*/
|
||||
enum class MoonPhase {
|
||||
enum class MoonPhase : StringIdentifiable {
|
||||
|
||||
FULL_MOON,
|
||||
WANING_GIBBOUS,
|
||||
@@ -28,6 +29,8 @@ enum class MoonPhase {
|
||||
FIRST_QUARTER,
|
||||
WAXING_GIBBOUS;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
private val VALUES = values()
|
||||
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ class PokemonSpawnDetail : SpawnDetail() {
|
||||
val species = PokemonSpecies.getByIdentifier(pokemon.species!!.asIdentifierDefaultingNamespace())
|
||||
if (species != null) {
|
||||
labels.addAll(
|
||||
species.secondaryType?.let { listOf(species.primaryType.name.lowercase(), it.name.lowercase()) }
|
||||
?: listOf(species.primaryType.name.lowercase())
|
||||
species.secondaryType?.let { listOf(species.primaryType.id().toString(), it.id().toString()) }
|
||||
?: listOf(species.primaryType.id().toString())
|
||||
)
|
||||
|
||||
if (height == -1) {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.api.storage.StorePosition
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import java.nio.file.Path
|
||||
|
||||
+8
-7
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@Suppress("unused")
|
||||
class PlayerAdvancementData {
|
||||
|
||||
var totalCaptureCount: Int = 0
|
||||
@@ -35,7 +36,7 @@ class PlayerAdvancementData {
|
||||
var totalTradedCount: Int = 0
|
||||
private set
|
||||
|
||||
private var totalTypeCaptureCounts = mutableMapOf<String, Int>()
|
||||
private var totalTypeCaptureCounts = mutableMapOf<Identifier, Int>()
|
||||
private var totalDefeatedCounts = mutableMapOf<Identifier, Int>()
|
||||
var aspectsCollected = mutableMapOf<Identifier, MutableSet<String>>()
|
||||
private set
|
||||
@@ -77,18 +78,18 @@ class PlayerAdvancementData {
|
||||
}
|
||||
|
||||
fun getTotalTypeCaptureCount(type: ElementalType): Int {
|
||||
if (!totalTypeCaptureCounts.containsKey(key = type.name)) {
|
||||
totalTypeCaptureCounts[type.name] = 0
|
||||
if (!totalTypeCaptureCounts.containsKey(type.id())) {
|
||||
totalTypeCaptureCounts[type.id()] = 0
|
||||
}
|
||||
return totalTypeCaptureCounts.get(key = type.name) ?: 0
|
||||
return totalTypeCaptureCounts[type.id()] ?: 0
|
||||
}
|
||||
|
||||
fun updateTotalTypeCaptureCount(type: ElementalType) {
|
||||
val count = totalTypeCaptureCounts[type.name] ?: 0
|
||||
val count = totalTypeCaptureCounts[type.id()] ?: 0
|
||||
if (count == 0) {
|
||||
totalTypeCaptureCounts[type.name] = 1
|
||||
totalTypeCaptureCounts[type.id()] = 1
|
||||
} else {
|
||||
totalTypeCaptureCounts.replace(type.name, count + 1)
|
||||
totalTypeCaptureCounts.replace(type.id(), count + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.types
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
|
||||
/**
|
||||
* Contains all the Cobblemon default elemental type related tags.
|
||||
*/
|
||||
object CobblemonElementalTypeTags {
|
||||
|
||||
val FIRE_IMMUNE: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("fire_immune"))
|
||||
|
||||
val FALL_DAMAGE_IMMUNE: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("fall_damage_immune"))
|
||||
|
||||
val LURE_BALL_BOOSTING: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("lure_ball_boosting"))
|
||||
|
||||
val NET_BALL_BOOSTING: TagKey<ElementalType> = TagKey.of(CobblemonRegistryKeys.ELEMENTAL_TYPE, cobblemonResource("net_ball_boosting"))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.types
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* The official [ElementalType]s and the ones the Cobblemon mod ships with.
|
||||
* These are not guaranteed to be present in a game instance as we can't control what datapacks may remove them.
|
||||
* It's also not safe to assume they function the exact same as they would in the official games, please check the various properties of [ElementalType].
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
object CobblemonElementalTypes {
|
||||
|
||||
val BUG_KEY: Identifier = cobblemonResource("bug")
|
||||
val BUG: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(BUG_KEY))
|
||||
|
||||
val DARK_KEY: Identifier = cobblemonResource("dark")
|
||||
val DARK: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(DARK_KEY))
|
||||
|
||||
val DRAGON_KEY: Identifier = cobblemonResource("dragon")
|
||||
val DRAGON: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(DRAGON_KEY))
|
||||
|
||||
val ELECTRIC_KEY: Identifier = cobblemonResource("electric")
|
||||
val ELECTRIC: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ELECTRIC_KEY))
|
||||
|
||||
val FAIRY_KEY: Identifier = cobblemonResource("fairy")
|
||||
val FAIRY: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FAIRY_KEY))
|
||||
|
||||
val FIGHTING_KEY: Identifier = cobblemonResource("fighting")
|
||||
val FIGHTING: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FIGHTING_KEY))
|
||||
|
||||
val FIRE_KEY: Identifier = cobblemonResource("fire")
|
||||
val FIRE: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FIRE_KEY))
|
||||
|
||||
val FLYING_KEY: Identifier = cobblemonResource("flying")
|
||||
val FLYING: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(FLYING_KEY))
|
||||
|
||||
val GHOST_KEY: Identifier = cobblemonResource("ghost")
|
||||
val GHOST: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GHOST_KEY))
|
||||
|
||||
val GRASS_KEY: Identifier = cobblemonResource("grass")
|
||||
val GRASS: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GRASS_KEY))
|
||||
|
||||
val GROUND_KEY: Identifier = cobblemonResource("ground")
|
||||
val GROUND: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(GROUND_KEY))
|
||||
|
||||
val ICE_KEY: Identifier = cobblemonResource("ice")
|
||||
val ICE: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ICE_KEY))
|
||||
|
||||
val NORMAL_KEY: Identifier = cobblemonResource("normal")
|
||||
val NORMAL: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(NORMAL_KEY))
|
||||
|
||||
val POISON_KEY: Identifier = cobblemonResource("poison")
|
||||
val POISON: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(POISON_KEY))
|
||||
|
||||
val PSYCHIC_KEY: Identifier = cobblemonResource("psychic")
|
||||
val PSYCHIC: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(PSYCHIC_KEY))
|
||||
|
||||
val ROCK_KEY: Identifier = cobblemonResource("rock")
|
||||
val ROCK: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(ROCK_KEY))
|
||||
|
||||
val STEEL_KEY: Identifier = cobblemonResource("steel")
|
||||
val STEEL: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(STEEL_KEY))
|
||||
|
||||
val WATER_KEY: Identifier = cobblemonResource("water")
|
||||
val WATER: Optional<ElementalType> get() = Optional.ofNullable(CobblemonRegistries.ELEMENTAL_TYPE.get(WATER_KEY))
|
||||
|
||||
}
|
||||
@@ -9,21 +9,119 @@
|
||||
package com.cobblemon.mod.common.api.types
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistryElement
|
||||
import com.cobblemon.mod.common.api.types.client.ClientData
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.HiddenPowerRequirement
|
||||
import com.cobblemon.mod.common.api.types.resistance.*
|
||||
import com.cobblemon.mod.common.util.codec.setCodec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* Class representing a type of a Pokemon or Move
|
||||
* Class representing the elemental type of Pokémon or Move.
|
||||
*
|
||||
* @param name: The English name used to load / find it (spaces -> _)
|
||||
* @param displayName: A Component used to display the name, normally a TranslatableText
|
||||
* @param textureXMultiplier: The multiplier by which the TypeWidget shall move the display
|
||||
* @param resourceLocation: The location of the resource used in the TypeWidget
|
||||
* @param damageTaken The [RawResistanceInformation] that will be converted into [ResistanceInformation] for this type.
|
||||
* @param hiddenPowerRequirement The [HiddenPowerRequirement] for this elemental type. If not present that means the type doesn't support hidden power.
|
||||
* @param clientData The [ClientData] of this type.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
class ElementalType(
|
||||
val name: String,
|
||||
val displayName: MutableText,
|
||||
val hue: Int,
|
||||
val textureXMultiplier: Int,
|
||||
val resourceLocation: Identifier = Identifier(Cobblemon.MODID, "ui/types.png")
|
||||
)
|
||||
private val damageTaken: Set<RawResistanceInformation>,
|
||||
val hiddenPowerRequirement: Optional<HiddenPowerRequirement>,
|
||||
val clientData: ClientData
|
||||
): CobblemonRegistryElement<ElementalType>, ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The translatable component responsible for showing this
|
||||
*/
|
||||
val displayName: MutableText by lazy { Text.translatable("${this.id().namespace}.type.${this.id().path.replace("/", ".")}") }
|
||||
|
||||
/**
|
||||
* The resolved [ResistanceInformation]s.
|
||||
* This is done by lazily invoking [RawResistanceInformation.toImplementation].
|
||||
*/
|
||||
private val resistanceInformation: HashSet<ResistanceInformation> by lazy {
|
||||
val resulting = this.damageTaken.map(RawResistanceInformation::toImplementation).toHashSet()
|
||||
this.populateMissingTypes(resulting)
|
||||
return@lazy resulting
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
fun resistanceInformation(): Set<ResistanceInformation> = this.resistanceInformation
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
fun resistanceAgainst(other: ElementalType): Resistance {
|
||||
return this.resistanceInformation().firstOrNull { it is ElementalTypeResistanceInformation && it.elementalType == other }?.resistance
|
||||
?: throw IllegalArgumentException("Cannot find type resistance for ${other.id()} this should be impossible.")
|
||||
}
|
||||
|
||||
override fun registryEntry(): RegistryEntry<ElementalType> = this.registry().getEntry(this)
|
||||
|
||||
override fun id(): Identifier = this.registry().getId(this)!!
|
||||
|
||||
override fun registry(): Registry<ElementalType> = CobblemonRegistries.ELEMENTAL_TYPE
|
||||
|
||||
override fun showdownId(): String {
|
||||
val showdownId = ShowdownIdentifiable.REGEX.replace(this.id().path.lowercase(), "")
|
||||
if (this.id().namespace == Cobblemon.MODID) {
|
||||
return showdownId
|
||||
}
|
||||
return this.id().namespace + showdownId
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean = other is ElementalType && other.id() == this.id()
|
||||
|
||||
override fun hashCode(): Int = this.id().hashCode()
|
||||
|
||||
/**
|
||||
* Adds in any missing [ResistanceInformation] for other loaded [ElementalType]s.
|
||||
*
|
||||
* @param current The currently loaded [ResistanceInformation].
|
||||
*/
|
||||
private fun populateMissingTypes(current: HashSet<ResistanceInformation>) {
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
if (current.none { it is ElementalTypeResistanceInformation && it.elementalType == type }) {
|
||||
val information = ElementalTypeResistanceInformation(type, Resistance.NEUTRAL)
|
||||
current.add(information)
|
||||
Cobblemon.LOGGER.info("{} elemental type was missing resistance information against {}, defaulting to neutral, it is recommended to validate if this is intended or if you should add additional data for the missing type", this.id(), type.id())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ElementalType> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
setCodec(RawResistanceInformation.CODEC).fieldOf("damageTaken").forGetter(ElementalType::damageTaken),
|
||||
HiddenPowerRequirement.CODEC.optionalFieldOf("hiddenPowerRequirement").forGetter(ElementalType::hiddenPowerRequirement),
|
||||
ClientData.CODEC.fieldOf("clientData").forGetter(ElementalType::clientData)
|
||||
).apply(builder, ::ElementalType)
|
||||
}
|
||||
|
||||
val NETWORK_CODEC: Codec<ElementalType> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
setCodec(RawResistanceInformation.CODEC).fieldOf("damageTaken").forGetter(ElementalType::damageTaken),
|
||||
ClientData.CODEC.fieldOf("clientData").forGetter(ElementalType::clientData)
|
||||
).apply(builder) { damageTaken, clientData -> ElementalType(damageTaken, Optional.empty(), clientData) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,169 +6,3 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types
|
||||
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Registry for all known ElementalTypes
|
||||
*/
|
||||
object ElementalTypes {
|
||||
|
||||
private val allTypes = mutableListOf<ElementalType>()
|
||||
|
||||
val NORMAL = register(
|
||||
name = "normal",
|
||||
displayName = Text.translatable("cobblemon.type.normal"),
|
||||
hue = 0xDDDDCF,
|
||||
textureXMultiplier = 0
|
||||
)
|
||||
|
||||
val FIRE = register(
|
||||
name = "fire",
|
||||
displayName = Text.translatable("cobblemon.type.fire"),
|
||||
hue = 0xE55C32,
|
||||
textureXMultiplier = 1
|
||||
)
|
||||
|
||||
val WATER = register(
|
||||
name = "water",
|
||||
displayName = Text.translatable("cobblemon.type.water"),
|
||||
hue = 0x4A9BE8,
|
||||
textureXMultiplier = 2
|
||||
)
|
||||
|
||||
val GRASS = register(
|
||||
name = "grass",
|
||||
displayName = Text.translatable("cobblemon.type.grass"),
|
||||
hue = 0x4DBC3C,
|
||||
textureXMultiplier = 3
|
||||
)
|
||||
|
||||
val ELECTRIC = register(
|
||||
name = "electric",
|
||||
displayName = Text.translatable("cobblemon.type.electric"),
|
||||
hue = 0xEFD128,
|
||||
textureXMultiplier = 4
|
||||
)
|
||||
|
||||
val ICE = register(
|
||||
name = "ice",
|
||||
displayName = Text.translatable("cobblemon.type.ice"),
|
||||
hue = 0x6BC3EF,
|
||||
textureXMultiplier = 5
|
||||
)
|
||||
|
||||
val FIGHTING = register(
|
||||
name = "fighting",
|
||||
displayName = Text.translatable("cobblemon.type.fighting"),
|
||||
hue = 0xC44C5C,
|
||||
textureXMultiplier = 6
|
||||
)
|
||||
|
||||
val POISON = register(
|
||||
name = "poison",
|
||||
displayName = Text.translatable("cobblemon.type.poison"),
|
||||
hue = 0xA24BD8,
|
||||
textureXMultiplier = 7
|
||||
)
|
||||
|
||||
val GROUND = register(
|
||||
name = "ground",
|
||||
displayName = Text.translatable("cobblemon.type.ground"),
|
||||
hue = 0xD89950,
|
||||
textureXMultiplier = 8
|
||||
)
|
||||
|
||||
val FLYING = register(
|
||||
name = "flying",
|
||||
displayName = Text.translatable("cobblemon.type.flying"),
|
||||
hue = 0xBCC1FF,
|
||||
textureXMultiplier = 9
|
||||
)
|
||||
|
||||
val PSYCHIC = register(
|
||||
name = "psychic",
|
||||
displayName = Text.translatable("cobblemon.type.psychic"),
|
||||
hue = 0xD86AD6,
|
||||
textureXMultiplier = 10
|
||||
)
|
||||
|
||||
val BUG = register(
|
||||
name = "bug",
|
||||
displayName = Text.translatable("cobblemon.type.bug"),
|
||||
hue = 0xA2C831,
|
||||
textureXMultiplier = 11
|
||||
)
|
||||
|
||||
val ROCK = register(
|
||||
name = "rock",
|
||||
displayName = Text.translatable("cobblemon.type.rock"),
|
||||
hue = 0xAA9666,
|
||||
textureXMultiplier = 12
|
||||
)
|
||||
|
||||
val GHOST = register(
|
||||
name = "ghost",
|
||||
displayName = Text.translatable("cobblemon.type.ghost"),
|
||||
hue = 0x9572E5,
|
||||
textureXMultiplier = 13
|
||||
)
|
||||
|
||||
val DRAGON = register(
|
||||
name = "dragon",
|
||||
displayName = Text.translatable("cobblemon.type.dragon"),
|
||||
hue = 0x535DE8,
|
||||
textureXMultiplier = 14
|
||||
)
|
||||
|
||||
val DARK = register(
|
||||
name = "dark",
|
||||
displayName = Text.translatable("cobblemon.type.dark"),
|
||||
hue = 0x5C6CB2,
|
||||
textureXMultiplier = 15
|
||||
)
|
||||
|
||||
val STEEL = register(
|
||||
name = "steel",
|
||||
displayName = Text.translatable("cobblemon.type.steel"),
|
||||
hue = 0xC3CCE0,
|
||||
textureXMultiplier = 16
|
||||
)
|
||||
|
||||
val FAIRY = register(
|
||||
name = "fairy",
|
||||
displayName = Text.translatable("cobblemon.type.fairy"),
|
||||
hue = 0xEA727E,
|
||||
textureXMultiplier = 17
|
||||
)
|
||||
|
||||
fun register(name: String, displayName: MutableText, hue: Int, textureXMultiplier: Int): ElementalType {
|
||||
return ElementalType(
|
||||
name = name,
|
||||
displayName = displayName,
|
||||
hue = hue,
|
||||
textureXMultiplier = textureXMultiplier
|
||||
).also {
|
||||
allTypes.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun register(elementalType: ElementalType): ElementalType {
|
||||
allTypes.add(elementalType)
|
||||
return elementalType
|
||||
}
|
||||
|
||||
fun get(name: String): ElementalType? {
|
||||
return allTypes.firstOrNull { type -> type.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun getOrException(name: String): ElementalType {
|
||||
return allTypes.first { type -> type.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
|
||||
fun count() = allTypes.size
|
||||
|
||||
fun all() = this.allTypes.toList()
|
||||
}
|
||||
|
||||
+8
-9
@@ -8,22 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.types.adapters
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.*
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object ElementalTypeAdapter: JsonSerializer<ElementalType>, JsonDeserializer<ElementalType> {
|
||||
|
||||
override fun serialize(src: ElementalType, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
return JsonPrimitive(src.name)
|
||||
return JsonPrimitive(if (src.id().namespace == Cobblemon.MODID) src.id().path else src.id().toString())
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ElementalType {
|
||||
return ElementalTypes.getOrException(json.asString)
|
||||
return CobblemonRegistries.ELEMENTAL_TYPE.get(json.asString.asIdentifierDefaultingNamespace())!!
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.types.client
|
||||
|
||||
import com.cobblemon.mod.common.util.math.toRGB
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Represents various properties used in UIs.
|
||||
* This data is present on the server and synchronized to clients.
|
||||
*
|
||||
* @property hue The RGB tint applied in a few UIs.
|
||||
* @property primaryTexture The primary texture for the type icon.
|
||||
* @property secondaryTexture The secondary texture used when a miniature icon is wanted.
|
||||
* @property uOffset The uOffset on the blitk.
|
||||
* @property vOffset The vOffset on the blitk.
|
||||
*/
|
||||
data class ClientData(
|
||||
val hue: Int,
|
||||
val primaryTexture: Identifier,
|
||||
val secondaryTexture: Identifier,
|
||||
val uOffset: Float,
|
||||
val vOffset: Float
|
||||
) {
|
||||
|
||||
val something = 0xA2C831
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ClientData> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.xmap(Integer::decode, Integer::toHexString).fieldOf("hue").forGetter(ClientData::hue),
|
||||
Identifier.CODEC.fieldOf("primaryTexture").forGetter(ClientData::primaryTexture),
|
||||
Identifier.CODEC.fieldOf("secondaryTexture").forGetter(ClientData::secondaryTexture),
|
||||
Codec.FLOAT.optionalFieldOf("uOffset", 0F).forGetter(ClientData::uOffset),
|
||||
Codec.FLOAT.optionalFieldOf("vOffset", 0F).forGetter(ClientData::vOffset)
|
||||
).apply(builder, ::ClientData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.types.hiddenpower
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.mojang.serialization.Codec
|
||||
|
||||
/**
|
||||
* Responsible for determining if a [Pokemon] can use the hidden power of a given type.
|
||||
* This will be attached to a [ElementalType.hiddenPowerRequirement].
|
||||
*
|
||||
* @property statMap The stat map that checks [IvCondition]s for each IV value of a [Pokemon].
|
||||
*
|
||||
* @throws IllegalArgumentException if not every stat of type [Stat.Type.PERMANENT] is present.
|
||||
*/
|
||||
class HiddenPowerRequirement(internal val statMap: Map<Stat, IvCondition>) {
|
||||
|
||||
init {
|
||||
if (Cobblemon.implementation.environment() == Environment.SERVER && !this.statMap.keys.containsAll(Cobblemon.statProvider.ofType(Stat.Type.PERMANENT))) {
|
||||
throw IllegalArgumentException("Cannot create a ${this::class.simpleName} when missing permanent stats")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] passes this requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being checked.
|
||||
* @return If this requirement is passed against the [pokemon].
|
||||
*/
|
||||
fun isValid(pokemon: Pokemon): Boolean = pokemon.ivs.all { (stat, value) -> this.statMap[stat]!!.fits(value) }
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<HiddenPowerRequirement> = Codec.unboundedMap(Stat.CODEC, IvCondition.CODEC)
|
||||
.xmap(::HiddenPowerRequirement, HiddenPowerRequirement::statMap)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.types.hiddenpower
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the odd or even IV value requirement for hidden power.
|
||||
*/
|
||||
enum class IvCondition : StringIdentifiable {
|
||||
|
||||
EVEN,
|
||||
ODD;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Checks if the given IV value respects the condition.
|
||||
*
|
||||
* @param ivValue The value being checked.
|
||||
* @return true if the value respects the condition.
|
||||
*/
|
||||
fun fits(ivValue: Int): Boolean = when (this) {
|
||||
EVEN -> ivValue % 2 == 0
|
||||
ODD -> ivValue % 2 != 0
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<IvCondition> = StringIdentifiable.createCodec(IvCondition::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
|
||||
/**
|
||||
* An implementation of [ResistanceInformation] for [ElementalType]s.
|
||||
*
|
||||
* @property elementalType The [ElementalType] that would be attacking the type containing this object.
|
||||
*/
|
||||
class ElementalTypeResistanceInformation(val elementalType: ElementalType, override val resistance: Resistance) : ResistanceInformation {
|
||||
|
||||
override fun showdownId(): String = this.elementalType.showdownId()
|
||||
|
||||
override fun toRaw(): RawResistanceInformation = RawResistanceInformation(this.elementalType.id().toString(), this.resistance, ResistanceVariant.ELEMENTAL_TYPE)
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* The raw representation of [ResistanceInformation].
|
||||
* This is used for (de)serialization purposes as certain implementations expect elements that depend on these to be loaded.
|
||||
*
|
||||
* @property value The raw string value used in the [ResistanceVariant.toImplementation].
|
||||
* @property resistance The [Resistance] value used in the [ResistanceVariant.toImplementation].
|
||||
* @property variant The [ResistanceVariant] that will decide the final [ResistanceInformation] implementation.
|
||||
*/
|
||||
data class RawResistanceInformation(
|
||||
val value: String,
|
||||
val resistance: Resistance,
|
||||
val variant: ResistanceVariant
|
||||
) {
|
||||
|
||||
/**
|
||||
* Converts this raw data to a [ResistanceInformation].
|
||||
*
|
||||
* @return The resulting [ResistanceInformation].
|
||||
*
|
||||
* @throws Exception An exception can be thrown by the [ResistanceVariant.toImplementation].
|
||||
*/
|
||||
fun toImplementation(): ResistanceInformation = this.variant.toImplementation(this)
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<RawResistanceInformation> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.fieldOf("value").forGetter(RawResistanceInformation::value),
|
||||
Resistance.CODEC.fieldOf("resistance").forGetter(RawResistanceInformation::resistance),
|
||||
ResistanceVariant.CODEC.fieldOf("variant").forGetter(RawResistanceInformation::variant)
|
||||
).apply(builder, ::RawResistanceInformation)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Represents the resistance of an [ElementalType] or a Showdown effect.
|
||||
*
|
||||
* @property showdownValue The showdown numerical value used in its data format for type resistances.
|
||||
*
|
||||
* @see [ResistanceInformation]
|
||||
*/
|
||||
enum class Resistance(val showdownValue: Int) : StringIdentifiable {
|
||||
|
||||
NEUTRAL(0),
|
||||
WEAK(1),
|
||||
RESIST(2),
|
||||
IMMUNE(3);
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<Resistance> = StringIdentifiable.createCodec(Resistance::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
|
||||
/**
|
||||
* Represents a resistance of an [ElementalType].
|
||||
* This can be to another [ElementalType] or some Showdown effect.
|
||||
* @see [ElementalTypeResistanceInformation]
|
||||
* @see [ShowdownEffectResistanceInformation]
|
||||
*/
|
||||
sealed interface ResistanceInformation : ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The [Resistance] value.
|
||||
*/
|
||||
val resistance: Resistance
|
||||
|
||||
/**
|
||||
* The raw form of this instance.
|
||||
* This is used for (de)serialization as certain elements like elemental types might not be fully loaded when utilizing this.
|
||||
*
|
||||
* @return The resulting [RawResistanceInformation].
|
||||
*/
|
||||
fun toRaw(): RawResistanceInformation
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
/**
|
||||
* Utility type to help with (de)serializing [ResistanceInformation].
|
||||
*
|
||||
* @see [RawResistanceInformation]
|
||||
* @see [RawResistanceInformation.CODEC]
|
||||
*/
|
||||
enum class ResistanceVariant : StringIdentifiable {
|
||||
|
||||
ELEMENTAL_TYPE,
|
||||
EFFECT_ID;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
/**
|
||||
* Converts a [RawResistanceInformation] to a [ResistanceInformation].
|
||||
*
|
||||
* @param raw The base [RawResistanceInformation].
|
||||
* @return The resulting [ResistanceInformation].
|
||||
*
|
||||
* @throws NullPointerException If this is a [ELEMENTAL_TYPE] and the [RawResistanceInformation.value] is not a possible [ElementalType].
|
||||
*/
|
||||
fun toImplementation(raw: RawResistanceInformation): ResistanceInformation = when (this) {
|
||||
ELEMENTAL_TYPE -> ElementalTypeResistanceInformation(CobblemonRegistries.ELEMENTAL_TYPE.get(raw.value.asIdentifierDefaultingNamespace())!!, raw.resistance)
|
||||
EFFECT_ID -> ShowdownEffectResistanceInformation(raw.value, raw.resistance)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val CODEC: Codec<ResistanceVariant> = StringIdentifiable.createCodec(ResistanceVariant::values)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.types.resistance
|
||||
|
||||
/**
|
||||
* An implementation of [ResistanceInformation] for Showdown effects.
|
||||
*
|
||||
* @property showdownEffectId The Showdown ID of the effect being checked.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class ShowdownEffectResistanceInformation(val showdownEffectId: String, override val resistance: Resistance) : ResistanceInformation {
|
||||
|
||||
override fun showdownId(): String = this.showdownEffectId
|
||||
|
||||
override fun toRaw(): RawResistanceInformation = RawResistanceInformation(this.showdownEffectId, this.resistance, ResistanceVariant.EFFECT_ID)
|
||||
|
||||
}
|
||||
@@ -114,7 +114,7 @@ object BattleRegistry {
|
||||
val evsInOrder = Stats.PERMANENT.map { pk.evs.getOrDefault(it) }.joinToString(separator = ",")
|
||||
packedTeamBuilder.append("$evsInOrder|")
|
||||
// Gender
|
||||
packedTeamBuilder.append("${pk.gender.showdownName}|")
|
||||
packedTeamBuilder.append("${pk.gender.showdownId()}|")
|
||||
// IVs
|
||||
val ivsInOrder = Stats.PERMANENT.map { pk.ivs.getOrDefault(it) }.joinToString(separator = ",")
|
||||
packedTeamBuilder.append("$ivsInOrder|")
|
||||
@@ -138,7 +138,7 @@ object BattleRegistry {
|
||||
// 0 - 9, empty == 10
|
||||
packedTeamBuilder.append("${if (pk.dmaxLevel < 10) pk.dmaxLevel else ""},")
|
||||
// Teratype
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.name},")
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.showdownId()},")
|
||||
|
||||
team.add(packedTeamBuilder.toString())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@@ -81,7 +83,7 @@ interface Targetable {
|
||||
}
|
||||
}
|
||||
|
||||
enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null }) {
|
||||
enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null }) : StringIdentifiable {
|
||||
any({ pokemon -> pokemon.getAllActivePokemon().filter { it != pokemon } }),
|
||||
all,
|
||||
allAdjacent,
|
||||
@@ -98,11 +100,14 @@ enum class MoveTarget(val targetList: (Targetable) -> List<Targetable>? = { null
|
||||
foeSide,
|
||||
scripted;
|
||||
|
||||
override fun asString(): String = this.name
|
||||
|
||||
companion object {
|
||||
|
||||
private val VALUES = values()
|
||||
|
||||
val CODEC: Codec<MoveTarget> = StringIdentifiable.createCodec(::VALUES)
|
||||
|
||||
/**
|
||||
* Attempts to parse a [MoveTarget] from the given [showdownId].
|
||||
*
|
||||
|
||||
@@ -21,9 +21,9 @@ import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.scheduling.after
|
||||
import com.cobblemon.mod.common.api.text.*
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
@@ -1704,7 +1704,7 @@ object ShowdownInterpreter {
|
||||
private fun handleTerastallizeInstructions(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
|
||||
val battlePokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val type = message.effectAt(1)?.let { ElementalTypes.get(it.id) } ?: return
|
||||
val type = message.effectAt(1)?.let { CobblemonRegistries.ELEMENTAL_TYPE.firstOrNull { type -> type.showdownId() == it.id } } ?: return
|
||||
battle.dispatchWaiting {
|
||||
battle.broadcastChatMessage(battleLang("terastallize", pokemonName, type.displayName).yellow())
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
|
||||
@@ -32,6 +32,7 @@ interface ShowdownService {
|
||||
fun getItemIds(): JsonArray
|
||||
fun registerSpecies()
|
||||
fun registerBagItems()
|
||||
fun registerTypes()
|
||||
fun indicateSpeciesInitialized() {}
|
||||
|
||||
|
||||
|
||||
+33
@@ -11,11 +11,14 @@ package com.cobblemon.mod.common.battles.runner.graal
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.IvCondition
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
@@ -43,6 +46,7 @@ import org.graalvm.polyglot.io.FileSystem
|
||||
* @since February 27, 2023
|
||||
* @author Hiroku, landonjw
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class GraalShowdownService : ShowdownService {
|
||||
|
||||
@Transient
|
||||
@@ -167,6 +171,35 @@ class GraalShowdownService : ShowdownService {
|
||||
receiveSpeciesDataFn.execute(jsArray)
|
||||
}
|
||||
|
||||
override fun registerTypes() {
|
||||
val receiveTypesDataFn = this.context.getBindings("js").getMember("receiveTypeData")
|
||||
val jsArray = this.context.eval("js", "new Array();")
|
||||
var index = 0L
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
val jObject = JsonObject().apply {
|
||||
val showdownId = type.showdownId()
|
||||
addProperty("name", showdownId.replaceFirstChar(Char::uppercase))
|
||||
addProperty("id", showdownId)
|
||||
val damageTaken = JsonObject()
|
||||
type.resistanceInformation().forEach { information ->
|
||||
damageTaken.addProperty(information.showdownId(), information.resistance.showdownValue)
|
||||
}
|
||||
add("damageTaken", damageTaken)
|
||||
type.hiddenPowerRequirement.ifPresent {
|
||||
val hpIvs = JsonObject()
|
||||
it.statMap.forEach { (stat, requirement) ->
|
||||
if (requirement == IvCondition.EVEN) {
|
||||
hpIvs.addProperty(stat.showdownId, 30)
|
||||
}
|
||||
}
|
||||
add("HPivs", hpIvs)
|
||||
}
|
||||
}
|
||||
jsArray.setArrayElement(index++, jObject)
|
||||
}
|
||||
receiveTypesDataFn.execute(jsArray)
|
||||
}
|
||||
|
||||
override fun indicateSpeciesInitialized() {
|
||||
val afterCobbledSpeciesInitFn = this.context.getBindings("js").getMember("afterCobbledSpeciesInit")
|
||||
afterCobbledSpeciesInitFn.execute()
|
||||
|
||||
+39
-1
@@ -11,6 +11,9 @@ package com.cobblemon.mod.common.battles.runner.socket
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.registry.CobblemonRegistries
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.hiddenpower.IvCondition
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
@@ -18,13 +21,14 @@ import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.nio.charset.Charset
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Mediator service for communicating between the Cobblemon Minecraft mod and Cobblemon showdown service via
|
||||
@@ -42,6 +46,7 @@ import java.util.UUID
|
||||
* @since February 27, 2023
|
||||
* @author landonjw
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class SocketShowdownService(val host: String = "localhost", val port: Int = 18468, val localPort: Int = 0) : ShowdownService {
|
||||
|
||||
private lateinit var socket: Socket
|
||||
@@ -146,6 +151,14 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerTypes() {
|
||||
writer.write(">resetTypeData\n")
|
||||
acknowledge()
|
||||
CobblemonRegistries.ELEMENTAL_TYPE.forEach { type ->
|
||||
this.sendType(type)
|
||||
}
|
||||
}
|
||||
|
||||
fun acknowledge(ifFails: () -> Unit = {}) {
|
||||
writer.flush()
|
||||
val ack = CharArray(3)
|
||||
@@ -166,4 +179,29 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
private fun sendType(type: ElementalType) {
|
||||
// See TypeInfo in Showdown
|
||||
val jObject = JsonObject().apply {
|
||||
val showdownId = type.showdownId()
|
||||
addProperty("name", showdownId.replaceFirstChar(Char::uppercase))
|
||||
addProperty("id", showdownId)
|
||||
val damageTaken = JsonObject()
|
||||
type.resistanceInformation().forEach { information ->
|
||||
damageTaken.addProperty(information.showdownId(), information.resistance.showdownValue)
|
||||
}
|
||||
add("damageTaken", damageTaken)
|
||||
type.hiddenPowerRequirement.ifPresent {
|
||||
val hpIvs = JsonObject()
|
||||
it.statMap.forEach { (stat, requirement) ->
|
||||
if (requirement == IvCondition.EVEN) {
|
||||
hpIvs.addProperty(stat.showdownId, 30)
|
||||
}
|
||||
}
|
||||
add("HPivs", hpIvs)
|
||||
}
|
||||
}
|
||||
writer.write(">receiveTypeData ${this.gson.toJson(jObject)}\n")
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,11 @@
|
||||
package com.cobblemon.mod.common.berry
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.GrowthFactor
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.registry.BiomeIdentifierCondition
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.WorldView
|
||||
import net.minecraft.world.biome.Biome
|
||||
|
||||
class PreferredBiomeGrowthFactor(
|
||||
val bonusYield: IntRange
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonFloatingState
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.moves.DamageCategory
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class MoveCategoryIcon(
|
||||
val x: Number,
|
||||
@@ -36,7 +35,7 @@ class MoveCategoryIcon(
|
||||
y = y.toFloat() / SCALE,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = HEIGHT * category.textureXMultiplier,
|
||||
vOffset = HEIGHT * category.ordinal,
|
||||
textureHeight = HEIGHT * 3,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class TypeIcon(
|
||||
val x: Number,
|
||||
@@ -28,24 +26,22 @@ class TypeIcon(
|
||||
companion object {
|
||||
private const val TYPE_ICON_DIAMETER = 36
|
||||
private const val SCALE = 0.5F
|
||||
|
||||
private val typesResource = cobblemonResource("textures/gui/types.png")
|
||||
private val smallTypesResource = cobblemonResource("textures/gui/types_small.png")
|
||||
}
|
||||
|
||||
fun render(context: DrawContext) {
|
||||
val diameter = if (small) (TYPE_ICON_DIAMETER / 2) else TYPE_ICON_DIAMETER
|
||||
val offsetX = if (centeredX) (((diameter / 2) * SCALE) + (if (secondaryType != null) (doubleCenteredOffset) else 0F)) else 0F;
|
||||
val offsetX = if (centeredX) (((diameter / 2) * SCALE) + (if (secondaryType != null) (doubleCenteredOffset) else 0F)) else 0F
|
||||
|
||||
if (secondaryType != null) {
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = if (small) smallTypesResource else typesResource,
|
||||
texture = if (small) secondaryType.clientData.secondaryTexture else secondaryType.clientData.primaryTexture,
|
||||
x = (x.toFloat() + secondaryOffset - offsetX) / SCALE,
|
||||
y = y.toFloat() / SCALE,
|
||||
height = diameter,
|
||||
width = diameter,
|
||||
uOffset = diameter * secondaryType!!.textureXMultiplier.toFloat() + 0.1,
|
||||
uOffset = diameter * secondaryType.clientData.uOffset + 0.1,
|
||||
vOffset = diameter * secondaryType.clientData.vOffset + 0.1,
|
||||
textureWidth = diameter * 18,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
@@ -54,12 +50,13 @@ class TypeIcon(
|
||||
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = if (small) smallTypesResource else typesResource,
|
||||
texture = if (small) type.clientData.secondaryTexture else type.clientData.primaryTexture,
|
||||
x = (x.toFloat() - offsetX) / SCALE,
|
||||
y = y.toFloat() / SCALE,
|
||||
height = diameter,
|
||||
width = diameter,
|
||||
uOffset = diameter * type.textureXMultiplier.toFloat() + 0.1,
|
||||
uOffset = diameter * type.clientData.uOffset + 0.1,
|
||||
vOffset = diameter * type.clientData.vOffset + 0.1,
|
||||
textureWidth = diameter * 18,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sin
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ abstract class BattleGimmickButton(gimmick: ShowdownMoveset.Gimmick, val x: Floa
|
||||
init {
|
||||
gimmickMoveTemplate?.let {
|
||||
moveTemplate = it
|
||||
rgb = it.elementalType.hue.toRGB()
|
||||
rgb = it.elementalType.clientData.hue.toRGB()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -83,7 +83,7 @@ class BattleMoveSelection(
|
||||
val y: Float,
|
||||
) {
|
||||
var moveTemplate = Moves.getByNameOrDummy(move.id)
|
||||
var rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
var rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
|
||||
open val targetList: List<Targetable>? get() = move.target.targetList(moveSelection.request.activePokemon)
|
||||
open val response: MoveActionResponse get() = MoveActionResponse(move.id, targetPnx)
|
||||
@@ -97,7 +97,7 @@ class BattleMoveSelection(
|
||||
}
|
||||
}
|
||||
|
||||
fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
fun render(context: DrawContext, mouseX: Int, mouseY: Int) {
|
||||
|
||||
val selectConditionOpacity = moveSelection.opacity * if (!selectable) 0.5F else 1F
|
||||
|
||||
@@ -184,7 +184,7 @@ class BattleMoveSelection(
|
||||
|
||||
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
moveTiles.forEach {
|
||||
it.render(context, mouseX, mouseY, delta)
|
||||
it.render(context, mouseX, mouseY)
|
||||
}
|
||||
backButton.render(context.matrices, mouseX, mouseY, delta)
|
||||
gimmickButtons.forEach {
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.client.gui.interact.moveselect
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
@@ -49,7 +48,7 @@ class MoveSlotButton(
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height && enabled
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
val rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
|
||||
val alpha = if (enabled) 1.0 else 0.5
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -31,7 +31,6 @@ import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.InputUtil
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
@@ -454,7 +453,7 @@ class PCGUI(
|
||||
ticksElapsed++
|
||||
|
||||
// Calculate select pointer offset
|
||||
var delayFactor = 3
|
||||
val delayFactor = 3
|
||||
if (ticksElapsed % (2 * delayFactor) == 0) selectPointerOffsetIncrement = !selectPointerOffsetIncrement
|
||||
if (ticksElapsed % delayFactor == 0) selectPointerOffsetY += if (selectPointerOffsetIncrement) 1 else -1
|
||||
}
|
||||
@@ -480,8 +479,8 @@ class PCGUI(
|
||||
offsetY = -10.0
|
||||
)
|
||||
} else {
|
||||
previewPokemon = null;
|
||||
modelWidget = null;
|
||||
previewPokemon = null
|
||||
modelWidget = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
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.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
+1
-2
@@ -37,7 +37,6 @@ import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
@@ -210,7 +209,7 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
|
||||
width = BASE_WIDTH, height = BASE_HEIGHT
|
||||
)
|
||||
// Render Frame
|
||||
val (r, g, b) = currentPokemon.form.primaryType.hue.toRGB()
|
||||
val (r, g, b) = currentPokemon.form.primaryType.clientData.hue.toRGB()
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseFrame,
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWid
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
@@ -306,7 +306,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
*/
|
||||
private fun displayMainScreen(screen: Int) {
|
||||
// Get stat tab index if currently displaying stat screen
|
||||
var subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
|
||||
mainScreenIndex = screen
|
||||
if (::mainScreen.isInitialized) remove(mainScreen)
|
||||
|
||||
+7
-9
@@ -10,28 +10,26 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
class PartySlotWidget(
|
||||
private val pX: Number,
|
||||
private val pY: Number,
|
||||
pX: Number,
|
||||
pY: Number,
|
||||
private val partyWidget: PartyWidget,
|
||||
private val summary: Summary,
|
||||
private val pokemon: Pokemon?,
|
||||
@@ -71,7 +69,7 @@ class PartySlotWidget(
|
||||
}
|
||||
|
||||
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
hovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
|
||||
hovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height
|
||||
val matrices = context.matrices
|
||||
val isDraggedSlot = partyWidget.swapEnabled && partyWidget.swapSource == index
|
||||
val slotPokemon = if (isDraggedSlot) null else pokemon
|
||||
@@ -208,8 +206,8 @@ class PartySlotWidget(
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (isValidClick(mouseX, mouseY, button)) {
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (isValidClick(pMouseX, pMouseY, pButton)) {
|
||||
if (partyWidget.swapEnabled) {
|
||||
toggleDrag(true)
|
||||
} else {
|
||||
@@ -220,7 +218,7 @@ class PartySlotWidget(
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
|
||||
+3
-3
@@ -70,7 +70,7 @@ class MoveSlotWidget(
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
|
||||
val moveTemplate = Moves.getByNameOrDummy(move.name)
|
||||
val rgb = moveTemplate.elementalType.hue.toRGB()
|
||||
val rgb = moveTemplate.elementalType.clientData.hue.toRGB()
|
||||
|
||||
if (movesWidget.selectedMove == move) {
|
||||
blitk(
|
||||
@@ -153,10 +153,10 @@ class MoveSlotWidget(
|
||||
switchMoveButton.render(context, pMouseX, pMouseY, pPartialTicks)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (isHovered) {
|
||||
movesWidget.selectMove(move)
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ class MoveSwapScreen(
|
||||
) {
|
||||
val matrices = context.matrices
|
||||
val tweakedRowTop = rowTop - (SLOT_SPACING / 2) + 1
|
||||
val rgb = move.elementalType.hue.toRGB()
|
||||
val rgb = move.elementalType.clientData.hue.toRGB()
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class SingleTypeWidget(
|
||||
pWidth: Int, pHeight: Int,
|
||||
private val type: ElementalType,
|
||||
private val renderText: Boolean = true
|
||||
) : TypeWidget(pX, pY, pWidth, pHeight, Text.literal("SingleTypeWidget - ${type.name}")) {
|
||||
) : TypeWidget(pX, pY, pWidth, pHeight, Text.literal("SingleTypeWidget - ").append(type.displayName)) {
|
||||
|
||||
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val matrices = context.matrices
|
||||
|
||||
+2
-1
@@ -32,7 +32,8 @@ abstract class TypeWidget(
|
||||
texture = typeResource,
|
||||
x = pX + OFFSET, y = pY,
|
||||
width = width, height = height,
|
||||
uOffset = width * type.textureXMultiplier.toFloat() + 0.1,
|
||||
uOffset = width * type.clientData.uOffset + 0.1,
|
||||
vOffset = width * type.clientData.vOffset + 0.1,
|
||||
textureWidth = width * 18
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,14 +13,13 @@ import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
@@ -25,18 +25,16 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket.Tra
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.api.pokemon.gender.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import java.util.UUID
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.InputUtil
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
@@ -48,9 +46,8 @@ import net.minecraft.text.MutableText
|
||||
*/
|
||||
class TradeGUI(
|
||||
val trade: ClientTrade,
|
||||
val traderId: UUID,
|
||||
val traderName: MutableText,
|
||||
val traderParty: MutableList<TradeablePokemon?>,
|
||||
private val traderName: MutableText,
|
||||
private val traderParty: MutableList<TradeablePokemon?>,
|
||||
val party: MutableList<TradeablePokemon?>
|
||||
): Screen(lang("trade.gui.title")) {
|
||||
|
||||
@@ -373,7 +370,7 @@ class TradeGUI(
|
||||
}
|
||||
|
||||
// Calculate select pointer offset
|
||||
var delayFactor = 3
|
||||
val delayFactor = 3
|
||||
if (ticksElapsed % (2 * delayFactor) == 0) selectPointerOffsetIncrement = !selectPointerOffsetIncrement
|
||||
if (ticksElapsed % delayFactor == 0) selectPointerOffsetY += if (selectPointerOffsetIncrement) 1 else -1
|
||||
|
||||
@@ -418,6 +415,7 @@ class TradeGUI(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun playSound(soundEvent: SoundEvent) {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
-1
@@ -23,7 +23,6 @@ object TradeStartedHandler : ClientNetworkPacketHandler<TradeStartedPacket> {
|
||||
MinecraftClient.getInstance().setScreen(
|
||||
TradeGUI(
|
||||
trade,
|
||||
packet.traderId,
|
||||
packet.traderName,
|
||||
packet.traderParty.toMutableList(),
|
||||
CobblemonClient.storage.myParty.map { it?.let(::TradeablePokemon) }.toMutableList()
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
|
||||
import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user