001    package net.minecraft.entity;
002    
003    import net.minecraft.pathfinding.PathEntity;
004    import net.minecraft.util.MathHelper;
005    import net.minecraft.util.Vec3;
006    import net.minecraft.world.World;
007    
008    public abstract class EntityCreature extends EntityLiving
009    {
010        private PathEntity pathToEntity;
011    
012        /** The Entity this EntityCreature is set to attack. */
013        protected Entity entityToAttack;
014    
015        /**
016         * returns true if a creature has attacked recently only used for creepers and skeletons
017         */
018        protected boolean hasAttacked = false;
019    
020        /** Used to make a creature speed up and wander away when hit. */
021        protected int fleeingTick = 0;
022    
023        public EntityCreature(World par1World)
024        {
025            super(par1World);
026        }
027    
028        /**
029         * Disables a mob's ability to move on its own while true.
030         */
031        protected boolean isMovementCeased()
032        {
033            return false;
034        }
035    
036        protected void updateEntityActionState()
037        {
038            this.worldObj.theProfiler.startSection("ai");
039    
040            if (this.fleeingTick > 0)
041            {
042                --this.fleeingTick;
043            }
044    
045            this.hasAttacked = this.isMovementCeased();
046            float var1 = 16.0F;
047    
048            if (this.entityToAttack == null)
049            {
050                this.entityToAttack = this.findPlayerToAttack();
051    
052                if (this.entityToAttack != null)
053                {
054                    this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true);
055                }
056            }
057            else if (this.entityToAttack.isEntityAlive())
058            {
059                float var2 = this.entityToAttack.getDistanceToEntity(this);
060    
061                if (this.canEntityBeSeen(this.entityToAttack))
062                {
063                    this.attackEntity(this.entityToAttack, var2);
064                }
065            }
066            else
067            {
068                this.entityToAttack = null;
069            }
070    
071            this.worldObj.theProfiler.endSection();
072    
073            if (!this.hasAttacked && this.entityToAttack != null && (this.pathToEntity == null || this.rand.nextInt(20) == 0))
074            {
075                this.pathToEntity = this.worldObj.getPathEntityToEntity(this, this.entityToAttack, var1, true, false, false, true);
076            }
077            else if (!this.hasAttacked && (this.pathToEntity == null && this.rand.nextInt(180) == 0 || this.rand.nextInt(120) == 0 || this.fleeingTick > 0) && this.entityAge < 100)
078            {
079                this.updateWanderPath();
080            }
081    
082            int var21 = MathHelper.floor_double(this.boundingBox.minY + 0.5D);
083            boolean var3 = this.isInWater();
084            boolean var4 = this.handleLavaMovement();
085            this.rotationPitch = 0.0F;
086    
087            if (this.pathToEntity != null && this.rand.nextInt(100) != 0)
088            {
089                this.worldObj.theProfiler.startSection("followpath");
090                Vec3 var5 = this.pathToEntity.getPosition(this);
091                double var6 = (double)(this.width * 2.0F);
092    
093                while (var5 != null && var5.squareDistanceTo(this.posX, var5.yCoord, this.posZ) < var6 * var6)
094                {
095                    this.pathToEntity.incrementPathIndex();
096    
097                    if (this.pathToEntity.isFinished())
098                    {
099                        var5 = null;
100                        this.pathToEntity = null;
101                    }
102                    else
103                    {
104                        var5 = this.pathToEntity.getPosition(this);
105                    }
106                }
107    
108                this.isJumping = false;
109    
110                if (var5 != null)
111                {
112                    double var8 = var5.xCoord - this.posX;
113                    double var10 = var5.zCoord - this.posZ;
114                    double var12 = var5.yCoord - (double)var21;
115                    float var14 = (float)(Math.atan2(var10, var8) * 180.0D / Math.PI) - 90.0F;
116                    float var15 = MathHelper.wrapAngleTo180_float(var14 - this.rotationYaw);
117                    this.moveForward = this.moveSpeed;
118    
119                    if (var15 > 30.0F)
120                    {
121                        var15 = 30.0F;
122                    }
123    
124                    if (var15 < -30.0F)
125                    {
126                        var15 = -30.0F;
127                    }
128    
129                    this.rotationYaw += var15;
130    
131                    if (this.hasAttacked && this.entityToAttack != null)
132                    {
133                        double var16 = this.entityToAttack.posX - this.posX;
134                        double var18 = this.entityToAttack.posZ - this.posZ;
135                        float var20 = this.rotationYaw;
136                        this.rotationYaw = (float)(Math.atan2(var18, var16) * 180.0D / Math.PI) - 90.0F;
137                        var15 = (var20 - this.rotationYaw + 90.0F) * (float)Math.PI / 180.0F;
138                        this.moveStrafing = -MathHelper.sin(var15) * this.moveForward * 1.0F;
139                        this.moveForward = MathHelper.cos(var15) * this.moveForward * 1.0F;
140                    }
141    
142                    if (var12 > 0.0D)
143                    {
144                        this.isJumping = true;
145                    }
146                }
147    
148                if (this.entityToAttack != null)
149                {
150                    this.faceEntity(this.entityToAttack, 30.0F, 30.0F);
151                }
152    
153                if (this.isCollidedHorizontally && !this.hasPath())
154                {
155                    this.isJumping = true;
156                }
157    
158                if (this.rand.nextFloat() < 0.8F && (var3 || var4))
159                {
160                    this.isJumping = true;
161                }
162    
163                this.worldObj.theProfiler.endSection();
164            }
165            else
166            {
167                super.updateEntityActionState();
168                this.pathToEntity = null;
169            }
170        }
171    
172        /**
173         * Time remaining during which the Animal is sped up and flees.
174         */
175        protected void updateWanderPath()
176        {
177            this.worldObj.theProfiler.startSection("stroll");
178            boolean var1 = false;
179            int var2 = -1;
180            int var3 = -1;
181            int var4 = -1;
182            float var5 = -99999.0F;
183    
184            for (int var6 = 0; var6 < 10; ++var6)
185            {
186                int var7 = MathHelper.floor_double(this.posX + (double)this.rand.nextInt(13) - 6.0D);
187                int var8 = MathHelper.floor_double(this.posY + (double)this.rand.nextInt(7) - 3.0D);
188                int var9 = MathHelper.floor_double(this.posZ + (double)this.rand.nextInt(13) - 6.0D);
189                float var10 = this.getBlockPathWeight(var7, var8, var9);
190    
191                if (var10 > var5)
192                {
193                    var5 = var10;
194                    var2 = var7;
195                    var3 = var8;
196                    var4 = var9;
197                    var1 = true;
198                }
199            }
200    
201            if (var1)
202            {
203                this.pathToEntity = this.worldObj.getEntityPathToXYZ(this, var2, var3, var4, 10.0F, true, false, false, true);
204            }
205    
206            this.worldObj.theProfiler.endSection();
207        }
208    
209        /**
210         * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack.
211         */
212        protected void attackEntity(Entity par1Entity, float par2) {}
213    
214        /**
215         * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block.
216         * Args: x, y, z
217         */
218        public float getBlockPathWeight(int par1, int par2, int par3)
219        {
220            return 0.0F;
221        }
222    
223        /**
224         * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking
225         * (Animals, Spiders at day, peaceful PigZombies).
226         */
227        protected Entity findPlayerToAttack()
228        {
229            return null;
230        }
231    
232        /**
233         * Checks if the entity's current position is a valid location to spawn this entity.
234         */
235        public boolean getCanSpawnHere()
236        {
237            int var1 = MathHelper.floor_double(this.posX);
238            int var2 = MathHelper.floor_double(this.boundingBox.minY);
239            int var3 = MathHelper.floor_double(this.posZ);
240            return super.getCanSpawnHere() && this.getBlockPathWeight(var1, var2, var3) >= 0.0F;
241        }
242    
243        /**
244         * Returns true if entity has a path to follow
245         */
246        public boolean hasPath()
247        {
248            return this.pathToEntity != null;
249        }
250    
251        /**
252         * sets the Entities walk path in EntityCreature
253         */
254        public void setPathToEntity(PathEntity par1PathEntity)
255        {
256            this.pathToEntity = par1PathEntity;
257        }
258    
259        /**
260         * Returns current entities target
261         */
262        public Entity getEntityToAttack()
263        {
264            return this.entityToAttack;
265        }
266    
267        /**
268         * Sets the entity which is to be attacked.
269         */
270        public void setTarget(Entity par1Entity)
271        {
272            this.entityToAttack = par1Entity;
273        }
274    
275        /**
276         * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
277         * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
278         */
279        public float getSpeedModifier()
280        {
281            float var1 = super.getSpeedModifier();
282    
283            if (this.fleeingTick > 0 && !this.isAIEnabled())
284            {
285                var1 *= 2.0F;
286            }
287    
288            return var1;
289        }
290    }