    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    }