    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.worldObj.playSoundAtEntity(this, "mob.irongolem.throw", 1.0F, 1.0F);
    161            return var2;
    162        }
    163
    164        @SideOnly(Side.CLIENT)
    165        public void handleHealthUpdate(byte par1)
    166        {
    167            if (par1 == 4)
    168            {
    169                this.attackTimer = 10;
    170                this.worldObj.playSoundAtEntity(this, "mob.irongolem.throw", 1.0F, 1.0F);
    171            }
    172            else if (par1 == 11)
    173            {
    174                this.holdRoseTick = 400;
    175            }
    176            else
    177            {
    178                super.handleHealthUpdate(par1);
    179            }
    180        }
    181
    182        public Village getVillage()
    183        {
    184            return this.villageObj;
    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.worldObj.playSoundAtEntity(this, "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    }