    001package net.minecraft.entity;
    002
    003import net.minecraft.pathfinding.PathEntity;
    004import net.minecraft.util.MathHelper;
    005import net.minecraft.util.Vec3;
    006import net.minecraft.world.World;
    007
    008public 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 f = 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, f, true, false, false, true);
    055            }
    056        }
    057        else if (this.entityToAttack.isEntityAlive())
    058        {
    059            float f1 = this.entityToAttack.getDistanceToEntity(this);
    060
    061            if (this.canEntityBeSeen(this.entityToAttack))
    062            {
    063                this.attackEntity(this.entityToAttack, f1);
    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, f, 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 i = MathHelper.floor_double(this.boundingBox.minY + 0.5D);
    083        boolean flag = this.isInWater();
    084        boolean flag1 = 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 vec3 = this.pathToEntity.getPosition(this);
    091            double d0 = (double)(this.width * 2.0F);
    092
    093            while (vec3 != null && vec3.squareDistanceTo(this.posX, vec3.yCoord, this.posZ) < d0 * d0)
    094            {
    095                this.pathToEntity.incrementPathIndex();
    096
    097                if (this.pathToEntity.isFinished())
    098                {
    099                    vec3 = null;
    100                    this.pathToEntity = null;
    101                }
    102                else
    103                {
    104                    vec3 = this.pathToEntity.getPosition(this);
    105                }
    106            }
    107
    108            this.isJumping = false;
    109
    110            if (vec3 != null)
    111            {
    112                double d1 = vec3.xCoord - this.posX;
    113                double d2 = vec3.zCoord - this.posZ;
    114                double d3 = vec3.yCoord - (double)i;
    115                float f2 = (float)(Math.atan2(d2, d1) * 180.0D / Math.PI) - 90.0F;
    116                float f3 = MathHelper.wrapAngleTo180_float(f2 - this.rotationYaw);
    117                this.moveForward = this.moveSpeed;
    118
    119                if (f3 > 30.0F)
    120                {
    121                    f3 = 30.0F;
    122                }
    123
    124                if (f3 < -30.0F)
    125                {
    126                    f3 = -30.0F;
    127                }
    128
    129                this.rotationYaw += f3;
    130
    131                if (this.hasAttacked && this.entityToAttack != null)
    132                {
    133                    double d4 = this.entityToAttack.posX - this.posX;
    134                    double d5 = this.entityToAttack.posZ - this.posZ;
    135                    float f4 = this.rotationYaw;
    136                    this.rotationYaw = (float)(Math.atan2(d5, d4) * 180.0D / Math.PI) - 90.0F;
    137                    f3 = (f4 - this.rotationYaw + 90.0F) * (float)Math.PI / 180.0F;
    138                    this.moveStrafing = -MathHelper.sin(f3) * this.moveForward * 1.0F;
    139                    this.moveForward = MathHelper.cos(f3) * this.moveForward * 1.0F;
    140                }
    141
    142                if (d3 > 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 && (flag || flag1))
    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 flag = false;
    179        int i = -1;
    180        int j = -1;
    181        int k = -1;
    182        float f = -99999.0F;
    183
    184        for (int l = 0; l < 10; ++l)
    185        {
    186            int i1 = MathHelper.floor_double(this.posX + (double)this.rand.nextInt(13) - 6.0D);
    187            int j1 = MathHelper.floor_double(this.posY + (double)this.rand.nextInt(7) - 3.0D);
    188            int k1 = MathHelper.floor_double(this.posZ + (double)this.rand.nextInt(13) - 6.0D);
    189            float f1 = this.getBlockPathWeight(i1, j1, k1);
    190
    191            if (f1 > f)
    192            {
    193                f = f1;
    194                i = i1;
    195                j = j1;
    196                k = k1;
    197                flag = true;
    198            }
    199        }
    200
    201        if (flag)
    202        {
    203            this.pathToEntity = this.worldObj.getEntityPathToXYZ(this, i, j, k, 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 i = MathHelper.floor_double(this.posX);
    238        int j = MathHelper.floor_double(this.boundingBox.minY);
    239        int k = MathHelper.floor_double(this.posZ);
    240        return super.getCanSpawnHere() && this.getBlockPathWeight(i, j, k) >= 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 f = super.getSpeedModifier();
    282
    283        if (this.fleeingTick > 0 && !this.isAIEnabled())
    284        {
    285            f *= 2.0F;
    286        }
    287
    288        return f;
    289    }
    290}