001    package net.minecraft.src;
002    
003    import cpw.mods.fml.common.Side;
004    import cpw.mods.fml.common.asm.SideOnly;
005    
006    public class EntityIronGolem extends EntityGolem
007    {
008        /** deincrements, and a distance-to-home check is done at 0 */
009        private int homeCheckTimer = 0;
010        Village villageObj = null;
011        private int attackTimer;
012        private int holdRoseTick;
013    
014        public EntityIronGolem(World par1World)
015        {
016            super(par1World);
017            this.texture = "/mob/villager_golem.png";
018            this.setSize(1.4F, 2.9F);
019            this.getNavigator().setAvoidsWater(true);
020            this.tasks.addTask(1, new EntityAIAttackOnCollide(this, 0.25F, true));
021            this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.22F, 32.0F));
022            this.tasks.addTask(3, new EntityAIMoveThroughVillage(this, 0.16F, true));
023            this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, 0.16F));
024            this.tasks.addTask(5, new EntityAILookAtVillager(this));
025            this.tasks.addTask(6, new EntityAIWander(this, 0.16F));
026            this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
027            this.tasks.addTask(8, new EntityAILookIdle(this));
028            this.targetTasks.addTask(1, new EntityAIDefendVillage(this));
029            this.targetTasks.addTask(2, new EntityAIHurtByTarget(this, false));
030            this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityLiving.class, 16.0F, 0, false, true, IMob.mobSelector));
031        }
032    
033        protected void entityInit()
034        {
035            super.entityInit();
036            this.dataWatcher.addObject(16, Byte.valueOf((byte)0));
037        }
038    
039        /**
040         * Returns true if the newer Entity AI code should be run
041         */
042        public boolean isAIEnabled()
043        {
044            return true;
045        }
046    
047        /**
048         * main AI tick function, replaces updateEntityActionState
049         */
050        protected void updateAITick()
051        {
052            if (--this.homeCheckTimer <= 0)
053            {
054                this.homeCheckTimer = 70 + this.rand.nextInt(50);
055                this.villageObj = this.worldObj.villageCollectionObj.findNearestVillage(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ), 32);
056    
057                if (this.villageObj == null)
058                {
059                    this.detachHome();
060                }
061                else
062                {
063                    ChunkCoordinates var1 = this.villageObj.getCenter();
064                    this.setHomeArea(var1.posX, var1.posY, var1.posZ, (int)((float)this.villageObj.getVillageRadius() * 0.6F));
065                }
066            }
067    
068            super.updateAITick();
069        }
070    
071        public int getMaxHealth()
072        {
073            return 100;
074        }
075    
076        /**
077         * Decrements the entity's air supply when underwater
078         */
079        protected int decreaseAirSupply(int par1)
080        {
081            return par1;
082        }
083    
084        protected void collideWithEntity(Entity par1Entity)
085        {
086            if (par1Entity instanceof IMob && this.getRNG().nextInt(20) == 0)
087            {
088                this.setAttackTarget((EntityLiving)par1Entity);
089            }
090    
091            super.collideWithEntity(par1Entity);
092        }
093    
094        /**
095         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
096         * use this to react to sunlight and start to burn.
097         */
098        public void onLivingUpdate()
099        {
100            super.onLivingUpdate();
101    
102            if (this.attackTimer > 0)
103            {
104                --this.attackTimer;
105            }
106    
107            if (this.holdRoseTick > 0)
108            {
109                --this.holdRoseTick;
110            }
111    
112            if (this.motionX * this.motionX + this.motionZ * this.motionZ > 2.500000277905201E-7D && this.rand.nextInt(5) == 0)
113            {
114                int var1 = MathHelper.floor_double(this.posX);
115                int var2 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset);
116                int var3 = MathHelper.floor_double(this.posZ);
117                int var4 = this.worldObj.getBlockId(var1, var2, var3);
118    
119                if (var4 > 0)
120                {
121                    this.worldObj.spawnParticle("tilecrack_" + var4 + "_", this.posX + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, this.boundingBox.minY + 0.1D, this.posZ + ((double)this.rand.nextFloat() - 0.5D) * (double)this.width, 4.0D * ((double)this.rand.nextFloat() - 0.5D), 0.5D, ((double)this.rand.nextFloat() - 0.5D) * 4.0D);
122                }
123            }
124        }
125    
126        public boolean isExplosiveMob(Class par1Class)
127        {
128            return this.getBit1Flag() && EntityPlayer.class.isAssignableFrom(par1Class) ? false : super.isExplosiveMob(par1Class);
129        }
130    
131        /**
132         * (abstract) Protected helper method to write subclass entity data to NBT.
133         */
134        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
135        {
136            super.writeEntityToNBT(par1NBTTagCompound);
137            par1NBTTagCompound.setBoolean("PlayerCreated", this.getBit1Flag());
138        }
139    
140        /**
141         * (abstract) Protected helper method to read subclass entity data from NBT.
142         */
143        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
144        {
145            super.readEntityFromNBT(par1NBTTagCompound);
146            this.setBit1FlagTo(par1NBTTagCompound.getBoolean("PlayerCreated"));
147        }
148    
149        public boolean attackEntityAsMob(Entity par1Entity)
150        {
151            this.attackTimer = 10;
152            this.worldObj.setEntityState(this, (byte)4);
153            boolean var2 = par1Entity.attackEntityFrom(DamageSource.causeMobDamage(this), 7 + this.rand.nextInt(15));
154    
155            if (var2)
156            {
157                par1Entity.motionY += 0.4000000059604645D;
158            }
159    
160            this.func_85030_a("mob.irongolem.throw", 1.0F, 1.0F);
161            return var2;
162        }
163    
164        public Village getVillage()
165        {
166            return this.villageObj;
167        }
168    
169        @SideOnly(Side.CLIENT)
170        public void handleHealthUpdate(byte par1)
171        {
172            if (par1 == 4)
173            {
174                this.attackTimer = 10;
175                this.func_85030_a("mob.irongolem.throw", 1.0F, 1.0F);
176            }
177            else if (par1 == 11)
178            {
179                this.holdRoseTick = 400;
180            }
181            else
182            {
183                super.handleHealthUpdate(par1);
184            }
185        }
186    
187        @SideOnly(Side.CLIENT)
188        public int getAttackTimer()
189        {
190            return this.attackTimer;
191        }
192    
193        public void setHoldingRose(boolean par1)
194        {
195            this.holdRoseTick = par1 ? 400 : 0;
196            this.worldObj.setEntityState(this, (byte)11);
197        }
198    
199        /**
200         * Returns the sound this mob makes while it's alive.
201         */
202        protected String getLivingSound()
203        {
204            return "none";
205        }
206    
207        /**
208         * Returns the sound this mob makes when it is hurt.
209         */
210        protected String getHurtSound()
211        {
212            return "mob.irongolem.hit";
213        }
214    
215        /**
216         * Returns the sound this mob makes on death.
217         */
218        protected String getDeathSound()
219        {
220            return "mob.irongolem.death";
221        }
222    
223        /**
224         * Plays step sound at given x, y, z for the entity
225         */
226        protected void playStepSound(int par1, int par2, int par3, int par4)
227        {
228            this.func_85030_a("mob.irongolem.walk", 1.0F, 1.0F);
229        }
230    
231        /**
232         * Drop 0-2 items of this living's type
233         */
234        protected void dropFewItems(boolean par1, int par2)
235        {
236            int var3 = this.rand.nextInt(3);
237            int var4;
238    
239            for (var4 = 0; var4 < var3; ++var4)
240            {
241                this.dropItem(Block.plantRed.blockID, 1);
242            }
243    
244            var4 = 3 + this.rand.nextInt(3);
245    
246            for (int var5 = 0; var5 < var4; ++var5)
247            {
248                this.dropItem(Item.ingotIron.shiftedIndex, 1);
249            }
250        }
251    
252        public int getHoldRoseTick()
253        {
254            return this.holdRoseTick;
255        }
256    
257        public boolean getBit1Flag()
258        {
259            return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0;
260        }
261    
262        public void setBit1FlagTo(boolean par1)
263        {
264            byte var2 = this.dataWatcher.getWatchableObjectByte(16);
265    
266            if (par1)
267            {
268                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 1)));
269            }
270            else
271            {
272                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -2)));
273            }
274        }
275    
276        /**
277         * Called when the mob's health reaches 0.
278         */
279        public void onDeath(DamageSource par1DamageSource)
280        {
281            if (!this.getBit1Flag() && this.attackingPlayer != null && this.villageObj != null)
282            {
283                this.villageObj.setReputationForPlayer(this.attackingPlayer.getCommandSenderName(), -5);
284            }
285    
286            super.onDeath(par1DamageSource);
287        }
288    }