Added a bunch of AI tasks to NPCs for combat (I dunno it's neat)

This commit is contained in:
Paul
2024-03-16 11:16:58 +10:00
parent 9da2e125ac
commit bd8d9fa9e3
8 changed files with 142 additions and 6 deletions
@@ -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.entity.ai
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object AttackAngryAtTask {
fun create(): SingleTickTask<LivingEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryValue(MemoryModuleType.ANGRY_AT),
it.queryMemoryAbsent(MemoryModuleType.ATTACK_TARGET)
).apply(it) { angryAt, attackTarget ->
TaskRunnable { world, entity, _ ->
val angryAt = it.getValue(angryAt)
val livingEntity = world.getEntity(angryAt) as? LivingEntity
if (livingEntity != null) {
entity.brain.remember(MemoryModuleType.ATTACK_TARGET, livingEntity)
} else {
entity.brain.forget(MemoryModuleType.ANGRY_AT)
}
return@TaskRunnable true
}
}
}
}
@@ -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.entity.ai
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.WalkTarget
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
object MoveToAttackTargetTask {
fun create(): SingleTickTask<LivingEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryValue(MemoryModuleType.ATTACK_TARGET),
it.queryMemoryOptional(MemoryModuleType.WALK_TARGET)
).apply(it) { attackTarget, walkTarget ->
TaskRunnable { world, entity, _ ->
val attackTarget = it.getValue(attackTarget)
val position = attackTarget.pos
val walkTarget = it.getOptionalValue(walkTarget).orElse(null)
if (walkTarget == null || walkTarget.lookTarget.pos.squaredDistanceTo(position) > 4.0) {
entity.brain.remember(MemoryModuleType.WALK_TARGET, WalkTarget(attackTarget, 0.5F, 1))
true
} else {
false
}
}
}
}
}
@@ -35,11 +35,14 @@ import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.Poseable
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
import com.cobblemon.mod.common.entity.ai.FollowWalkTargetTask
import com.cobblemon.mod.common.entity.ai.GetAngryAtAttackerTask
import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
import com.cobblemon.mod.common.entity.ai.StayAfloatTask
import com.cobblemon.mod.common.entity.npc.ai.ChooseWanderTargetTask
import com.cobblemon.mod.common.entity.npc.ai.LookAtBattlingPokemonTask
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
import com.cobblemon.mod.common.entity.npc.ai.SwitchFromBattleTask
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -57,6 +60,7 @@ import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Dynamic
import java.util.UUID
import java.util.concurrent.CompletableFuture
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityPose
import net.minecraft.entity.Npc
import net.minecraft.entity.ai.brain.Activity
@@ -64,10 +68,14 @@ import net.minecraft.entity.ai.brain.Brain
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.sensor.Sensor
import net.minecraft.entity.ai.brain.sensor.SensorType
import net.minecraft.entity.ai.brain.task.ForgetAngryAtTargetTask
import net.minecraft.entity.ai.brain.task.LookAroundTask
import net.minecraft.entity.ai.brain.task.LookAtMobTask
import net.minecraft.entity.ai.brain.task.RandomTask
import net.minecraft.entity.attribute.DefaultAttributeContainer
import net.minecraft.entity.attribute.EntityAttributes
import net.minecraft.entity.damage.DamageSource
import net.minecraft.entity.damage.DamageSources
import net.minecraft.entity.data.DataTracker
import net.minecraft.entity.data.TrackedData
import net.minecraft.entity.passive.PassiveEntity
@@ -143,6 +151,7 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
// This has to be below constructor and entity tracker fields otherwise initialization order is weird and breaks them syncing
companion object {
fun createAttributes(): DefaultAttributeContainer.Builder = createMobAttributes()
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 1.0)
val NPC_CLASS = DataTracker.registerData(NPCEntity::class.java, IdentifierDataSerializer)
val ASPECTS = DataTracker.registerData(NPCEntity::class.java, StringSetDataSerializer)
@@ -162,6 +171,7 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
val MEMORY_MODULES: List<MemoryModuleType<*>> = ImmutableList.of(
MemoryModuleType.LOOK_TARGET,
MemoryModuleType.WALK_TARGET,
MemoryModuleType.ATTACK_TARGET,
MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE,
MemoryModuleType.PATH,
MemoryModuleType.IS_PANICKING,
@@ -172,6 +182,7 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
MemoryModuleType.HURT_BY_ENTITY,
MemoryModuleType.NEAREST_VISIBLE_PLAYER,
MemoryModuleType.ANGRY_AT,
MemoryModuleType.ATTACK_COOLING_DOWN,
)
const val SEND_OUT_ANIMATION = "send_out"
@@ -196,7 +207,8 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
val brain = createBrainProfile().deserialize(dynamic)
brain.setTaskList(Activity.CORE, ImmutableList.of(
Pair.of(0, StayAfloatTask(0.8F)),
Pair.of(0, GetAngryAtAttackerTask.create())
Pair.of(0, GetAngryAtAttackerTask.create()),
Pair.of(0, ForgetAngryAtTargetTask.create())
))
brain.setTaskList(Activity.IDLE, ImmutableList.of(
Pair.of(1, RandomTask(
@@ -207,7 +219,10 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
)
)),
Pair.of(1, FollowWalkTargetTask()),
Pair.of(0, SwitchToBattleTask.create())
Pair.of(0, SwitchToBattleTask.create()),
Pair.of(1, AttackAngryAtTask.create()),
Pair.of(1, MoveToAttackTargetTask.create()),
Pair.of(1, MeleeAttackTask.create(2F, 30L))
))
brain.setTaskList(BATTLING, ImmutableList.of(
Pair.of(0, SwitchFromBattleTask.create()),
@@ -221,6 +236,11 @@ class NPCEntity(world: World) : PassiveEntity(CobblemonEntities.NPC, world), Npc
return brain
}
override fun tryAttack(target: Entity): Boolean {
target as ServerPlayerEntity
return target.damage(this.damageSources.mobAttack(this), attributes.getValue(EntityAttributes.GENERIC_ATTACK_DAMAGE).toFloat() * 5F)
}
override fun onFinishPathfinding() {
// brain.forget(MemoryModuleType.WALK_TARGET)
}
@@ -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.entity.npc.ai
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.entity.ai.brain.task.SingleTickTask
import net.minecraft.entity.ai.brain.task.TaskRunnable
import net.minecraft.entity.ai.brain.task.TaskTriggerer
import net.minecraft.util.Unit
object MeleeAttackTask {
fun create(range: Float, cooldownTicks: Long): SingleTickTask<LivingEntity> = TaskTriggerer.task {
it.group(
it.queryMemoryValue(MemoryModuleType.ATTACK_TARGET),
it.queryMemoryOptional(MemoryModuleType.ATTACK_COOLING_DOWN)
).apply(it) { attackTarget, cooldown ->
TaskRunnable { world, entity, _ ->
val attackTarget = it.getValue(attackTarget)
if (entity.distanceTo(attackTarget) <= range) {
entity.tryAttack(attackTarget)
cooldown.remember(true, cooldownTicks)
true
} else {
false
}
}
}
}
}
Binary file not shown.
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>local.com.bedrockk</groupId>
<artifactId>molang</artifactId>
<version>1.1.13</version>
</project>
+3 -3
View File
@@ -3,10 +3,10 @@
<groupId>local.com.bedrockk</groupId>
<artifactId>molang</artifactId>
<versioning>
<release>1.1.12</release>
<release>1.1.13</release>
<versions>
<version>1.1.12</version>
<version>1.1.13</version>
</versions>
<lastUpdated>20231949339999</lastUpdated>
<lastUpdated>20231949349999</lastUpdated>
</versioning>
</metadata>
+1 -1
View File
@@ -29,7 +29,7 @@ versions:
# common
graal: 22.3.0
molang: 1.1.12
molang: 1.1.13
# test
junit: 5.9.0