112 lines
3.7 KiB
Rust
112 lines
3.7 KiB
Rust
use std::sync::{Arc, Weak};
|
|
|
|
use pumpkin_data::item_stack::ItemStack;
|
|
use pumpkin_data::particle::Particle;
|
|
use pumpkin_data::sound::{Sound, SoundCategory};
|
|
use pumpkin_data::{entity::EntityType, item::Item};
|
|
use pumpkin_util::math::vector3::Vector3;
|
|
|
|
use crate::entity::{
|
|
Entity, EntityBase, EntityBaseFuture, NBTStorage, NbtFuture,
|
|
ai::goal::{
|
|
breed::BreedGoal, escape_danger::EscapeDangerGoal, follow_parent::FollowParentGoal,
|
|
look_around::RandomLookAroundGoal, look_at_entity::LookAtEntityGoal, swim::SwimGoal,
|
|
tempt::TemptGoal, wander_around::WanderAroundGoal,
|
|
},
|
|
mob::{Mob, MobEntity},
|
|
player::Player,
|
|
};
|
|
use pumpkin_nbt::compound::NbtCompound;
|
|
|
|
const TEMPT_ITEMS: &[&Item] = &[&Item::WHEAT];
|
|
|
|
/// Represents a Cow, a common passive mob that provides milk, leather, and beef.
|
|
///
|
|
/// Wiki: <https://minecraft.wiki/w/Cow>
|
|
pub struct CowEntity {
|
|
pub mob_entity: MobEntity,
|
|
}
|
|
|
|
impl CowEntity {
|
|
pub async fn new(entity: Entity) -> Arc<Self> {
|
|
let mob_entity = MobEntity::new(entity);
|
|
let cow = Self { mob_entity };
|
|
let mob_arc = Arc::new(cow);
|
|
let mob_weak: Weak<dyn Mob> = {
|
|
let mob_arc: Arc<dyn Mob> = mob_arc.clone();
|
|
Arc::downgrade(&mob_arc)
|
|
};
|
|
|
|
{
|
|
let mut goal_selector = mob_arc.mob_entity.goals_selector.lock().await;
|
|
|
|
goal_selector.add_goal(0, Box::new(SwimGoal::default()));
|
|
goal_selector.add_goal(1, EscapeDangerGoal::new(2.0));
|
|
goal_selector.add_goal(2, BreedGoal::new(1.0));
|
|
goal_selector.add_goal(3, Box::new(TemptGoal::new(1.25, TEMPT_ITEMS)));
|
|
goal_selector.add_goal(4, Box::new(FollowParentGoal::new(1.25)));
|
|
goal_selector.add_goal(5, Box::new(WanderAroundGoal::new(1.0)));
|
|
goal_selector.add_goal(
|
|
6,
|
|
LookAtEntityGoal::with_default(mob_weak, &EntityType::PLAYER, 6.0),
|
|
);
|
|
goal_selector.add_goal(7, Box::new(RandomLookAroundGoal::default()));
|
|
};
|
|
|
|
mob_arc
|
|
}
|
|
}
|
|
|
|
impl NBTStorage for CowEntity {
|
|
fn write_nbt<'a>(&'a self, nbt: &'a mut NbtCompound) -> NbtFuture<'a, ()> {
|
|
self.mob_entity.living_entity.write_nbt(nbt)
|
|
}
|
|
|
|
fn read_nbt_non_mut<'a>(&'a self, nbt: &'a NbtCompound) -> NbtFuture<'a, ()> {
|
|
self.mob_entity.living_entity.read_nbt_non_mut(nbt)
|
|
}
|
|
}
|
|
|
|
impl Mob for CowEntity {
|
|
fn get_mob_entity(&self) -> &MobEntity {
|
|
&self.mob_entity
|
|
}
|
|
|
|
fn mob_interact<'a>(
|
|
&'a self,
|
|
player: &'a Arc<Player>,
|
|
item_stack: &'a mut ItemStack,
|
|
) -> EntityBaseFuture<'a, bool> {
|
|
Box::pin(async move {
|
|
let is_food = TEMPT_ITEMS.iter().any(|i| i.id == item_stack.item.id);
|
|
if is_food && self.is_breeding_ready() && !self.is_in_love() {
|
|
item_stack.decrement_unless_creative(player.gamemode.load(), 1);
|
|
|
|
self.mob_entity.set_love_ticks(600);
|
|
let entity = &self.mob_entity.living_entity.entity;
|
|
let world = entity.world.load();
|
|
let pos = entity.pos.load();
|
|
|
|
world
|
|
.spawn_particle(
|
|
pos + Vector3::new(0.0, f64::from(entity.height()), 0.0),
|
|
Vector3::new(0.5, 0.5, 0.5),
|
|
1.0,
|
|
7,
|
|
Particle::Heart,
|
|
)
|
|
.await;
|
|
world
|
|
.play_sound(
|
|
Sound::EntityCowAmbient,
|
|
SoundCategory::Neutral,
|
|
&entity.pos.load(),
|
|
)
|
|
.await;
|
|
return true;
|
|
}
|
|
false
|
|
})
|
|
}
|
|
}
|