diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/README.md b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/README.md index 279466d480..edf60506ec 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/README.md +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/README.md @@ -117,7 +117,7 @@ Example behaviour (`uses_healing_machine.json`): "configurations": [ { "type": "add_tasks_to_activity", - "activity": "idle", + "activity": "minecraft:idle", "tasksByPriority": { "1": [ "heal_using_healing_machine", diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FleeAttackerTaskConfig.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FleeAttackerTaskConfig.kt index 0c49f9377e..710b297338 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FleeAttackerTaskConfig.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/FleeAttackerTaskConfig.kt @@ -9,44 +9,36 @@ package com.cobblemon.mod.common.api.ai.config.task import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext -import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask +import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable import com.cobblemon.mod.common.api.ai.asVariables -import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE -import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER -import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue -import com.cobblemon.mod.common.util.withQueryValue +import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable +import com.cobblemon.mod.common.entity.ai.FleeFromAttackerTask +import com.cobblemon.mod.common.util.asExpression +import com.mojang.datafixers.util.Either 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.SetWalkTargetAwayFrom import net.minecraft.world.entity.ai.memory.MemoryModuleType import net.minecraft.world.entity.ai.sensing.SensorType class FleeAttackerTaskConfig : SingleTaskConfig { - var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_attacker", true).asExpressible() - var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible() - var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible() + val avoidDurationTicks: ExpressionOrEntityVariable = Either.left("600".asExpression()) - override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf( - condition, - speedMultiplier, - desiredDistance - ).asVariables() + override fun getVariables( + entity: LivingEntity, + behaviourConfigurationContext: BehaviourConfigurationContext + ): List { + return listOf(avoidDurationTicks).asVariables() + } override fun createTask( entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext - ): BehaviorControl? { - if (!condition.resolveBoolean(behaviourConfigurationContext.runtime) || entity !is PathfinderMob) return null - - behaviourConfigurationContext.addMemories(MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET) - behaviourConfigurationContext.addSensors(SensorType.HURT_BY) - - val speedMultiplier = speedMultiplier.resolveFloat(behaviourConfigurationContext.runtime) - val desiredDistance = desiredDistance.resolveInt(behaviourConfigurationContext.runtime) - return WrapperLivingEntityTask( - SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false), - PathfinderMob::class.java + ): BehaviorControl { + behaviourConfigurationContext.addMemories( + MemoryModuleType.HURT_BY_ENTITY, + MemoryModuleType.AVOID_TARGET ) + behaviourConfigurationContext.addSensors(SensorType.HURT_BY) + return FleeFromAttackerTask.create(avoidDurationTicks.asExpression()) } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/README.md b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/README.md index 69629e3613..fe21c127c1 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/README.md +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/README.md @@ -162,11 +162,11 @@ on the entity type and this piggy-backs off the Minecraft list of aggressive mob The 'calm_down' type creates a task that will make the entity calm down when it is no longer being hurt and is far from hostiles and its attacker. - `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick. -### flee_attacker -The 'flee_attacker' type creates a task that will make the entity flee from its attacker when it is hurt. +### walk_away_from_avoid_target +The 'flee_attacker' type creates a task that will make the entity flee from its avoid target. - `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick. -- `speedMultiplier`: A MoLang expression that determines the speed multiplier for fleeing from the attacker. Defaults to 0.5 which is an elevated speed to usual. -- `desiredDistance`: A MoLang expression that determines the distance from the attacker that the entity should try to maintain. Defaults to 9. +- `speedMultiplier`: A MoLang expression that determines the speed multiplier for fleeing from the avoid target. Defaults to 0.5 which is an elevated speed to usual. +- `desiredDistance`: A MoLang expression that determines the distance from the target that the entity should try to maintain. Defaults to 9. ### flee_nearest_hostile The 'flee_nearest_hostile' type creates a task that will make the entity flee from the nearest hostile entity when it is hurt. diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt index 5e87c0dcc3..3d380949ac 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt @@ -78,8 +78,9 @@ interface TaskConfig { cobblemonResource("switch_to_panic_when_hurt") to SwitchToPanicWhenHurtTaskConfig::class.java, cobblemonResource("switch_to_panic_when_hostiles_nearby") to SwitchToPanicWhenHostilesNearbyTaskConfig::class.java, cobblemonResource("calm_down") to CalmDownTaskConfig::class.java, - cobblemonResource("flee_attacker") to FleeAttackerTaskConfig::class.java, + cobblemonResource("walk_away_from_avoid_target") to WalkAwayFromAvoidTargetTaskConfig::class.java, cobblemonResource("flee_nearest_hostile") to FleeNearestHostileTaskConfig::class.java, + cobblemonResource("flee_attacker") to FleeAttackerTaskConfig::class.java, cobblemonResource("fly_in_circles") to FlyInCirclesTaskConfig::class.java, cobblemonResource("run_script") to RunScript::class.java, cobblemonResource("look_in_direction") to LookInDirectionTaskConfig::class.java, diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WalkAwayFromAvoidTargetTaskConfig.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WalkAwayFromAvoidTargetTaskConfig.kt new file mode 100644 index 0000000000..c0f47dfe70 --- /dev/null +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/WalkAwayFromAvoidTargetTaskConfig.kt @@ -0,0 +1,53 @@ +/* + * 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.ai.config.task + +import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext +import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable +import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask +import com.cobblemon.mod.common.api.ai.asVariables +import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE +import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER +import com.cobblemon.mod.common.util.asExpression +import com.mojang.datafixers.util.Either +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.SetWalkTargetAwayFrom +import net.minecraft.world.entity.ai.memory.MemoryModuleType +import net.minecraft.world.entity.ai.sensing.SensorType + +class WalkAwayFromAvoidTargetTaskConfig : SingleTaskConfig { + var condition: ExpressionOrEntityVariable = Either.left("true".asExpression()) + var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.7).asExpressible() + var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible() + + override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf( + condition, + speedMultiplier, + desiredDistance + ).asVariables() + + override fun createTask( + entity: LivingEntity, + behaviourConfigurationContext: BehaviourConfigurationContext + ): BehaviorControl? { + if (!condition.resolveBoolean(behaviourConfigurationContext.runtime) || entity !is PathfinderMob) return null + + behaviourConfigurationContext.addMemories(MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET) + behaviourConfigurationContext.addSensors(SensorType.HURT_BY) + + val speedMultiplier = speedMultiplier.resolveFloat(behaviourConfigurationContext.runtime) + val desiredDistance = desiredDistance.resolveInt(behaviourConfigurationContext.runtime) + return WrapperLivingEntityTask( + SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false), + PathfinderMob::class.java + ) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FleeFromAttackerTask.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FleeFromAttackerTask.kt index 10a760382d..042effc1cd 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FleeFromAttackerTask.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/ai/FleeFromAttackerTask.kt @@ -8,6 +8,11 @@ package com.cobblemon.mod.common.entity.ai +import com.bedrockk.molang.Expression +import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue +import com.cobblemon.mod.common.util.mainThreadRuntime +import com.cobblemon.mod.common.util.resolveInt +import com.cobblemon.mod.common.util.withQueryValue import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.behavior.OneShot import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder @@ -15,7 +20,7 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger import net.minecraft.world.entity.ai.memory.MemoryModuleType object FleeFromAttackerTask { - fun create(): OneShot { + fun create(avoidDurationTicks: Expression): OneShot { return BehaviorBuilder.create { it.group( it.present(MemoryModuleType.HURT_BY_ENTITY), @@ -27,7 +32,9 @@ object FleeFromAttackerTask { if (avoidTarget != null && avoidTarget == hurtByEntity.uuid) { return@Trigger false } - entity.brain.setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, hurtByEntity, 30 * 20) + mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue()) + val avoidDurationTicks = mainThreadRuntime.resolveInt(avoidDurationTicks) + entity.brain.setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, hurtByEntity, avoidDurationTicks.toLong()) return@Trigger true } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/GoToSleepTask.kt b/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/GoToSleepTask.kt index 1e1bd8e539..fe16145d22 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/GoToSleepTask.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/ai/tasks/GoToSleepTask.kt @@ -26,7 +26,7 @@ object GoToSleepTask { it.absent(MemoryModuleType.WALK_TARGET), it.registered(CobblemonMemories.POKEMON_DROWSY) ).apply(it) { _, pokemonDrowsy -> - Trigger { world, entity, _ -> + Trigger { _, entity, _ -> val hasSleepStatus = entity.pokemon.status?.status === Statuses.SLEEP if (entity.behaviour.resting.canSleep && ((it.tryGet(pokemonDrowsy).orElse(false) && entity.canSleepAt(entity.blockPosition().below())) || hasSleepStatus) && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) { if (!hasSleepStatus) { diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/CombatBehaviour.kt b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/CombatBehaviour.kt index 2c2e536a9d..846289afc1 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/CombatBehaviour.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/CombatBehaviour.kt @@ -13,7 +13,7 @@ import com.cobblemon.mod.common.api.molang.ObjectValue class CombatBehaviour { var willDefendSelf = false - var willFlee = false + var willFlee = true var willDefendOwner = false var fightsMelee = true diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/PokemonBrain.kt b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/PokemonBrain.kt index be88440746..6bf4bd260d 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/PokemonBrain.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/PokemonBrain.kt @@ -28,6 +28,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor import com.cobblemon.mod.common.entity.pokemon.ai.tasks.* import com.cobblemon.mod.common.pokemon.Pokemon +import com.cobblemon.mod.common.util.asExpression import com.cobblemon.mod.common.util.toDF import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet @@ -59,6 +60,11 @@ object PokemonBrain { private val ADULT_FOLLOW_RANGE = UniformInt.of(5, 16) private val AVOID_MEMORY_DURATION = TimeUtil.rangeOfSeconds(5, 20) + /** + * The things that absolutely should be on all pokemon can be put in here. Things that make no sense + * without specific activities/Behaviours should be given as part of those activities. Some of the things + * in this list currently violate this rule but it's whatever, I'll get to them later. + */ val SENSORS: Collection>> = listOf( SensorType.NEAREST_LIVING_ENTITIES, SensorType.HURT_BY, @@ -206,7 +212,7 @@ object PokemonBrain { if (pokemon.form.behaviour.combat.willDefendSelf) { add(0 toDF GetAngryAtAttackerTask.create()) } else { - add(0 toDF FleeFromAttackerTask.create()) + add(0 toDF FleeFromAttackerTask.create("600".asExpression())) } add(0 toDF StopBeingAngryIfTargetDead.create()) diff --git a/common/src/main/resources/data/cobblemon/behaviours/panics.json b/common/src/main/resources/data/cobblemon/behaviours/panics.json index 730b03562a..7e0813e12f 100644 --- a/common/src/main/resources/data/cobblemon/behaviours/panics.json +++ b/common/src/main/resources/data/cobblemon/behaviours/panics.json @@ -3,29 +3,34 @@ "description": "cobblemon.behaviour.panics.desc", "configurations": [ { - "type": "add_tasks_to_activity", - "activity": "idle", + "type": "cobblemon:add_tasks_to_activity", + "activity": "minecraft:idle", "tasksByPriority": { - "0": ["switch_to_panic_when_hurt"] + "0": ["cobblemon:flee_attacker"], + "10": ["cobblemon:switch_to_panic_when_hurt"] } }, { - "type": "add_tasks_to_activity", - "activity": "panic", + "type": "cobblemon:add_tasks_to_activity", + "activity": "minecraft:panic", "tasksByPriority": { "0": [ - "calm_down", - "follow_walk_target" + "cobblemon:flee_attacker", + { + "type": "cobblemon:activity_change", + "activity": "minecraft:idle", + "condition": "q.entity.lacks_memory_value('minecraft:avoid_target')" + } ], "1": [ - "flee_nearest_hostile" + "cobblemon:flee_nearest_hostile" ], "2": [ - "flee_attacker" + "cobblemon:walk_away_from_avoid_target" ], "3": [ { - "type": "wander", + "type": "cobblemon:wander", "speedMultiplier": { "variableName": "flee_speed_multiplier", "category": "cobblemon.entity.variable.category.fear", diff --git a/common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json b/common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json index 2eec4d4376..7178846b52 100644 --- a/common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json +++ b/common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json @@ -31,7 +31,7 @@ }, { "type": "apply_behaviours", - "condition": "!q.entity.is_in_party && q.entity.behaviour.combat.will_flee", + "condition": "!q.entity.is_in_party && (q.entity.behaviour.combat.will_flee && !q.entity.behaviour.combat.will_defend_self)", "behaviours": [ "cobblemon:panics" ]