    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        public float getSpeedModifier()
    275        {
    276            float var1 = super.getSpeedModifier();
    277
    278            if (this.fleeingTick > 0 && !this.isAIEnabled())
    279            {
    280                var1 *= 2.0F;
    281            }
    282
    283            return var1;
    284        }
    285    }