From 7e4054ad8fd02c04afb1aa30cdc3fcfdbd032ea4 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 24 Mar 2025 16:15:57 +1000 Subject: [PATCH] Improved land wandering, added path type filtering to pokemon pathing --- ai_bugs.txt | 9 ++ .../cobblemon/mod/common/CobblemonMemories.kt | 2 +- .../api/ai/config/task/FindAirTaskConfig.kt | 2 +- .../api/ai/config/task/WanderTaskConfig.kt | 135 +++++++++--------- .../common/entity/ai/CobblemonWalkTarget.kt | 32 +++++ .../common/entity/ai/FollowWalkTargetTask.kt | 23 ++- .../mod/common/entity/ai/StayAfloatTask.kt | 6 +- .../entity/pokemon/ai/tasks/EatGrassTask.kt | 1 + .../cobblemon/mod/common/pokemon/Species.kt | 6 +- .../common/pokemon/ai/OmniPathNodeMaker.kt | 6 + .../assets/cobblemon/lang/en_us.json | 4 + .../pokemon/pokemon_eats_grass.json | 15 ++ .../cobblemon/species/generation2/mareep.json | 9 +- .../species/generation3/nosepass.json | 10 +- .../species/generation8/dubwool.json | 9 +- .../cobblemon/species/generation8/wooloo.json | 9 +- 16 files changed, 168 insertions(+), 110 deletions(-) create mode 100644 ai_bugs.txt create mode 100644 common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/CobblemonWalkTarget.kt create mode 100644 common/src/main/resources/data/cobblemon/brain_presets/pokemon/pokemon_eats_grass.json diff --git a/ai_bugs.txt b/ai_bugs.txt new file mode 100644 index 0000000000..585095fecf --- /dev/null +++ b/ai_bugs.txt @@ -0,0 +1,9 @@ + +- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint + https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac + +- Why is magikarp trying to path through ice + https://gyazo.com/ae230758c529f885eeb0dd91e60530d2 + +- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise + NPC wandering will be jank too. \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonMemories.kt b/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonMemories.kt index c73ca5d44c..2680de0f3f 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonMemories.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonMemories.kt @@ -37,7 +37,7 @@ object CobblemonMemories { val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL) val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL) val POKEMON_BATTLE = register("pokemon_battle") - val PATH_COOLDOWN = register("path_cooldown", PrimitiveCodec.BOOL) + val PATH_COOLDOWN = register("path_cooldown") val TARGETED_BATTLE_POKEMON = register("targeted_battle_pokemon") val NEAREST_VISIBLE_ATTACKER = register("nearest_visible_attacker") val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops") diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FindAirTaskConfig.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FindAirTaskConfig.kt index fd106c5a22..6c39a0ae2c 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FindAirTaskConfig.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FindAirTaskConfig.kt @@ -67,7 +67,7 @@ class FindAirTaskConfig : SingleTaskConfig { val blockPos = entity.closestPosition(iterable) { isAirPos(entity.level(), it) } ?: return@Trigger false - walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 1)) + walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 0)) return@Trigger true } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WanderTaskConfig.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WanderTaskConfig.kt index f3042db772..70489b81dc 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WanderTaskConfig.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WanderTaskConfig.kt @@ -12,25 +12,17 @@ import com.cobblemon.mod.common.CobblemonMemories import com.cobblemon.mod.common.api.ai.BrainConfigurationContext import com.cobblemon.mod.common.api.ai.asVariables import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue -import com.cobblemon.mod.common.entity.pokemon.PokemonEntity -import com.cobblemon.mod.common.pokemon.Pokemon -import com.cobblemon.mod.common.util.canFit -import com.cobblemon.mod.common.util.toVec3d +import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget import com.cobblemon.mod.common.util.withQueryValue import net.minecraft.core.BlockPos -import net.minecraft.tags.BlockTags import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.ai.behavior.BehaviorControl -import net.minecraft.world.entity.ai.behavior.BlockPosTracker -import net.minecraft.world.entity.ai.behavior.RandomStroll import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder import net.minecraft.world.entity.ai.behavior.declarative.Trigger import net.minecraft.world.entity.ai.memory.MemoryModuleType -import net.minecraft.world.entity.ai.memory.WalkTarget import net.minecraft.world.entity.ai.util.LandRandomPos -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.Vec3 +import net.minecraft.world.level.pathfinder.PathType class WanderTaskConfig : SingleTaskConfig { companion object { @@ -76,69 +68,74 @@ class WanderTaskConfig : SingleTaskConfig { pathCooldown.setWithExpiry(true, 40L) - val targetVec = getLandTarget(entity) ?: return@Trigger true //LandRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt()) ?: return@Trigger false - walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1)) - lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0))) +// val targetVec = getLandTarget(entity) ?: return@Trigger true + val targetVec = LandRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt()) ?: return@Trigger false + val pos = BlockPos.containing(targetVec) + walkTarget.set(CobblemonWalkTarget(pos, speedMultiplier.resolveFloat(), 0, { it !in listOf(PathType.WATER, PathType.WATER_BORDER) })) + lookTarget.erase() return@Trigger true } } } } - @Suppress("DEPRECATION", "MemberVisibilityCanBePrivate") - fun getLandTarget(entity: PathfinderMob): Vec3? { - val roamDistanceCondition: (BlockPos) -> Boolean = if (entity is PokemonEntity) ({ entity.tethering?.canRoamTo(it) != false }) else ({ true }) - val iterable: Iterable = BlockPos.randomBetweenClosed(entity.random, 64, entity.blockX - 10, entity.blockY, entity.blockZ - 10, entity.blockX + 10, entity.blockY, entity.blockZ + 10) - val condition: (BlockState, BlockPos) -> Boolean = { _, pos -> entity.canFit(pos) && roamDistanceCondition(pos) } - val iterator = iterable.iterator() - position@ - while (iterator.hasNext()) { - val pos = iterator.next().mutable() - var blockState = entity.level().getBlockState(pos) - - val maxSteps = 16 - var steps = 0 - var good = false - if (!blockState.isSolid && !blockState.liquid()) { - pos.move(0, -1, 0) - var previousWasAir = true - while (steps++ < maxSteps && pos.y > entity.level().minBuildHeight) { - if (pos.y <= entity.level().minBuildHeight) { - continue@position - } - blockState = entity.level().getBlockState(pos) - if (blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) && previousWasAir) { - pos.move(0, 1, 0) - blockState = entity.level().getBlockState(pos) - good = true - break - } else { - previousWasAir = blockState.isAir - } - pos.move(0, -1, 0) - } - } else { - var previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) - pos.move(0, 1, 0) - while (steps++ < maxSteps) { - if (pos.y >= entity.level().maxBuildHeight) { - continue@position - } - blockState = entity.level().getBlockState(pos) - if (blockState.isAir && previousWasSolid) { - good = true - break - } - previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) - pos.move(0, 1, 0) - } - } - - if (good && condition(blockState, pos)) { - return pos.toVec3d() - } - } - - return null - } + /* + * This method is from the old wander goal. It is very verbose but reliably finds decent land wander targets. Its only advantage over + * the LandRandomPos method (with our CobblemonWalkTarget) is that it doesn't lead entities in the direction of water. + */ +// fun getLandTarget(entity: PathfinderMob): Vec3? { +// val roamDistanceCondition: (BlockPos) -> Boolean = if (entity is PokemonEntity) ({ entity.tethering?.canRoamTo(it) != false }) else ({ true }) +// val iterable: Iterable = BlockPos.randomBetweenClosed(entity.random, 64, entity.blockX - 10, entity.blockY, entity.blockZ - 10, entity.blockX + 10, entity.blockY, entity.blockZ + 10) +// val condition: (BlockState, BlockPos) -> Boolean = { _, pos -> entity.canFit(pos) && roamDistanceCondition(pos) } +// val iterator = iterable.iterator() +// position@ +// while (iterator.hasNext()) { +// val pos = iterator.next().mutable() +// var blockState = entity.level().getBlockState(pos) +// +// val maxSteps = 16 +// var steps = 0 +// var good = false +// if (!blockState.isSolid && !blockState.liquid()) { +// pos.move(0, -1, 0) +// var previousWasAir = true +// while (steps++ < maxSteps && pos.y > entity.level().minBuildHeight) { +// if (pos.y <= entity.level().minBuildHeight) { +// continue@position +// } +// blockState = entity.level().getBlockState(pos) +// if (blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) && previousWasAir) { +// pos.move(0, 1, 0) +// blockState = entity.level().getBlockState(pos) +// good = true +// break +// } else { +// previousWasAir = blockState.isAir +// } +// pos.move(0, -1, 0) +// } +// } else { +// var previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) +// pos.move(0, 1, 0) +// while (steps++ < maxSteps) { +// if (pos.y >= entity.level().maxBuildHeight) { +// continue@position +// } +// blockState = entity.level().getBlockState(pos) +// if (blockState.isAir && previousWasSolid) { +// good = true +// break +// } +// previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) +// pos.move(0, 1, 0) +// } +// } +// +// if (good && condition(blockState, pos)) { +// return pos.toVec3d() +// } +// } +// +// return null +// } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/CobblemonWalkTarget.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/CobblemonWalkTarget.kt new file mode 100644 index 0000000000..74316b459b --- /dev/null +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/CobblemonWalkTarget.kt @@ -0,0 +1,32 @@ +/* + * 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.entity.ai + +import net.minecraft.core.BlockPos +import net.minecraft.world.entity.ai.behavior.BlockPosTracker +import net.minecraft.world.entity.ai.memory.WalkTarget +import net.minecraft.world.level.pathfinder.PathType + +/** + * This is a trick to allow us to instruct the node-maker to only consider specific node types, + * even if the entity can, in a pinch, use more. + * + * @author Hiroku + * @since March 24th, 2025 + */ +class CobblemonWalkTarget( + pos: BlockPos, + speedModifier: Float, + completionRange: Int, + val nodeTypeFilter: (PathType) -> Boolean = { true }, +) : WalkTarget( + BlockPosTracker(pos), + speedModifier, + completionRange +) \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FollowWalkTargetTask.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FollowWalkTargetTask.kt index d1a61578d5..e7b4bc43b6 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FollowWalkTargetTask.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FollowWalkTargetTask.kt @@ -8,6 +8,7 @@ package com.cobblemon.mod.common.entity.ai +import com.cobblemon.mod.common.pokemon.ai.OmniPathNodeMaker import net.minecraft.core.BlockPos import net.minecraft.server.level.ServerLevel import net.minecraft.world.entity.PathfinderMob @@ -18,6 +19,7 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus import net.minecraft.world.entity.ai.memory.WalkTarget import net.minecraft.world.entity.ai.util.DefaultRandomPos import net.minecraft.world.level.pathfinder.Path +import net.minecraft.world.level.pathfinder.PathType import net.minecraft.world.phys.Vec3 class FollowWalkTargetTask( @@ -102,9 +104,22 @@ class FollowWalkTargetTask( } } + private fun withNodeFilter(entity: PathfinderMob, nodeFilter: (PathType) -> Boolean, block: () -> Unit) { + val nodeEvaluator = entity.navigation.nodeEvaluator + if (nodeEvaluator is OmniPathNodeMaker) { + nodeEvaluator.nodeFilter = nodeFilter + block() + nodeEvaluator.nodeFilter = { true } + } else { + block() + } + } + private fun hasFinishedPath(entity: PathfinderMob, walkTarget: WalkTarget, time: Long): Boolean { val blockPos = walkTarget.target.currentBlockPosition() - this.path = entity.navigation.createPath(blockPos, 0) + withNodeFilter(entity, (walkTarget as? CobblemonWalkTarget)?.nodeTypeFilter ?: { true }) { + this.path = entity.navigation.createPath(blockPos, 0) + } this.speed = walkTarget.speedModifier val brain = entity.brain if (hasReached(entity, walkTarget)) { @@ -126,10 +141,12 @@ class FollowWalkTargetTask( 10, 7, Vec3.atBottomCenterOf(blockPos), - 1.5707963705062866 + Math.PI / 2F ) if (vec3d != null) { - this.path = entity.navigation.createPath(vec3d.x, vec3d.y, vec3d.z, 0) + withNodeFilter(entity, (walkTarget as? CobblemonWalkTarget)?.nodeTypeFilter ?: { true }) { + this.path = entity.navigation.createPath(vec3d.x, vec3d.y, vec3d.z, 0) + } return this.path != null } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/StayAfloatTask.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/StayAfloatTask.kt index f3b45a4e8c..53e9966058 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/StayAfloatTask.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/StayAfloatTask.kt @@ -12,13 +12,9 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.tags.FluidTags import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.ai.behavior.Behavior -import net.minecraft.world.entity.ai.memory.MemoryModuleType -import net.minecraft.world.entity.ai.memory.MemoryStatus class StayAfloatTask(private val chance: Float = 0F) : Behavior( - mapOf( - MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT, - ) + mapOf() ) { override fun checkExtraStartConditions(world: ServerLevel, entity: PathfinderMob): Boolean { return entity.isInWater && entity.getFluidHeight(FluidTags.WATER) > entity.fluidJumpThreshold || entity.isInLava diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/EatGrassTask.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/EatGrassTask.kt index 69fc3f0cea..57f71d37bc 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/EatGrassTask.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/EatGrassTask.kt @@ -59,6 +59,7 @@ class EatGrassTask( override fun start(world: ServerLevel, entity: PokemonEntity, time: Long) { timer = 40 + entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_COOLDOWN, true, 40L) entity.playAnimation("eat") world.broadcastEntityEvent(entity, 10.toByte()) } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Species.kt b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Species.kt index 26bdc82fbc..2cf39eb65e 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Species.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Species.kt @@ -125,13 +125,9 @@ class Species : ClientDataSynchronizer, ShowdownIdentifiable { ) }, ApplyPresets().apply { - presets.add(cobblemonResource("floats")) + presets.addAll(listOf(cobblemonResource("floats"), cobblemonResource("avoids_water"))) condition = Either.left("!q.entity.behaviour.moving.swim.can_breathe_underwater".asExpression()) }, - ApplyPresets().apply { - presets.add(cobblemonResource("avoids_water")) - condition = Either.left("q.entity.behaviour.moving.swim.avoids_water".asExpression()) - }, ApplyPresets().apply { condition = Either.left("!q.entity.is_in_party".asExpression()) presets.add(cobblemonResource("pokemon_sleeps")) diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/OmniPathNodeMaker.kt b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/OmniPathNodeMaker.kt index ee6fc9508b..1638c7551c 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/OmniPathNodeMaker.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/OmniPathNodeMaker.kt @@ -43,6 +43,8 @@ class OmniPathNodeMaker : NodeEvaluator() { var canPathThroughFire: Boolean = false + var nodeFilter: (PathType) -> Boolean = { true } + override fun prepare(cachedWorld: PathNavigationRegion, entity: Mob) { super.prepare(cachedWorld, entity) nodePosToType.clear() @@ -188,6 +190,10 @@ class OmniPathNodeMaker : NodeEvaluator() { } fun isValidPathType(type: PathType): Boolean { + if (!nodeFilter(type)) { + return false + } + return when { (type == PathType.BREACH || type == PathType.WATER || type == PathType.WATER_BORDER) && canSwimInWater() -> true type == PathType.OPEN && canFly() -> true diff --git a/common/src/main/resources/assets/cobblemon/lang/en_us.json b/common/src/main/resources/assets/cobblemon/lang/en_us.json index f81ed2f4b6..d0173362d4 100644 --- a/common/src/main/resources/assets/cobblemon/lang/en_us.json +++ b/common/src/main/resources/assets/cobblemon/lang/en_us.json @@ -939,6 +939,7 @@ "cobblemon.command.dialogue.invalid-dialogue": "Invalid dialogue identifier", "cobblemon.command.pc.invalid-box": "Box number %1$s exceeds max boxes of %2$s.", "cobblemon.command.unlockablepcboxwallpaper.invalid-wallpaper": "Invalid wallpaper identifier", + "cobblemon.command.brainedit.non_scriptable": "You are not looking at a MoLang scriptable entity.", "cobblemon.ui.generic.yes": "Yes", "cobblemon.ui.generic.no": "No", @@ -2823,6 +2824,9 @@ "cobblemon.brain_preset.avoids_water.name": "Avoids Water", "cobblemon.brain_preset.avoids_water.desc": "Tries to find air and then gets away from water.", + "cobblemon.brain_preset.pokemon_eats_grass.name": "Eats Grass", + "cobblemon.brain_preset.pokemon_eats_grass.desc": "The Pokémon occasionally eats grass underfoot.", + "cobblemon.move.10000000voltthunderbolt": "10,000,000 Volt Thunderbolt", "cobblemon.move.10000000voltthunderbolt.desc": "The user, Pikachu wearing a cap, powers up a jolt of electricity using its Z-Power and unleashes it. Critical hits land more easily.", "cobblemon.move.absorb": "Absorb", diff --git a/common/src/main/resources/data/cobblemon/brain_presets/pokemon/pokemon_eats_grass.json b/common/src/main/resources/data/cobblemon/brain_presets/pokemon/pokemon_eats_grass.json new file mode 100644 index 0000000000..99ca907c92 --- /dev/null +++ b/common/src/main/resources/data/cobblemon/brain_presets/pokemon/pokemon_eats_grass.json @@ -0,0 +1,15 @@ +{ + "name": "cobblemon.brain_preset.pokemon_eats_grass.name", + "description": "cobblemon.brain_preset.pokemon_eats_grass.desc", + "configurations": [ + { + "type": "add_tasks_to_activity", + "activity": "idle", + "tasksByPriority": { + "2": [ + "eat_grass" + ] + } + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/data/cobblemon/species/generation2/mareep.json b/common/src/main/resources/data/cobblemon/species/generation2/mareep.json index 78b4ebd339..bf92195ba3 100644 --- a/common/src/main/resources/data/cobblemon/species/generation2/mareep.json +++ b/common/src/main/resources/data/cobblemon/species/generation2/mareep.json @@ -64,13 +64,8 @@ }, "ai": [ { - "type": "add_tasks_to_activity", - "activity": "idle", - "tasksByPriority": { - "2": [ - "eat_grass" - ] - } + "type": "apply_presets", + "preset": "cobblemon:eats_grass" } ], "drops": { diff --git a/common/src/main/resources/data/cobblemon/species/generation3/nosepass.json b/common/src/main/resources/data/cobblemon/species/generation3/nosepass.json index b3569180f0..252f37a113 100644 --- a/common/src/main/resources/data/cobblemon/species/generation3/nosepass.json +++ b/common/src/main/resources/data/cobblemon/species/generation3/nosepass.json @@ -64,11 +64,11 @@ { "type": "add_tasks_to_activity", "activity": "idle", - "tasksByPriority": { - "2": [ - "point_to_spawn" - ] - } + "tasksByPriority": { + "2": [ + "point_to_spawn" + ] + } } ], "drops": { diff --git a/common/src/main/resources/data/cobblemon/species/generation8/dubwool.json b/common/src/main/resources/data/cobblemon/species/generation8/dubwool.json index 184c14a225..cad7c0028b 100644 --- a/common/src/main/resources/data/cobblemon/species/generation8/dubwool.json +++ b/common/src/main/resources/data/cobblemon/species/generation8/dubwool.json @@ -59,13 +59,8 @@ }, "ai": [ { - "type": "add_tasks_to_activity", - "activity": "idle", - "tasksByPriority": { - "2": [ - "eat_grass" - ] - } + "type": "apply_presets", + "presets": ["cobblemon:eats_grass"] } ], "drops": { diff --git a/common/src/main/resources/data/cobblemon/species/generation8/wooloo.json b/common/src/main/resources/data/cobblemon/species/generation8/wooloo.json index 8c20bf1cb8..2a8aa805ce 100644 --- a/common/src/main/resources/data/cobblemon/species/generation8/wooloo.json +++ b/common/src/main/resources/data/cobblemon/species/generation8/wooloo.json @@ -53,13 +53,8 @@ }, "ai": [ { - "type": "add_tasks_to_activity", - "activity": "idle", - "tasksByPriority": { - "2": [ - "eat_grass" - ] - } + "type": "apply_presets", + "presets": ["cobblemon:eats_grass"] } ], "standingEyeHeight": 0.6,