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    }