mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 22:56:23 -04:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9318be9a17 |
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object CobblemonMemories {
|
||||
@@ -60,6 +61,7 @@ object CobblemonMemories {
|
||||
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
val RECENT_CATCH_ATTEMPT = register<UUID>("recent_catch_attempt")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.config.task.EatGrassTaskConfig.Companion.EATING_GRASS
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.FiteMeSoyBoyTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class FiteThrowerTaskConfig : SingleTaskConfig {
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
behaviourConfigurationContext.addMemories(CobblemonMemories.RECENT_CATCH_ATTEMPT)
|
||||
|
||||
return WrapperLivingEntityTask(
|
||||
FiteMeSoyBoyTask(),
|
||||
PokemonEntity::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> = emptyList()
|
||||
}
|
||||
@@ -120,6 +120,7 @@ interface TaskConfig {
|
||||
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
|
||||
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
|
||||
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
|
||||
cobblemonResource("fite_me_soy_boy") to FiteThrowerTaskConfig::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+41
-35
@@ -13,6 +13,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonEntities.EMPTY_POKEBALL
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokeball.PokeBallCaptureCalculatedEvent
|
||||
@@ -72,8 +73,8 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.EntityHitResult
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragModifier, Schedulable {
|
||||
@@ -178,21 +179,30 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
var pokeBall: PokeBall = PokeBalls.POKE_BALL
|
||||
|
||||
|
||||
override fun onHitBlock(hitResult: BlockHitResult) {
|
||||
if (captureState == CaptureState.NOT) {
|
||||
if (level().isServerSide()) {
|
||||
super.onHitBlock(hitResult)
|
||||
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
|
||||
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
|
||||
discard()
|
||||
val player = this.owner as? ServerPlayer
|
||||
if (player?.isCreative == false) {
|
||||
spawnAtLocation(defaultItem)
|
||||
when (captureState) {
|
||||
CaptureState.FALL -> {
|
||||
if (level().isServerSide()) {
|
||||
beginCapture()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setNoGravity(false)
|
||||
deltaMovement = Vec3.ZERO
|
||||
CaptureState.NOT -> {
|
||||
if (level().isServerSide()) {
|
||||
super.onHitBlock(hitResult)
|
||||
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
|
||||
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
|
||||
discard()
|
||||
val player = this.owner as? ServerPlayer
|
||||
if (player?.isCreative == false) {
|
||||
spawnAtLocation(defaultItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
isNoGravity = false
|
||||
deltaMovement = Vec3.ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,15 +225,14 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
}
|
||||
|
||||
if (battle != null && owner != null && owner is LivingEntity) {
|
||||
val throwerActor = battle.getActor(owner.uuid)
|
||||
val throwerActor = battle.getActor(owner.uuid) ?: run {
|
||||
owner.sendSystemMessage(lang("capture.in_battle", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return onHitEntity@drop()
|
||||
}
|
||||
|
||||
val hitActor = battle.actors.find { it.isForPokemon(pokemonEntity) }
|
||||
val hitBattlePokemon = hitActor?.activePokemon?.find { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
|
||||
|
||||
if (throwerActor == null) {
|
||||
owner.sendSystemMessage(lang("capture.in_battle", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
}
|
||||
|
||||
if (hitActor == null || hitBattlePokemon == null) {
|
||||
return drop() // Weird, shouldn't be possible
|
||||
}
|
||||
@@ -254,6 +263,9 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
} else if (pokemonEntity.isBusy) {
|
||||
owner?.sendSystemMessage(lang("capture.busy", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
} else if (battle == null && pokemonEntity.brain.hasMemoryValue(CobblemonMemories.RECENT_CATCH_ATTEMPT)) {
|
||||
pokemonEntity.playAnimation("cry")
|
||||
return drop()
|
||||
} else if (owner is ServerPlayer && BattleRegistry.getBattleByParticipatingPlayer(owner) != null) {
|
||||
owner.sendSystemMessage(lang("you_in_battle").red())
|
||||
return drop()
|
||||
@@ -456,7 +468,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
after(seconds = 0.7F) {
|
||||
// Start beaming them up.
|
||||
deltaMovement = Vec3.ZERO
|
||||
setNoGravity(true)
|
||||
isNoGravity = true
|
||||
level().playSoundServer(position(), CobblemonSounds.POKE_BALL_RECALL, volume = 0.6F)
|
||||
pokemonEntity.beamMode = 3
|
||||
}
|
||||
@@ -471,7 +483,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
// If it was still falling after a second and a half, just assume it's landed because we can't wait all day.
|
||||
if (captureState == CaptureState.FALL) {
|
||||
deltaMovement = Vec3.ZERO
|
||||
setNoGravity(true)
|
||||
isNoGravity = true
|
||||
setOnGround(true)
|
||||
beginCapture()
|
||||
}
|
||||
@@ -479,21 +491,14 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHit(hitResult: HitResult) {
|
||||
super.onHit(hitResult)
|
||||
if (captureState == CaptureState.FALL && hitResult.type == HitResult.Type.BLOCK) {
|
||||
if (level().isServerSide()) {
|
||||
beginCapture()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
|
||||
fun beginCapture() {
|
||||
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
|
||||
capturingPokemon?.setPositionSafely(position())
|
||||
val capturingPokemon = this.capturingPokemon ?: return
|
||||
capturingPokemon.setPositionSafely(position())
|
||||
|
||||
val thrower = owner as LivingEntity
|
||||
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon!!).let {
|
||||
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon!!, pokeBallEntity = this, captureResult = it)
|
||||
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon).let {
|
||||
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon, pokeBallEntity = this, captureResult = it)
|
||||
CobblemonEvents.POKE_BALL_CAPTURE_CALCULATED.post(event)
|
||||
event.captureResult
|
||||
}
|
||||
@@ -530,11 +535,12 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun getCurrentPoseType(): PoseType {
|
||||
return PoseType.NONE
|
||||
}
|
||||
|
||||
override fun canUsePortal(allowVehicles: Boolean) = false
|
||||
override fun canUsePortal(allowVehicles: Boolean) = captureState == CaptureState.NOT
|
||||
|
||||
override fun getAddEntityPacket(entityTrackerEntry: ServerEntity): Packet<ClientGamePacketListener> =
|
||||
ClientboundCustomPayloadPacket(
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.EntityTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
|
||||
class FiteMeSoyBoyTask : Behavior<PokemonEntity>(
|
||||
ImmutableMap.of(
|
||||
CobblemonMemories.RECENT_CATCH_ATTEMPT, MemoryStatus.VALUE_PRESENT,
|
||||
)
|
||||
) {
|
||||
companion object {
|
||||
private const val ATTACK_RANGE = 6.0
|
||||
private const val SPEED = 1.0f
|
||||
}
|
||||
|
||||
private var targetEntity: Optional<ServerPlayer> = Optional.empty()
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, entity: PokemonEntity): Boolean {
|
||||
this.targetEntity = findSoyBoy(level, entity)
|
||||
return targetEntity.isPresent
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: PokemonEntity, gameTime: Long): Boolean
|
||||
= targetEntity.map { it.isAlive }.orElse(false)
|
||||
&& entity.brain.hasMemoryValue(CobblemonMemories.RECENT_CATCH_ATTEMPT)
|
||||
|
||||
private fun findSoyBoy(level: ServerLevel, entity: PokemonEntity): Optional<ServerPlayer> {
|
||||
val soyBoyUuid = entity.brain.getMemory(CobblemonMemories.RECENT_CATCH_ATTEMPT)?.get() ?: return Optional.empty()
|
||||
return level.players()
|
||||
.find { it.uuid == soyBoyUuid }
|
||||
?.let { Optional.of(it) } ?: Optional.empty()
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: PokemonEntity, gameTime: Long) {
|
||||
addLookWalkTargets(entity)
|
||||
super.start(level, entity, gameTime)
|
||||
}
|
||||
|
||||
private fun addLookWalkTargets(entity: LivingEntity) {
|
||||
targetEntity.ifPresent {
|
||||
val lookTarget = EntityTracker(it, true)
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET, lookTarget)
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET, WalkTarget(lookTarget, SPEED, 1))
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: PokemonEntity, gameTime: Long) {
|
||||
targetEntity = Optional.empty()
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, entity: PokemonEntity, gameTime: Long) {
|
||||
if (targetEntity.isPresent && entity.hasLineOfSight(targetEntity.get())) {
|
||||
val soyBoy = targetEntity.get()
|
||||
if (soyBoy.isAlive) {
|
||||
if (entity.distanceToSqr(soyBoy) <= ATTACK_RANGE * ATTACK_RANGE) {
|
||||
if (entity.forceBattle(soyBoy)) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.RECENT_CATCH_ATTEMPT)
|
||||
}
|
||||
} else {
|
||||
addLookWalkTargets(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,7 +201,8 @@ object PokemonBrain {
|
||||
CobblemonMemories.HERD_LEADER,
|
||||
CobblemonMemories.HERD_SIZE,
|
||||
CobblemonMemories.ATTACK_TARGET_DATA,
|
||||
CobblemonMemories.NEARBY_SWEET_BERRY_BUSH
|
||||
CobblemonMemories.NEARBY_SWEET_BERRY_BUSH,
|
||||
CobblemonMemories.RECENT_CATCH_ATTEMPT
|
||||
)
|
||||
|
||||
private fun coreTasks(pokemon: Pokemon) = buildList<Pair<Int, BehaviorControl<in PokemonEntity>>> {
|
||||
@@ -209,10 +210,12 @@ object PokemonBrain {
|
||||
add(0 toDF StayAfloatTask(0.8F))
|
||||
}
|
||||
|
||||
add(0 toDF FiteMeSoyBoyTask())
|
||||
|
||||
if (pokemon.form.behaviour.combat.willDefendSelf) {
|
||||
add(0 toDF GetAngryAtAttackerTask.create())
|
||||
add(1 toDF GetAngryAtAttackerTask.create())
|
||||
} else {
|
||||
add(0 toDF FleeFromAttackerTask.create("600".asExpression()))
|
||||
add(1 toDF FleeFromAttackerTask.create("600".asExpression()))
|
||||
}
|
||||
|
||||
add(0 toDF StopBeingAngryIfTargetDead.create())
|
||||
|
||||
@@ -3757,6 +3757,9 @@
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.name": "Picks Up Items",
|
||||
"cobblemon.behaviour.pokemon_picks_up_items.desc": "The Pokémon will pick up items that it cares about.",
|
||||
|
||||
"cobblemon.behaviour.pokemon_fites_thrower.name": "Fite Poké Ball Thrower",
|
||||
"cobblemon.behaviour.pokemon_fites_thrower.desc": "Fite me, soy boy!",
|
||||
|
||||
"npc.sacchi.name": "Professor Sacchi",
|
||||
|
||||
"cobblemon.move.pound": "Pound",
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "cobblemon.behaviour.pokemon_fites_thrower.name",
|
||||
"description": "cobblemon.behaviour.pokemon_fites_thrower.desc",
|
||||
"entityType": "cobblemon:pokemon",
|
||||
"onAdd": "q.entity.add_callback('cobblemon:hit_by_pokeball', 'cobblemon:fite_thrower');",
|
||||
"onRemove": "q.entity.remove_callback('cobblemon:hit_by_pokeball', 'cobblemon:fite_thrower');",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "add_memories_and_sensors",
|
||||
"memories": [
|
||||
"cobblemon:recent_catch_attempt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "core",
|
||||
"tasksByPriority": {
|
||||
"0": [
|
||||
"cobblemon:fite_me_soy_boy"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"switch_to_fight"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "fight",
|
||||
"tasksByPriority": {
|
||||
"3": [
|
||||
"switch_from_fight"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
t.thrower = q.pokeball.thrower;
|
||||
t.thrower != 0 ? {
|
||||
'Set the entity memory to try engaging the thrower in battle for the next 30 seconds';
|
||||
q.entity.set_uuid_memory('cobblemon:recent_catch_attempt', t.thrower.uuid, 20 * 60);
|
||||
};
|
||||
Reference in New Issue
Block a user