001package net.minecraft.entity.ai;
002
003import net.minecraft.block.Block;
004import net.minecraft.block.BlockHalfSlab;
005import net.minecraft.entity.EntityCreature;
006import net.minecraft.entity.EntityLiving;
007import net.minecraft.entity.player.EntityPlayer;
008import net.minecraft.item.Item;
009import net.minecraft.item.ItemStack;
010import net.minecraft.pathfinding.PathFinder;
011import net.minecraft.pathfinding.PathPoint;
012import net.minecraft.util.MathHelper;
013
014public class EntityAIControlledByPlayer extends EntityAIBase
015{
016    private final EntityLiving thisEntity;
017    private final float maxSpeed;
018    private float currentSpeed = 0.0F;
019
020    /** Whether the entity's speed is boosted. */
021    private boolean speedBoosted = false;
022
023    /**
024     * Counter for speed boosting, upon reaching maxSpeedBoostTime the speed boost will be disabled
025     */
026    private int speedBoostTime = 0;
027
028    /** Maximum time the entity's speed should be boosted for. */
029    private int maxSpeedBoostTime = 0;
030
031    public EntityAIControlledByPlayer(EntityLiving par1EntityLiving, float par2)
032    {
033        this.thisEntity = par1EntityLiving;
034        this.maxSpeed = par2;
035        this.setMutexBits(7);
036    }
037
038    /**
039     * Execute a one shot task or start executing a continuous task
040     */
041    public void startExecuting()
042    {
043        this.currentSpeed = 0.0F;
044    }
045
046    /**
047     * Resets the task
048     */
049    public void resetTask()
050    {
051        this.speedBoosted = false;
052        this.currentSpeed = 0.0F;
053    }
054
055    /**
056     * Returns whether the EntityAIBase should begin execution.
057     */
058    public boolean shouldExecute()
059    {
060        return this.thisEntity.isEntityAlive() && this.thisEntity.riddenByEntity != null && this.thisEntity.riddenByEntity instanceof EntityPlayer && (this.speedBoosted || this.thisEntity.canBeSteered());
061    }
062
063    /**
064     * Updates the task
065     */
066    public void updateTask()
067    {
068        EntityPlayer entityplayer = (EntityPlayer)this.thisEntity.riddenByEntity;
069        EntityCreature entitycreature = (EntityCreature)this.thisEntity;
070        float f = MathHelper.wrapAngleTo180_float(entityplayer.rotationYaw - this.thisEntity.rotationYaw) * 0.5F;
071
072        if (f > 5.0F)
073        {
074            f = 5.0F;
075        }
076
077        if (f < -5.0F)
078        {
079            f = -5.0F;
080        }
081
082        this.thisEntity.rotationYaw = MathHelper.wrapAngleTo180_float(this.thisEntity.rotationYaw + f);
083
084        if (this.currentSpeed < this.maxSpeed)
085        {
086            this.currentSpeed += (this.maxSpeed - this.currentSpeed) * 0.01F;
087        }
088
089        if (this.currentSpeed > this.maxSpeed)
090        {
091            this.currentSpeed = this.maxSpeed;
092        }
093
094        int i = MathHelper.floor_double(this.thisEntity.posX);
095        int j = MathHelper.floor_double(this.thisEntity.posY);
096        int k = MathHelper.floor_double(this.thisEntity.posZ);
097        float f1 = this.currentSpeed;
098
099        if (this.speedBoosted)
100        {
101            if (this.speedBoostTime++ > this.maxSpeedBoostTime)
102            {
103                this.speedBoosted = false;
104            }
105
106            f1 += f1 * 1.15F * MathHelper.sin((float)this.speedBoostTime / (float)this.maxSpeedBoostTime * (float)Math.PI);
107        }
108
109        float f2 = 0.91F;
110
111        if (this.thisEntity.onGround)
112        {
113            f2 = 0.54600006F;
114            int l = this.thisEntity.worldObj.getBlockId(MathHelper.floor_float((float)i), MathHelper.floor_float((float)j) - 1, MathHelper.floor_float((float)k));
115
116            if (l > 0)
117            {
118                f2 = Block.blocksList[l].slipperiness * 0.91F;
119            }
120        }
121
122        float f3 = 0.16277136F / (f2 * f2 * f2);
123        float f4 = MathHelper.sin(entitycreature.rotationYaw * (float)Math.PI / 180.0F);
124        float f5 = MathHelper.cos(entitycreature.rotationYaw * (float)Math.PI / 180.0F);
125        float f6 = entitycreature.getAIMoveSpeed() * f3;
126        float f7 = Math.max(f1, 1.0F);
127        f7 = f6 / f7;
128        float f8 = f1 * f7;
129        float f9 = -(f8 * f4);
130        float f10 = f8 * f5;
131
132        if (MathHelper.abs(f9) > MathHelper.abs(f10))
133        {
134            if (f9 < 0.0F)
135            {
136                f9 -= this.thisEntity.width / 2.0F;
137            }
138
139            if (f9 > 0.0F)
140            {
141                f9 += this.thisEntity.width / 2.0F;
142            }
143
144            f10 = 0.0F;
145        }
146        else
147        {
148            f9 = 0.0F;
149
150            if (f10 < 0.0F)
151            {
152                f10 -= this.thisEntity.width / 2.0F;
153            }
154
155            if (f10 > 0.0F)
156            {
157                f10 += this.thisEntity.width / 2.0F;
158            }
159        }
160
161        int i1 = MathHelper.floor_double(this.thisEntity.posX + (double)f9);
162        int j1 = MathHelper.floor_double(this.thisEntity.posZ + (double)f10);
163        PathPoint pathpoint = new PathPoint(MathHelper.floor_float(this.thisEntity.width + 1.0F), MathHelper.floor_float(this.thisEntity.height + entityplayer.height + 1.0F), MathHelper.floor_float(this.thisEntity.width + 1.0F));
164
165        if (i != i1 || k != j1)
166        {
167            int k1 = this.thisEntity.worldObj.getBlockId(i, j, k);
168            int l1 = this.thisEntity.worldObj.getBlockId(i, j - 1, k);
169            boolean flag = this.func_98216_b(k1) || Block.blocksList[k1] == null && this.func_98216_b(l1);
170
171            if (!flag && PathFinder.func_82565_a(this.thisEntity, i1, j, j1, pathpoint, false, false, true) == 0 && PathFinder.func_82565_a(this.thisEntity, i, j + 1, k, pathpoint, false, false, true) == 1 && PathFinder.func_82565_a(this.thisEntity, i1, j + 1, j1, pathpoint, false, false, true) == 1)
172            {
173                entitycreature.getJumpHelper().setJumping();
174            }
175        }
176
177        if (!entityplayer.capabilities.isCreativeMode && this.currentSpeed >= this.maxSpeed * 0.5F && this.thisEntity.getRNG().nextFloat() < 0.006F && !this.speedBoosted)
178        {
179            ItemStack itemstack = entityplayer.getHeldItem();
180
181            if (itemstack != null && itemstack.itemID == Item.carrotOnAStick.itemID)
182            {
183                itemstack.damageItem(1, entityplayer);
184
185                if (itemstack.stackSize == 0)
186                {
187                    ItemStack itemstack1 = new ItemStack(Item.fishingRod);
188                    itemstack1.setTagCompound(itemstack.stackTagCompound);
189                    entityplayer.inventory.mainInventory[entityplayer.inventory.currentItem] = itemstack1;
190                }
191            }
192        }
193
194        this.thisEntity.moveEntityWithHeading(0.0F, f1);
195    }
196
197    private boolean func_98216_b(int par1)
198    {
199        return Block.blocksList[par1] != null && (Block.blocksList[par1].getRenderType() == 10 || Block.blocksList[par1] instanceof BlockHalfSlab);
200    }
201
202    /**
203     * Return whether the entity's speed is boosted.
204     */
205    public boolean isSpeedBoosted()
206    {
207        return this.speedBoosted;
208    }
209
210    /**
211     * Boost the entity's movement speed.
212     */
213    public void boostSpeed()
214    {
215        this.speedBoosted = true;
216        this.speedBoostTime = 0;
217        this.maxSpeedBoostTime = this.thisEntity.getRNG().nextInt(841) + 140;
218    }
219
220    /**
221     * Return whether the entity is being controlled by a player.
222     */
223    public boolean isControlledByPlayer()
224    {
225        return !this.isSpeedBoosted() && this.currentSpeed > this.maxSpeed * 0.3F;
226    }
227}