Compare commits

...
Author SHA1 Message Date
Paul c1673d0416 Mergo conflicto 2024-05-19 19:14:21 +10:00
Paul 865e365093 Merge remote-tracking branch 'origin/main' into mooshtank_fix_and_shuckle_nerf_but_1.5
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/DataKeys.kt
2024-05-19 19:12:06 +10:00
Paul 1c1985e563 Cleaned up Mooshtank implementation but can only be merged with Ghimmighoul big cry 2023-11-27 11:41:04 +10:00
5 changed files with 280 additions and 115 deletions
@@ -96,6 +96,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.MooshtankFeatureProvider
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
@@ -286,6 +287,10 @@ object Cobblemon {
SpeciesFeatures.register(
DataKeys.HAS_BEEN_SHEARED,
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.HAS_BEEN_SHEARED), default = false))
SpeciesFeatures.register(
DataKeys.MOOSHTANK,
MooshtankFeatureProvider
)
CustomPokemonProperty.register(UncatchableProperty)
CustomPokemonProperty.register(PokemonFlagProperty)
@@ -20,8 +20,6 @@ import com.cobblemon.mod.common.api.events.pokemon.ShoulderMountEvent
import com.cobblemon.mod.common.api.interaction.PokemonEntityInteraction
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.status.Statuses
@@ -58,12 +56,11 @@ import com.cobblemon.mod.common.pokemon.activestate.InactivePokemonState
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.ai.FormPokemonBehaviour
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.feature.MooshtankFeature
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import java.util.EnumSet
import java.util.Optional
import java.util.UUID
import java.util.*
import java.util.concurrent.CompletableFuture
import net.minecraft.entity.*
import net.minecraft.entity.ai.control.MoveControl
@@ -77,7 +74,6 @@ import net.minecraft.entity.damage.DamageTypes
import net.minecraft.entity.data.DataTracker
import net.minecraft.entity.data.TrackedData
import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.entity.effect.StatusEffect
import net.minecraft.entity.passive.AnimalEntity
import net.minecraft.entity.passive.PassiveEntity
import net.minecraft.entity.passive.TameableShoulderEntity
@@ -87,7 +83,6 @@ import net.minecraft.item.DyeItem
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUsage
import net.minecraft.item.Items
import net.minecraft.item.SuspiciousStewItem
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtHelper
import net.minecraft.nbt.NbtString
@@ -104,18 +99,14 @@ import net.minecraft.sound.SoundEvents
import net.minecraft.text.Text
import net.minecraft.text.TextContent
import net.minecraft.util.ActionResult
import net.minecraft.util.Colors
import net.minecraft.util.DyeColor
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
import net.minecraft.util.math.Vec3d
import net.minecraft.world.EntityView
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
import java.util.*
@Suppress("unused")
open class PokemonEntity(
@@ -622,106 +613,24 @@ open class PokemonEntity(
this.emitGameEvent(GameEvent.SHEAR, player)
itemStack.damage(1, player) { it.sendToolBreakStatus(hand) }
return ActionResult.SUCCESS
}
else if (itemStack.isOf(Items.BUCKET)) {
} else if (itemStack.isOf(Items.BUCKET)) {
if (pokemon.getFeature<FlagSpeciesFeature>(DataKeys.CAN_BE_MILKED) != null) {
player.playSound(SoundEvents.ENTITY_GOAT_MILK, 1.0f, 1.0f)
val milkBucket = ItemUsage.exchangeStack(itemStack, player, Items.MILK_BUCKET.defaultStack)
player.setStackInHand(hand, milkBucket)
return ActionResult.success(world.isClient)
}
} else if (itemStack.isOf(Items.BOWL)) {
if (pokemon.aspects.any() {it.contains("mooshtank")}) {
player.playSound(SoundEvents.ENTITY_MOOSHROOM_MILK, 1.0f, 1.0f)
// if the Mooshtank ate a Flower beforehand
if (pokemon.lastFlowerFed != ItemStack.EMPTY && pokemon.aspects.any() {it.contains("mooshtank-brown")}) {
var effect: StatusEffect? = null
var duration = 0
if (pokemon.lastFlowerFed.isOf(Items.ALLIUM)) {
effect = StatusEffect.byRawId(12) // Fire Resistance
duration = 80 // 4 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.AZURE_BLUET)) {
effect = StatusEffect.byRawId(15) // Blindness
duration = 160 // 8 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.BLUE_ORCHID) || pokemon.lastFlowerFed.isOf(Items.DANDELION)) {
effect = StatusEffect.byRawId(23) // Saturation
duration = 7 // .35 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.CORNFLOWER)) {
effect = StatusEffect.byRawId(8) // Jump Boost
duration = 120 // 6 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.LILY_OF_THE_VALLEY)) {
effect = StatusEffect.byRawId(19) // Poison
duration = 240 // 12 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.OXEYE_DAISY)) {
effect = StatusEffect.byRawId(10) // Regeneration
duration = 160 // 8 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.POPPY) || pokemon.lastFlowerFed.isOf(Items.TORCHFLOWER)) {
effect = StatusEffect.byRawId(16) // Night Vision
duration = 100 // 5 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.PINK_TULIP) || pokemon.lastFlowerFed.isOf(Items.RED_TULIP) || pokemon.lastFlowerFed.isOf(Items.WHITE_TULIP) || pokemon.lastFlowerFed.isOf(Items.ORANGE_TULIP)) {
effect = StatusEffect.byRawId(18) // Weakness
duration = 180 // 9 seconds
} else if (pokemon.lastFlowerFed.isOf(Items.WITHER_ROSE)) {
effect = StatusEffect.byRawId(20) // Wither
duration = 160 // 8 seconds
} else if (pokemon.lastFlowerFed.isOf(CobblemonItems.PEP_UP_FLOWER)) {
effect = StatusEffect.byRawId(25) // Levitation
duration = 160 // 8 seconds
}
// modify the suspicious stew with the effect
val susStewStack = Items.SUSPICIOUS_STEW.defaultStack
SuspiciousStewItem.addEffectToStew(susStewStack, effect, duration)
val susStewEffect = ItemUsage.exchangeStack(itemStack, player, susStewStack)
//give player modified Suspicious Stew
player.setStackInHand(hand, susStewEffect)
// reset the flower fed state
pokemon.lastFlowerFed = ItemStack.EMPTY
return ActionResult.success(world.isClient)
}
else {
val mushroomStew = ItemUsage.exchangeStack(itemStack, player, Items.MUSHROOM_STEW.defaultStack)
player.setStackInHand(hand, mushroomStew)
return ActionResult.success(world.isClient)
}
}
}
// Flowers used on brown MooshTanks
else if (itemStack.isOf(Items.ALLIUM) ||
itemStack.isOf(Items.AZURE_BLUET) ||
itemStack.isOf(Items.BLUE_ORCHID) ||
itemStack.isOf(Items.DANDELION) ||
itemStack.isOf(Items.CORNFLOWER) ||
itemStack.isOf(Items.LILY_OF_THE_VALLEY) ||
itemStack.isOf(Items.OXEYE_DAISY) ||
itemStack.isOf(Items.POPPY) ||
itemStack.isOf(Items.TORCHFLOWER) ||
itemStack.isOf(Items.PINK_TULIP) ||
itemStack.isOf(Items.RED_TULIP) ||
itemStack.isOf(Items.WHITE_TULIP) ||
itemStack.isOf(Items.ORANGE_TULIP) ||
itemStack.isOf(Items.WITHER_ROSE) ||
itemStack.isOf(CobblemonItems.PEP_UP_FLOWER)) {
if (pokemon.aspects.any() {it.contains("mooshtank")}) {
player.playSound(SoundEvents.ENTITY_MOOSHROOM_EAT, 1.0f, 1.0f)
pokemon.lastFlowerFed = itemStack
return ActionResult.success(world.isClient)
}
} else if(!player.isSneaking && (itemStack.isOf(CobblemonItems.RELIC_COIN)
|| itemStack.isOf(CobblemonItems.RELIC_COIN_POUCH)
|| itemStack.isOf(CobblemonItems.RELIC_COIN_SACK)
|| itemStack.isOf(Items.NETHERITE_SCRAP)
|| itemStack.isOf(Items.NETHERITE_INGOT)
|| itemStack.isOf(Items.NETHERITE_BLOCK))) {
} else if (!player.isSneaking && (itemStack.isOf(CobblemonItems.RELIC_COIN)
|| itemStack.isOf(CobblemonItems.RELIC_COIN_POUCH)
|| itemStack.isOf(CobblemonItems.RELIC_COIN_SACK)
|| itemStack.isOf(Items.NETHERITE_SCRAP)
|| itemStack.isOf(Items.NETHERITE_INGOT)
|| itemStack.isOf(Items.NETHERITE_BLOCK))) {
if(GimmighoulStashHandler.interactMob(player, hand, pokemon)) {
return ActionResult.SUCCESS
}
}
else if (itemStack.item is DyeItem && colorFeature != null) {
} else if (itemStack.item is DyeItem && colorFeature != null) {
val item = itemStack.item as DyeItem
if (item.color.name.lowercase() != colorFeature.value.lowercase()) {
itemStack.decrement(1)
@@ -729,16 +638,19 @@ open class PokemonEntity(
this.pokemon.markFeatureDirty(colorFeature)
this.pokemon.updateAspects()
}
}
else if (itemStack.item.equals(Items.WATER_BUCKET) && colorFeature != null) {
} else if (itemStack.item.equals(Items.WATER_BUCKET) && colorFeature != null) {
itemStack.decrement(1)
player.giveOrDropItemStack(Items.BUCKET.defaultStack)
colorFeature.value = ""
this.pokemon.markFeatureDirty(colorFeature)
this.pokemon.updateAspects()
} else {
val result = pokemon.getFeature<MooshtankFeature>(DataKeys.MOOSHTANK)?.interact(this, player, hand)
if (result != null) {
return result
}
}
if (hand == Hand.MAIN_HAND && player is ServerPlayerEntity && pokemon.getOwnerPlayer() == player) {
if (player.isSneaking) {
InteractPokemonUIPacket(this.getUuid(), isReadyToSitOnPlayer && pokemon in player.party()).sendToPlayer(player)
@@ -0,0 +1,256 @@
/*
* 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.pokemon.feature
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.JsonObject
import net.minecraft.entity.effect.StatusEffect
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemUsage
import net.minecraft.item.Items
import net.minecraft.item.SuspiciousStewItem
import net.minecraft.nbt.NbtCompound
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.SoundEvents
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
class MooshtankFlowerEffect(
val items: Set<Identifier>,
val effect: StatusEffect,
val duration: Int
)
object MooshtankFeatureProvider : SpeciesFeatureProvider<MooshtankFeature>, AspectProvider, CustomPokemonPropertyType<MooshtankFeature> {
override fun invoke(pokemon: Pokemon): MooshtankFeature? {
return pokemon.getFeature(DataKeys.MOOSHTANK) // It's not a mooshtank unless it's been explicitly branded as one already
}
override fun invoke(nbt: NbtCompound): MooshtankFeature? {
if (nbt.contains(DataKeys.MOOSHTANK)) {
return MooshtankFeature().also { it.loadFromNBT(nbt.getCompound(DataKeys.MOOSHTANK)) }
} else {
return null
}
}
override fun invoke(json: JsonObject): MooshtankFeature? {
if (json.has(DataKeys.MOOSHTANK)) {
return MooshtankFeature().also { it.loadFromJSON(json.getAsJsonObject(DataKeys.MOOSHTANK)) }
} else {
return null
}
}
override fun provide(pokemon: Pokemon): Set<String> {
val feature = pokemon.getFeature<MooshtankFeature>(DataKeys.MOOSHTANK)
return if (feature != null) {
setOf("${feature.name}-" + if (feature.isBrown) "brown" else "red")
} else {
emptySet()
}
}
override fun provide(properties: PokemonProperties): Set<String> {
val feature = properties.customProperties.filterIsInstance<MooshtankFeature>().firstOrNull()
return if (feature != null) {
setOf("${feature.name}-" + if (feature.isBrown) "brown" else "red")
} else {
emptySet()
}
}
override val keys = setOf(DataKeys.MOOSHTANK)
override val needsKey = true
override fun fromString(value: String?): MooshtankFeature? {
val isBrown = when (value?.lowercase()) {
null -> false
"red" -> false
"brown" -> true
else -> return null
}
return MooshtankFeature().also { it.isBrown = isBrown }
}
override fun examples() = setOf("red", "brown")
}
class MooshtankFeature : SpeciesFeature, CustomPokemonProperty {
companion object {
val effectedFlowers = mutableListOf(
MooshtankFlowerEffect(
setOf(Identifier("allium")),
StatusEffects.FIRE_RESISTANCE,
80 // 4 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("azure_bluet")),
StatusEffects.BLINDNESS,
160 // 8 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("blue_orchid"), Identifier("dandelion")),
StatusEffects.SATURATION,
7 // .35 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("cornflower")),
StatusEffects.JUMP_BOOST,
120 // 6 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("lily_of_the_valley")),
StatusEffects.POISON,
240 // 12 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("oxeye_daisy")),
StatusEffects.REGENERATION,
160 // 8 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("poppy"), Identifier("torchflower")),
StatusEffects.NIGHT_VISION,
100 // 5 seconds
),
MooshtankFlowerEffect(
setOf(
Identifier("pink_tulip"),
Identifier("red_tulip"),
Identifier("white_tulip"),
Identifier("orange_tulip")
),
StatusEffects.WEAKNESS,
180 // 9 seconds
),
MooshtankFlowerEffect(
setOf(Identifier("wither_rose")),
StatusEffects.WITHER,
160 // 8 seconds
),
MooshtankFlowerEffect(
setOf(cobblemonResource("pep_up_flower")),
StatusEffects.LEVITATION,
160 // 8 seconds
)
)
}
override val name = DataKeys.MOOSHTANK
var isBrown = false
var lastFlowerFed: Identifier? = null
fun interact(pokemonEntity: PokemonEntity, player: PlayerEntity, hand: Hand): ActionResult? {
val itemStack = player.getStackInHand(hand)
val itemId = pokemonEntity.world.registryManager.get(RegistryKeys.ITEM).getId(itemStack.item) ?: return null // not likely
if (itemStack.isOf(Items.BOWL)) {
player.playSound(SoundEvents.ENTITY_MOOSHROOM_MILK, 1.0f, 1.0f)
// if the Mooshtank ate a Flower beforehand
val lastFlowerFed = this.lastFlowerFed
if (lastFlowerFed != null && isBrown) {
val flowerEffect = effectedFlowers.find { lastFlowerFed in it.items }
val effect = flowerEffect?.effect
val duration = flowerEffect?.duration ?: 0
// modify the suspicious stew with the effect
val susStewStack = Items.SUSPICIOUS_STEW.defaultStack
SuspiciousStewItem.addEffectToStew(susStewStack, effect, duration)
val susStewEffect = ItemUsage.exchangeStack(itemStack, player, susStewStack)
//give player modified Suspicious Stew
player.setStackInHand(hand, susStewEffect)
// reset the flower fed state
this.lastFlowerFed = null
pokemonEntity.pokemon.markFeatureDirty(this)
return ActionResult.success(pokemonEntity.world.isClient)
} else {
val mushroomStew = ItemUsage.exchangeStack(itemStack, player, Items.MUSHROOM_STEW.defaultStack)
player.setStackInHand(hand, mushroomStew)
return ActionResult.success(pokemonEntity.world.isClient)
}
} else if (this.isBrown && effectedFlowers.any { itemId in it.items }) {
player.playSound(SoundEvents.ENTITY_MOOSHROOM_EAT, 1.0f, 1.0f)
lastFlowerFed = itemId
pokemonEntity.pokemon.markFeatureDirty(this)
return ActionResult.success(pokemonEntity.world.isClient)
}
return null
}
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
val nbt = NbtCompound()
nbt.putBoolean(DataKeys.MOOSHTANK_BROWN, isBrown)
val lastFlowerFed = this.lastFlowerFed
if (lastFlowerFed != null) {
nbt.putString(DataKeys.MOOSHTANK_LAST_FLOWER_FED, lastFlowerFed.toString())
}
pokemonNBT.put(DataKeys.MOOSHTANK, nbt)
return pokemonNBT
}
override fun loadFromNBT(pokemonNBT: NbtCompound): SpeciesFeature {
val nbt = pokemonNBT.getCompound(DataKeys.MOOSHTANK)
isBrown = nbt.getBoolean(DataKeys.MOOSHTANK_BROWN)
lastFlowerFed = nbt.getString(DataKeys.MOOSHTANK_LAST_FLOWER_FED).takeIf { it.isNotBlank() }?.let(::Identifier)
return this
}
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
val json = JsonObject()
json.addProperty(DataKeys.MOOSHTANK_BROWN, isBrown)
val lastFlowerFed = this.lastFlowerFed
if (lastFlowerFed != null) {
json.addProperty(DataKeys.MOOSHTANK_LAST_FLOWER_FED, lastFlowerFed.toString())
}
pokemonJSON.add(DataKeys.MOOSHTANK, json)
return pokemonJSON
}
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
val json = pokemonJSON.getAsJsonObject(DataKeys.MOOSHTANK)
isBrown = json.get(DataKeys.MOOSHTANK_BROWN).asBoolean
lastFlowerFed = json.get(DataKeys.MOOSHTANK_LAST_FLOWER_FED)?.asString?.let(::Identifier)
return this
}
override fun asString() = "mooshtank=${if (isBrown) "brown" else "red"}"
override fun apply(pokemon: Pokemon) {
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
val existingFeature = pokemon.getFeature<MooshtankFeature>(name)
if (existingFeature != null) {
existingFeature.isBrown = isBrown
pokemon.markFeatureDirty(existingFeature)
} else {
val feature = MooshtankFeature().also { it.isBrown = isBrown }
pokemon.features.add(feature)
pokemon.markFeatureDirty(feature)
}
pokemon.updateAspects()
}
}
override fun matches(pokemon: Pokemon): Boolean {
val feature = pokemon.getFeature<MooshtankFeature>(DataKeys.MOOSHTANK)
return feature != null && feature.isBrown == isBrown
}
}
@@ -138,6 +138,9 @@ object DataKeys {
// Variants
const val IS_MOOSHTANK = "mooshtank"
const val MOOSHTANK_BROWN = "IsBrown"
const val MOOSHTANK_LAST_FLOWER_FED = "LastFlowerFed"
const val MOOSHTANK = "mooshtank"
// Persistent Data
const val POKEMON_PERSISTENT_DATA = "PersistentData"
@@ -1,11 +0,0 @@
{
"type": "choice",
"keys": ["mooshtank"],
"default": "false",
"choices": [
"red",
"brown"
],
"isAspect": true,
"aspectFormat": "mooshtank-{{choice}}"
}