001 package net.minecraft.entity.ai;
002
003 import java.util.Iterator;
004 import java.util.List;
005 import java.util.Random;
006 import net.minecraft.entity.EntityAgeable;
007 import net.minecraft.entity.item.EntityXPOrb;
008 import net.minecraft.entity.passive.EntityAnimal;
009 import net.minecraft.world.World;
010
011 public class EntityAIMate extends EntityAIBase
012 {
013 private EntityAnimal theAnimal;
014 World theWorld;
015 private EntityAnimal targetMate;
016
017 /**
018 * Delay preventing a baby from spawning immediately when two mate-able animals find each other.
019 */
020 int spawnBabyDelay = 0;
021
022 /** The speed the creature moves at during mating behavior. */
023 float moveSpeed;
024
025 public EntityAIMate(EntityAnimal par1EntityAnimal, float par2)
026 {
027 this.theAnimal = par1EntityAnimal;
028 this.theWorld = par1EntityAnimal.worldObj;
029 this.moveSpeed = par2;
030 this.setMutexBits(3);
031 }
032
033 /**
034 * Returns whether the EntityAIBase should begin execution.
035 */
036 public boolean shouldExecute()
037 {
038 if (!this.theAnimal.isInLove())
039 {
040 return false;
041 }
042 else
043 {
044 this.targetMate = this.getNearbyMate();
045 return this.targetMate != null;
046 }
047 }
048
049 /**
050 * Returns whether an in-progress EntityAIBase should continue executing
051 */
052 public boolean continueExecuting()
053 {
054 return this.targetMate.isEntityAlive() && this.targetMate.isInLove() && this.spawnBabyDelay < 60;
055 }
056
057 /**
058 * Resets the task
059 */
060 public void resetTask()
061 {
062 this.targetMate = null;
063 this.spawnBabyDelay = 0;
064 }
065
066 /**
067 * Updates the task
068 */
069 public void updateTask()
070 {
071 this.theAnimal.getLookHelper().setLookPositionWithEntity(this.targetMate, 10.0F, (float)this.theAnimal.getVerticalFaceSpeed());
072 this.theAnimal.getNavigator().tryMoveToEntityLiving(this.targetMate, this.moveSpeed);
073 ++this.spawnBabyDelay;
074
075 if (this.spawnBabyDelay == 60)
076 {
077 this.spawnBaby();
078 }
079 }
080
081 /**
082 * Loops through nearby animals and finds another animal of the same type that can be mated with. Returns the first
083 * valid mate found.
084 */
085 private EntityAnimal getNearbyMate()
086 {
087 float var1 = 8.0F;
088 List var2 = this.theWorld.getEntitiesWithinAABB(this.theAnimal.getClass(), this.theAnimal.boundingBox.expand((double)var1, (double)var1, (double)var1));
089 Iterator var3 = var2.iterator();
090 EntityAnimal var4;
091
092 do
093 {
094 if (!var3.hasNext())
095 {
096 return null;
097 }
098
099 var4 = (EntityAnimal)var3.next();
100 }
101 while (!this.theAnimal.canMateWith(var4));
102
103 return var4;
104 }
105
106 /**
107 * Spawns a baby animal of the same type.
108 */
109 private void spawnBaby()
110 {
111 EntityAgeable var1 = this.theAnimal.createChild(this.targetMate);
112
113 if (var1 != null)
114 {
115 this.theAnimal.setGrowingAge(6000);
116 this.targetMate.setGrowingAge(6000);
117 this.theAnimal.resetInLove();
118 this.targetMate.resetInLove();
119 var1.setGrowingAge(-24000);
120 var1.setLocationAndAngles(this.theAnimal.posX, this.theAnimal.posY, this.theAnimal.posZ, 0.0F, 0.0F);
121 this.theWorld.spawnEntityInWorld(var1);
122 Random var2 = this.theAnimal.getRNG();
123
124 for (int var3 = 0; var3 < 7; ++var3)
125 {
126 double var4 = var2.nextGaussian() * 0.02D;
127 double var6 = var2.nextGaussian() * 0.02D;
128 double var8 = var2.nextGaussian() * 0.02D;
129 this.theWorld.spawnParticle("heart", this.theAnimal.posX + (double)(var2.nextFloat() * this.theAnimal.width * 2.0F) - (double)this.theAnimal.width, this.theAnimal.posY + 0.5D + (double)(var2.nextFloat() * this.theAnimal.height), this.theAnimal.posZ + (double)(var2.nextFloat() * this.theAnimal.width * 2.0F) - (double)this.theAnimal.width, var4, var6, var8);
130 }
131
132 this.theWorld.spawnEntityInWorld(new EntityXPOrb(this.theWorld, this.theAnimal.posX, this.theAnimal.posY, this.theAnimal.posZ, var2.nextInt(7) + 1));
133 }
134 }
135 }