    001    package net.minecraft.src;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import java.util.List;
    006
    007    public class EntityWither extends EntityMob implements IBossDisplayData, IRangedAttackMob
    008    {
    009        private float[] field_82220_d = new float[2];
    010        private float[] field_82221_e = new float[2];
    011        private float[] field_82217_f = new float[2];
    012        private float[] field_82218_g = new float[2];
    013        private int[] field_82223_h = new int[2];
    014        private int[] field_82224_i = new int[2];
    015        private int field_82222_j;
    016        private static final IEntitySelector field_82219_bJ = new EntityWitherAttackFilter();
    017
    018        public EntityWither(World par1World)
    019        {
    020            super(par1World);
    021            this.setEntityHealth(this.getMaxHealth());
    022            this.texture = "/mob/wither.png";
    023            this.setSize(0.9F, 4.0F);
    024            this.isImmuneToFire = true;
    025            this.moveSpeed = 0.6F;
    026            this.getNavigator().setCanSwim(true);
    027            this.tasks.addTask(0, new EntityAISwimming(this));
    028            this.tasks.addTask(2, new EntityAIArrowAttack(this, this.moveSpeed, 40, 20.0F));
    029            this.tasks.addTask(5, new EntityAIWander(this, this.moveSpeed));
    030            this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
    031            this.tasks.addTask(7, new EntityAILookIdle(this));
    032            this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
    033            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 30.0F, 0, false, false, field_82219_bJ));
    034            this.experienceValue = 50;
    035        }
    036
    037        protected void entityInit()
    038        {
    039            super.entityInit();
    040            this.dataWatcher.addObject(16, new Integer(100));
    041            this.dataWatcher.addObject(17, new Integer(0));
    042            this.dataWatcher.addObject(18, new Integer(0));
    043            this.dataWatcher.addObject(19, new Integer(0));
    044            this.dataWatcher.addObject(20, new Integer(0));
    045        }
    046
    047        /**
    048         * (abstract) Protected helper method to write subclass entity data to NBT.
    049         */
    050        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    051        {
    052            super.writeEntityToNBT(par1NBTTagCompound);
    053            par1NBTTagCompound.setInteger("Invul", this.func_82212_n());
    054        }
    055
    056        /**
    057         * (abstract) Protected helper method to read subclass entity data from NBT.
    058         */
    059        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    060        {
    061            super.readEntityFromNBT(par1NBTTagCompound);
    062            this.func_82215_s(par1NBTTagCompound.getInteger("Invul"));
    063            this.dataWatcher.updateObject(16, Integer.valueOf(this.health));
    064        }
    065
    066        @SideOnly(Side.CLIENT)
    067        public float getShadowSize()
    068        {
    069            return this.height / 8.0F;
    070        }
    071
    072        /**
    073         * Returns the sound this mob makes while it's alive.
    074         */
    075        protected String getLivingSound()
    076        {
    077            return "mob.wither.idle";
    078        }
    079
    080        /**
    081         * Returns the sound this mob makes when it is hurt.
    082         */
    083        protected String getHurtSound()
    084        {
    085            return "mob.wither.hurt";
    086        }
    087
    088        /**
    089         * Returns the sound this mob makes on death.
    090         */
    091        protected String getDeathSound()
    092        {
    093            return "mob.wither.death";
    094        }
    095
    096        @SideOnly(Side.CLIENT)
    097
    098        /**
    099         * Returns the texture's file path as a String.
    100         */
    101        public String getTexture()
    102        {
    103            int var1 = this.func_82212_n();
    104            return var1 > 0 && (var1 > 80 || var1 / 5 % 2 != 1) ? "/mob/wither_invul.png" : "/mob/wither.png";
    105        }
    106
    107        /**
    108         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
    109         * use this to react to sunlight and start to burn.
    110         */
    111        public void onLivingUpdate()
    112        {
    113            if (!this.worldObj.isRemote)
    114            {
    115                this.dataWatcher.updateObject(16, Integer.valueOf(this.health));
    116            }
    117
    118            this.motionY *= 0.6000000238418579D;
    119            double var4;
    120            double var6;
    121            double var8;
    122
    123            if (!this.worldObj.isRemote && this.func_82203_t(0) > 0)
    124            {
    125                Entity var1 = this.worldObj.getEntityByID(this.func_82203_t(0));
    126
    127                if (var1 != null)
    128                {
    129                    if (this.posY < var1.posY || !this.func_82205_o() && this.posY < var1.posY + 5.0D)
    130                    {
    131                        if (this.motionY < 0.0D)
    132                        {
    133                            this.motionY = 0.0D;
    134                        }
    135
    136                        this.motionY += (0.5D - this.motionY) * 0.6000000238418579D;
    137                    }
    138
    139                    double var2 = var1.posX - this.posX;
    140                    var4 = var1.posZ - this.posZ;
    141                    var6 = var2 * var2 + var4 * var4;
    142
    143                    if (var6 > 9.0D)
    144                    {
    145                        var8 = (double)MathHelper.sqrt_double(var6);
    146                        this.motionX += (var2 / var8 * 0.5D - this.motionX) * 0.6000000238418579D;
    147                        this.motionZ += (var4 / var8 * 0.5D - this.motionZ) * 0.6000000238418579D;
    148                    }
    149                }
    150            }
    151
    152            if (this.motionX * this.motionX + this.motionZ * this.motionZ > 0.05000000074505806D)
    153            {
    154                this.rotationYaw = (float)Math.atan2(this.motionZ, this.motionX) * (180F / (float)Math.PI) - 90.0F;
    155            }
    156
    157            super.onLivingUpdate();
    158            int var20;
    159
    160            for (var20 = 0; var20 < 2; ++var20)
    161            {
    162                this.field_82218_g[var20] = this.field_82221_e[var20];
    163                this.field_82217_f[var20] = this.field_82220_d[var20];
    164            }
    165
    166            int var21;
    167
    168            for (var20 = 0; var20 < 2; ++var20)
    169            {
    170                var21 = this.func_82203_t(var20 + 1);
    171                Entity var3 = null;
    172
    173                if (var21 > 0)
    174                {
    175                    var3 = this.worldObj.getEntityByID(var21);
    176                }
    177
    178                if (var3 != null)
    179                {
    180                    var4 = this.func_82214_u(var20 + 1);
    181                    var6 = this.func_82208_v(var20 + 1);
    182                    var8 = this.func_82213_w(var20 + 1);
    183                    double var10 = var3.posX - var4;
    184                    double var12 = var3.posY + (double)var3.getEyeHeight() - var6;
    185                    double var14 = var3.posZ - var8;
    186                    double var16 = (double)MathHelper.sqrt_double(var10 * var10 + var14 * var14);
    187                    float var18 = (float)(Math.atan2(var14, var10) * 180.0D / Math.PI) - 90.0F;
    188                    float var19 = (float)(-(Math.atan2(var12, var16) * 180.0D / Math.PI));
    189                    this.field_82220_d[var20] = this.func_82204_b(this.field_82220_d[var20], var19, 40.0F);
    190                    this.field_82221_e[var20] = this.func_82204_b(this.field_82221_e[var20], var18, 10.0F);
    191                }
    192                else
    193                {
    194                    this.field_82221_e[var20] = this.func_82204_b(this.field_82221_e[var20], this.renderYawOffset, 10.0F);
    195                }
    196            }
    197
    198            boolean var22 = this.func_82205_o();
    199
    200            for (var21 = 0; var21 < 3; ++var21)
    201            {
    202                double var23 = this.func_82214_u(var21);
    203                double var5 = this.func_82208_v(var21);
    204                double var7 = this.func_82213_w(var21);
    205                this.worldObj.spawnParticle("smoke", var23 + this.rand.nextGaussian() * 0.30000001192092896D, var5 + this.rand.nextGaussian() * 0.30000001192092896D, var7 + this.rand.nextGaussian() * 0.30000001192092896D, 0.0D, 0.0D, 0.0D);
    206
    207                if (var22 && this.worldObj.rand.nextInt(4) == 0)
    208                {
    209                    this.worldObj.spawnParticle("mobSpell", var23 + this.rand.nextGaussian() * 0.30000001192092896D, var5 + this.rand.nextGaussian() * 0.30000001192092896D, var7 + this.rand.nextGaussian() * 0.30000001192092896D, 0.699999988079071D, 0.699999988079071D, 0.5D);
    210                }
    211            }
    212
    213            if (this.func_82212_n() > 0)
    214            {
    215                for (var21 = 0; var21 < 3; ++var21)
    216                {
    217                    this.worldObj.spawnParticle("mobSpell", this.posX + this.rand.nextGaussian() * 1.0D, this.posY + (double)(this.rand.nextFloat() * 3.3F), this.posZ + this.rand.nextGaussian() * 1.0D, 0.699999988079071D, 0.699999988079071D, 0.8999999761581421D);
    218                }
    219            }
    220        }
    221
    222        protected void updateAITasks()
    223        {
    224            int var1;
    225
    226            if (this.func_82212_n() > 0)
    227            {
    228                var1 = this.func_82212_n() - 1;
    229
    230                if (var1 <= 0)
    231                {
    232                    this.worldObj.newExplosion(this, this.posX, this.posY + (double)this.getEyeHeight(), this.posZ, 7.0F, false, this.worldObj.func_82736_K().func_82766_b("mobGriefing"));
    233                    this.worldObj.func_82739_e(1013, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    234                }
    235
    236                this.func_82215_s(var1);
    237
    238                if (this.ticksExisted % 10 == 0)
    239                {
    240                    this.heal(10);
    241                }
    242            }
    243            else
    244            {
    245                super.updateAITasks();
    246                int var13;
    247
    248                for (var1 = 1; var1 < 3; ++var1)
    249                {
    250                    if (this.ticksExisted >= this.field_82223_h[var1 - 1])
    251                    {
    252                        this.field_82223_h[var1 - 1] = this.ticksExisted + 10 + this.rand.nextInt(10);
    253
    254                        if (this.worldObj.difficultySetting >= 2)
    255                        {
    256                            int var10001 = var1 - 1;
    257                            int var10003 = this.field_82224_i[var1 - 1];
    258                            this.field_82224_i[var10001] = this.field_82224_i[var1 - 1] + 1;
    259
    260                            if (var10003 > 15)
    261                            {
    262                                float var2 = 10.0F;
    263                                float var3 = 5.0F;
    264                                double var4 = MathHelper.func_82716_a(this.rand, this.posX - (double)var2, this.posX + (double)var2);
    265                                double var6 = MathHelper.func_82716_a(this.rand, this.posY - (double)var3, this.posY + (double)var3);
    266                                double var8 = MathHelper.func_82716_a(this.rand, this.posZ - (double)var2, this.posZ + (double)var2);
    267                                this.func_82209_a(var1 + 1, var4, var6, var8, true);
    268                                this.field_82224_i[var1 - 1] = 0;
    269                            }
    270                        }
    271
    272                        var13 = this.func_82203_t(var1);
    273
    274                        if (var13 > 0)
    275                        {
    276                            Entity var15 = this.worldObj.getEntityByID(var13);
    277
    278                            if (var15 != null && var15.isEntityAlive() && this.getDistanceSqToEntity(var15) <= 900.0D && this.canEntityBeSeen(var15))
    279                            {
    280                                this.func_82216_a(var1 + 1, (EntityLiving)var15);
    281                                this.field_82223_h[var1 - 1] = this.ticksExisted + 40 + this.rand.nextInt(20);
    282                                this.field_82224_i[var1 - 1] = 0;
    283                            }
    284                            else
    285                            {
    286                                this.func_82211_c(var1, 0);
    287                            }
    288                        }
    289                        else
    290                        {
    291                            List var14 = this.worldObj.func_82733_a(EntityLiving.class, this.boundingBox.expand(20.0D, 8.0D, 20.0D), field_82219_bJ);
    292
    293                            for (int var17 = 0; var17 < 10 && !var14.isEmpty(); ++var17)
    294                            {
    295                                EntityLiving var5 = (EntityLiving)var14.get(this.rand.nextInt(var14.size()));
    296
    297                                if (var5 != this && var5.isEntityAlive() && this.canEntityBeSeen(var5))
    298                                {
    299                                    if (var5 instanceof EntityPlayer)
    300                                    {
    301                                        if (!((EntityPlayer)var5).capabilities.disableDamage)
    302                                        {
    303                                            this.func_82211_c(var1, var5.entityId);
    304                                        }
    305                                    }
    306                                    else
    307                                    {
    308                                        this.func_82211_c(var1, var5.entityId);
    309                                    }
    310
    311                                    break;
    312                                }
    313
    314                                var14.remove(var5);
    315                            }
    316                        }
    317                    }
    318                }
    319
    320                if (this.getAttackTarget() != null)
    321                {
    322                    this.func_82211_c(0, this.getAttackTarget().entityId);
    323                }
    324                else
    325                {
    326                    this.func_82211_c(0, 0);
    327                }
    328
    329                if (this.field_82222_j > 0)
    330                {
    331                    --this.field_82222_j;
    332
    333                    if (this.field_82222_j == 0 && this.worldObj.func_82736_K().func_82766_b("mobGriefing"))
    334                    {
    335                        var1 = MathHelper.floor_double(this.posY);
    336                        var13 = MathHelper.floor_double(this.posX);
    337                        int var16 = MathHelper.floor_double(this.posZ);
    338                        boolean var19 = false;
    339
    340                        for (int var18 = -1; var18 <= 1; ++var18)
    341                        {
    342                            for (int var20 = -1; var20 <= 1; ++var20)
    343                            {
    344                                for (int var7 = 0; var7 <= 3; ++var7)
    345                                {
    346                                    int var21 = var13 + var18;
    347                                    int var9 = var1 + var7;
    348                                    int var10 = var16 + var20;
    349                                    int var11 = this.worldObj.getBlockId(var21, var9, var10);
    350
    351                                    if (var11 > 0 && var11 != Block.bedrock.blockID)
    352                                    {
    353                                        int var12 = this.worldObj.getBlockMetadata(var21, var9, var10);
    354                                        this.worldObj.playAuxSFX(2001, var21, var9, var10, var11 + (var12 << 12));
    355                                        Block.blocksList[var11].dropBlockAsItem(this.worldObj, var21, var9, var10, var12, 0);
    356                                        this.worldObj.setBlockWithNotify(var21, var9, var10, 0);
    357                                        var19 = true;
    358                                    }
    359                                }
    360                            }
    361                        }
    362
    363                        if (var19)
    364                        {
    365                            this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1012, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    366                        }
    367                    }
    368                }
    369
    370                if (this.ticksExisted % 20 == 0)
    371                {
    372                    this.heal(1);
    373                }
    374            }
    375        }
    376
    377        public void func_82206_m()
    378        {
    379            this.func_82215_s(220);
    380            this.setEntityHealth(this.getMaxHealth() / 3);
    381        }
    382
    383        /**
    384         * Sets the Entity inside a web block.
    385         */
    386        public void setInWeb() {}
    387
    388        /**
    389         * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
    390         */
    391        public int getTotalArmorValue()
    392        {
    393            return 4;
    394        }
    395
    396        private double func_82214_u(int par1)
    397        {
    398            if (par1 <= 0)
    399            {
    400                return this.posX;
    401            }
    402            else
    403            {
    404                float var2 = (this.renderYawOffset + (float)(180 * (par1 - 1))) / 180.0F * (float)Math.PI;
    405                float var3 = MathHelper.cos(var2);
    406                return this.posX + (double)var3 * 1.3D;
    407            }
    408        }
    409
    410        private double func_82208_v(int par1)
    411        {
    412            return par1 <= 0 ? this.posY + 3.0D : this.posY + 2.2D;
    413        }
    414
    415        private double func_82213_w(int par1)
    416        {
    417            if (par1 <= 0)
    418            {
    419                return this.posZ;
    420            }
    421            else
    422            {
    423                float var2 = (this.renderYawOffset + (float)(180 * (par1 - 1))) / 180.0F * (float)Math.PI;
    424                float var3 = MathHelper.sin(var2);
    425                return this.posZ + (double)var3 * 1.3D;
    426            }
    427        }
    428
    429        private float func_82204_b(float par1, float par2, float par3)
    430        {
    431            float var4 = MathHelper.wrapAngleTo180_float(par2 - par1);
    432
    433            if (var4 > par3)
    434            {
    435                var4 = par3;
    436            }
    437
    438            if (var4 < -par3)
    439            {
    440                var4 = -par3;
    441            }
    442
    443            return par1 + var4;
    444        }
    445
    446        private void func_82216_a(int par1, EntityLiving par2EntityLiving)
    447        {
    448            this.func_82209_a(par1, par2EntityLiving.posX, par2EntityLiving.posY + (double)par2EntityLiving.getEyeHeight() * 0.5D, par2EntityLiving.posZ, par1 == 0 && this.rand.nextFloat() < 0.001F);
    449        }
    450
    451        private void func_82209_a(int par1, double par2, double par4, double par6, boolean par8)
    452        {
    453            this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1014, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    454            double var9 = this.func_82214_u(par1);
    455            double var11 = this.func_82208_v(par1);
    456            double var13 = this.func_82213_w(par1);
    457            double var15 = par2 - var9;
    458            double var17 = par4 - var11;
    459            double var19 = par6 - var13;
    460            EntityWitherSkull var21 = new EntityWitherSkull(this.worldObj, this, var15, var17, var19);
    461
    462            if (par8)
    463            {
    464                var21.func_82343_e(true);
    465            }
    466
    467            var21.posY = var11;
    468            var21.posX = var9;
    469            var21.posZ = var13;
    470            this.worldObj.spawnEntityInWorld(var21);
    471        }
    472
    473        public void func_82196_d(EntityLiving par1EntityLiving)
    474        {
    475            this.func_82216_a(0, par1EntityLiving);
    476        }
    477
    478        /**
    479         * Called when the entity is attacked.
    480         */
    481        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    482        {
    483            if (par1DamageSource == DamageSource.drown)
    484            {
    485                return false;
    486            }
    487            else if (this.func_82212_n() > 0)
    488            {
    489                return false;
    490            }
    491            else
    492            {
    493                Entity var3;
    494
    495                if (this.func_82205_o())
    496                {
    497                    var3 = par1DamageSource.getSourceOfDamage();
    498
    499                    if (var3 instanceof EntityArrow)
    500                    {
    501                        return false;
    502                    }
    503                }
    504
    505                var3 = par1DamageSource.getEntity();
    506
    507                if (var3 != null && !(var3 instanceof EntityPlayer) && var3 instanceof EntityLiving && ((EntityLiving)var3).getCreatureAttribute() == this.getCreatureAttribute())
    508                {
    509                    return false;
    510                }
    511                else
    512                {
    513                    if (this.field_82222_j <= 0)
    514                    {
    515                        this.field_82222_j = 20;
    516                    }
    517
    518                    for (int var4 = 0; var4 < this.field_82224_i.length; ++var4)
    519                    {
    520                        this.field_82224_i[var4] += 3;
    521                    }
    522
    523                    return super.attackEntityFrom(par1DamageSource, par2);
    524                }
    525            }
    526        }
    527
    528        /**
    529         * Drop 0-2 items of this living's type
    530         */
    531        protected void dropFewItems(boolean par1, int par2)
    532        {
    533            this.dropItem(Item.field_82792_bS.shiftedIndex, 1);
    534        }
    535
    536        /**
    537         * Makes the entity despawn if requirements are reached
    538         */
    539        protected void despawnEntity()
    540        {
    541            this.entityAge = 0;
    542        }
    543
    544        @SideOnly(Side.CLIENT)
    545        public int getBrightnessForRender(float par1)
    546        {
    547            return 15728880;
    548        }
    549
    550        /**
    551         * Returns true if other Entities should be prevented from moving through this Entity.
    552         */
    553        public boolean canBeCollidedWith()
    554        {
    555            return !this.isDead;
    556        }
    557
    558        /**
    559         * Returns the health points of the dragon.
    560         */
    561        public int getDragonHealth()
    562        {
    563            return this.dataWatcher.getWatchableObjectInt(16);
    564        }
    565
    566        /**
    567         * Called when the mob is falling. Calculates and applies fall damage.
    568         */
    569        protected void fall(float par1) {}
    570
    571        /**
    572         * adds a PotionEffect to the entity
    573         */
    574        public void addPotionEffect(PotionEffect par1PotionEffect) {}
    575
    576        /**
    577         * Returns true if the newer Entity AI code should be run
    578         */
    579        protected boolean isAIEnabled()
    580        {
    581            return true;
    582        }
    583
    584        public int getMaxHealth()
    585        {
    586            return 300;
    587        }
    588
    589        @SideOnly(Side.CLIENT)
    590        public float func_82207_a(int par1)
    591        {
    592            return this.field_82221_e[par1];
    593        }
    594
    595        @SideOnly(Side.CLIENT)
    596        public float func_82210_r(int par1)
    597        {
    598            return this.field_82220_d[par1];
    599        }
    600
    601        public int func_82212_n()
    602        {
    603            return this.dataWatcher.getWatchableObjectInt(20);
    604        }
    605
    606        public void func_82215_s(int par1)
    607        {
    608            this.dataWatcher.updateObject(20, Integer.valueOf(par1));
    609        }
    610
    611        public int func_82203_t(int par1)
    612        {
    613            return this.dataWatcher.getWatchableObjectInt(17 + par1);
    614        }
    615
    616        public void func_82211_c(int par1, int par2)
    617        {
    618            this.dataWatcher.updateObject(17 + par1, Integer.valueOf(par2));
    619        }
    620
    621        public boolean func_82205_o()
    622        {
    623            return this.getDragonHealth() <= this.getMaxHealth() / 2;
    624        }
    625
    626        /**
    627         * Get this Entity's EnumCreatureAttribute
    628         */
    629        public EnumCreatureAttribute getCreatureAttribute()
    630        {
    631            return EnumCreatureAttribute.UNDEAD;
    632        }
    633    }