forked from mirrors/cobblemon
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a141e0c6e | ||
|
|
638a9e77d7 |
@@ -20,6 +20,8 @@ object CobblemonActivities {
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
val POKEMON_HERD = register(Activity("pokemon_herd"))
|
||||
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
|
||||
val POKEMON_STEAL_HONEY = register(Activity("pokemon_steal_honey"))
|
||||
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
|
||||
@@ -54,6 +54,8 @@ object CobblemonMemories {
|
||||
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
|
||||
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
|
||||
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
|
||||
val HAS_HONEY = register<Boolean>("has_honey")
|
||||
val SACCHARINE_LOG_LOCATION = register<BlockPos>("saccharine_log_location")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
|
||||
@@ -37,6 +37,8 @@ object CobblemonSensors {
|
||||
|
||||
val NEARBY_FLOWER = register("nearby_flower", ::FlowerSensor)
|
||||
|
||||
val NEARBY_SACCHARINE_LOG = register("nearby_saccharine_log", ::SaccharineLogSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToSaccharineLogTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class PathToSaccharineLogTaskConfig : SingleTaskConfig {
|
||||
companion object { const val SLATHER = "slather" }
|
||||
private val condition = booleanVariable(SLATHER, "can_slather_honey", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, ctx: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) return null
|
||||
if (!checkCondition(entity, condition)) return null
|
||||
|
||||
ctx.addMemories(
|
||||
CobblemonMemories.SACCHARINE_LOG_LOCATION,
|
||||
CobblemonMemories.HAS_HONEY
|
||||
)
|
||||
ctx.addSensors(CobblemonSensors.NEARBY_SACCHARINE_LOG)
|
||||
return PathToSaccharineLogTask.create()
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.SlatherHoneyOnLogTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class SlatherHoneyOnLogTaskConfig : SingleTaskConfig {
|
||||
companion object { const val SLATHER = "slather" }
|
||||
private val condition = booleanVariable(SLATHER, "can_slather_honey", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, ctx: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) return null
|
||||
if (!checkCondition(entity, condition)) return null
|
||||
return SlatherHoneyOnLogTask.create()
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.StealHoneyFromHiveTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class StealHoneyFromHiveTaskConfig : SingleTaskConfig {
|
||||
companion object { const val STEAL = "steal" }
|
||||
private val condition = booleanVariable(STEAL, "can_steal_honey", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, ctx: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) return null
|
||||
if (!checkCondition(entity, condition)) return null
|
||||
return StealHoneyFromHiveTask.create()
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,10 @@ interface TaskConfig {
|
||||
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
|
||||
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
|
||||
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
|
||||
)
|
||||
cobblemonResource("steal_honey_from_hive") to StealHoneyFromHiveTaskConfig::class.java,
|
||||
cobblemonResource("path_to_saccharine_log") to PathToSaccharineLogTaskConfig::class.java,
|
||||
cobblemonResource("slather_honey_on_log") to SlatherHoneyOnLogTaskConfig::class.java,
|
||||
)
|
||||
|
||||
val runtime = MoLangRuntime().setup()
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock
|
||||
|
||||
class SaccharineLogSensor : Sensor<PokemonEntity>(200) {
|
||||
override fun requires() = setOf(CobblemonMemories.SACCHARINE_LOG_LOCATION, CobblemonMemories.HAS_HONEY)
|
||||
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
|
||||
// Only search if we're carrying honey
|
||||
if (!brain.hasMemoryValue(CobblemonMemories.HAS_HONEY)) {
|
||||
brain.eraseMemory(CobblemonMemories.SACCHARINE_LOG_LOCATION)
|
||||
return
|
||||
}
|
||||
|
||||
val current = brain.getMemory(CobblemonMemories.SACCHARINE_LOG_LOCATION).orElse(null)
|
||||
if (current != null && isValidLog(world, entity, current)) return
|
||||
if (current != null) brain.eraseMemory(CobblemonMemories.SACCHARINE_LOG_LOCATION)
|
||||
|
||||
val searchRadius = 16
|
||||
val center = entity.blockPosition()
|
||||
var best: BlockPos? = null
|
||||
var bestDist = Double.MAX_VALUE
|
||||
|
||||
BlockPos.betweenClosedStream(
|
||||
center.offset(-searchRadius, -2, -searchRadius),
|
||||
center.offset(searchRadius, 2, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
if (state.block == CobblemonBlocks.SACCHARINE_LOG && // plain log only
|
||||
state.getValue(RotatedPillarBlock.AXIS) == Direction.Axis.Y &&
|
||||
hasReachableFace(world, entity, pos)
|
||||
) {
|
||||
val d = pos.distToCenterSqr(center.x + 0.5, center.y + 0.5, center.z + 0.5)
|
||||
if (d < bestDist) {
|
||||
bestDist = d
|
||||
best = pos.immutable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null) brain.setMemory(CobblemonMemories.SACCHARINE_LOG_LOCATION, best)
|
||||
}
|
||||
|
||||
private fun isValidLog(world: ServerLevel, entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
val state = world.getBlockState(pos)
|
||||
return state.block == CobblemonBlocks.SACCHARINE_LOG &&
|
||||
state.getValue(RotatedPillarBlock.AXIS) == Direction.Axis.Y &&
|
||||
hasReachableFace(world, entity, pos)
|
||||
}
|
||||
|
||||
private fun hasReachableFace(world: ServerLevel, entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
for (dir in Direction.Plane.HORIZONTAL) {
|
||||
val at = pos.relative(dir)
|
||||
if (world.isEmptyBlock(at)) {
|
||||
val path = entity.navigation.createPath(at, 0)
|
||||
if (path != null && path.canReach()) return true
|
||||
}
|
||||
}
|
||||
for (dir in arrayOf(Direction.UP, Direction.DOWN)) {
|
||||
val at = pos.relative(dir)
|
||||
if (world.isEmptyBlock(at)) {
|
||||
val path = entity.navigation.createPath(at, 0)
|
||||
if (path != null && path.canReach()) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -27,15 +27,23 @@ object PathToBeeHiveTask {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.POLLINATED),
|
||||
it.registered(CobblemonMemories.POLLINATED),
|
||||
it.registered(CobblemonMemories.HAS_HONEY),
|
||||
it.present(CobblemonMemories.HIVE_LOCATION),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { lookTarget, walkTarget, pollinated, hiveMemory, hiveCooldown ->
|
||||
).apply(it) { lookTarget, walkTarget, pollinated, hasHoney, hiveMemory, hiveCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val brain = entity.brain
|
||||
val hasPollinated = brain.hasMemoryValue(CobblemonMemories.POLLINATED)
|
||||
val hasHoneyMem = brain.hasMemoryValue(CobblemonMemories.HAS_HONEY)
|
||||
if (!hasPollinated && !hasHoneyMem) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val hiveLocation = it.get(hiveMemory)
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
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.phys.Vec3
|
||||
|
||||
object PathToSaccharineLogTask {
|
||||
fun create(): OneShot<in LivingEntity> = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.SACCHARINE_LOG_LOCATION),
|
||||
it.present(CobblemonMemories.HAS_HONEY)
|
||||
).apply(it) { lookTarget, walkTarget, logMem, hasHoney ->
|
||||
Trigger { world, entity, _ ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
val log = it.get(logMem)
|
||||
val target = Vec3.atCenterOf(log)
|
||||
|
||||
// if already close, let the slather task handle it
|
||||
if (entity.distanceToSqr(target) <= 2.0) return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(target, 0.35F, 0))
|
||||
lookTarget.set(BlockPosTracker(target.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.block.SaccharineLogSlatheredBlock
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
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.level.block.RotatedPillarBlock
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.random.Random
|
||||
|
||||
object SlatherHoneyOnLogTask {
|
||||
fun create(): OneShot<in LivingEntity> = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.SACCHARINE_LOG_LOCATION),
|
||||
it.present(CobblemonMemories.HAS_HONEY)
|
||||
).apply(it) { walkTarget, logMem, hasHoney ->
|
||||
Trigger { world, entity, _ ->
|
||||
if (entity !is PathfinderMob) return@Trigger false
|
||||
val pos = it.get(logMem)
|
||||
val target = Vec3.atCenterOf(pos)
|
||||
if (entity.distanceToSqr(target) > 2.0) return@Trigger false
|
||||
|
||||
val state = world.getBlockState(pos)
|
||||
if (state.block != CobblemonBlocks.SACCHARINE_LOG) return@Trigger false
|
||||
if (state.getValue(RotatedPillarBlock.AXIS) != Direction.Axis.Y) return@Trigger false
|
||||
|
||||
// pick a horizontal face with air in front
|
||||
val face = Direction.Plane.HORIZONTAL.find {
|
||||
world.getBlockState(pos.relative(it)).isAir
|
||||
} ?: return@Trigger false
|
||||
|
||||
val newState = CobblemonBlocks.SACCHARINE_LOG_SLATHERED.defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, Direction.Axis.Y)
|
||||
.setValue(SaccharineLogSlatheredBlock.HONEY_TYPE, Random.nextInt(0, SaccharineLogSlatheredBlock.HONEY_TYPE_MAX + 1))
|
||||
|
||||
world.setBlock(pos, newState, 3)
|
||||
world.playSound(null, pos, SoundEvents.HONEY_BLOCK_PLACE, SoundSource.BLOCKS, 1f, 1f)
|
||||
|
||||
entity.brain.eraseMemory(CobblemonMemories.SACCHARINE_LOG_LOCATION)
|
||||
entity.brain.eraseMemory(CobblemonMemories.HAS_HONEY)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
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.level.block.BeehiveBlock
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object StealHoneyFromHiveTask {
|
||||
fun create(): OneShot<in LivingEntity> = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.HIVE_LOCATION),
|
||||
it.absent(CobblemonMemories.HAS_HONEY),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { walkTarget, hiveMem, hasHoney, cooldown ->
|
||||
Trigger { world, entity, _ ->
|
||||
if (entity !is PathfinderMob) return@Trigger false
|
||||
val hive = it.get(hiveMem)
|
||||
val center = Vec3.atCenterOf(hive)
|
||||
if (entity.distanceToSqr(center) > 2.0) return@Trigger false
|
||||
|
||||
val state = world.getBlockState(hive)
|
||||
val block = state.block
|
||||
if (block is BeehiveBlock) {
|
||||
val level = state.getValue(BeehiveBlock.HONEY_LEVEL)
|
||||
if (level > 0) {
|
||||
world.setBlock(hive, state.setValue(BeehiveBlock.HONEY_LEVEL, level - 1), 3)
|
||||
entity.brain.setMemory(CobblemonMemories.HAS_HONEY, true)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 1200L)
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,8 @@ object PokemonBrain {
|
||||
SensorType.IS_IN_WATER,
|
||||
CobblemonSensors.NEARBY_GROWABLE_CROPS,
|
||||
CobblemonSensors.NEARBY_BEE_HIVE,
|
||||
CobblemonSensors.NEARBY_FLOWER
|
||||
CobblemonSensors.NEARBY_FLOWER,
|
||||
CobblemonSensors.NEARBY_SACCHARINE_LOG
|
||||
|
||||
// CobblemonSensors.BATTLING_POKEMON,
|
||||
// CobblemonSensors.NPC_BATTLING
|
||||
@@ -193,7 +194,8 @@ object PokemonBrain {
|
||||
CobblemonMemories.RECENTLY_ATE_GRASS,
|
||||
CobblemonMemories.HERD_LEADER,
|
||||
CobblemonMemories.HERD_SIZE,
|
||||
CobblemonMemories.ATTACK_TARGET_DATA
|
||||
CobblemonMemories.ATTACK_TARGET_DATA,
|
||||
CobblemonMemories.SACCHARINE_LOG_LOCATION
|
||||
)
|
||||
|
||||
private fun coreTasks(pokemon: Pokemon) = buildList<Pair<Int, BehaviorControl<in PokemonEntity>>> {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "cobblemon.behaviour.pokemon_honey_heist.name",
|
||||
"description": "cobblemon.behaviour.pokemon_honey_heist.desc",
|
||||
"entityType": "cobblemon:pokemon",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "cobblemon:pokemon_steal_honey",
|
||||
"condition": "!q.entity.is_in_party",
|
||||
"tasksByPriority": {
|
||||
"0": [
|
||||
{ "type": "cobblemon:activity_change",
|
||||
"activity": "minecraft:idle",
|
||||
"condition": "q.entity.has_memory_value('cobblemon:hive_cooldown')"
|
||||
}
|
||||
],
|
||||
|
||||
"2": [ "steal_honey_from_hive" ],
|
||||
"3": [ "path_to_hive" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "minecraft:idle",
|
||||
"condition": "!q.entity.is_in_party",
|
||||
"tasksByPriority": {
|
||||
"0": [
|
||||
{ "type": "cobblemon:activity_change",
|
||||
"activity": "cobblemon:pokemon_steal_honey",
|
||||
"condition": "!q.entity.has_memory_value('cobblemon:has_honey') && !q.entity.has_memory_value('cobblemon:hive_cooldown') && q.entity.has_memory_value('cobblemon:hive_location')"
|
||||
}
|
||||
],
|
||||
"1": [
|
||||
{ "type": "cobblemon:run_script", "script": "cobblemon:wander_around_hive" }
|
||||
],
|
||||
"2": [ "slather_honey_on_log" ],
|
||||
"3": [ "path_to_saccharine_log" ]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -53,7 +53,15 @@
|
||||
"canSleep": true,
|
||||
"willSleepOnBed": true,
|
||||
"light": "0-4"
|
||||
}
|
||||
},
|
||||
"ai": [
|
||||
{
|
||||
"type": "apply_behaviours",
|
||||
"behaviours": [
|
||||
"cobblemon:pokemon_honey_heist"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"drops": {
|
||||
"amount": 6,
|
||||
|
||||
Reference in New Issue
Block a user