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