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