    001    package net.minecraft.src;
    002
    003    import java.util.Calendar;
    004
    005    public class EntityBat extends EntityAmbientCreature
    006    {
    007        /**
    008         * randomly selected ChunkCoordinates in a 7x6x7 box around the bat (y offset -2 to 4) towards which it will fly.
    009         * upon getting close a new target will be selected
    010         */
    011        private ChunkCoordinates currentFlightTarget;
    012
    013        public EntityBat(World par1World)
    014        {
    015            super(par1World);
    016            this.texture = "/mob/bat.png";
    017            this.setSize(0.5F, 0.9F);
    018            this.setIsBatHanging(true);
    019        }
    020
    021        protected void entityInit()
    022        {
    023            super.entityInit();
    024            this.dataWatcher.addObject(16, new Byte((byte)0));
    025        }
    026
    027        /**
    028         * Returns the volume for the sounds this mob makes.
    029         */
    030        protected float getSoundVolume()
    031        {
    032            return 0.1F;
    033        }
    034
    035        /**
    036         * Gets the pitch of living sounds in living entities.
    037         */
    038        protected float getSoundPitch()
    039        {
    040            return super.getSoundPitch() * 0.95F;
    041        }
    042
    043        /**
    044         * Returns the sound this mob makes while it's alive.
    045         */
    046        protected String getLivingSound()
    047        {
    048            return this.getIsBatHanging() && this.rand.nextInt(4) != 0 ? null : "mob.bat.idle";
    049        }
    050
    051        /**
    052         * Returns the sound this mob makes when it is hurt.
    053         */
    054        protected String getHurtSound()
    055        {
    056            return "mob.bat.hurt";
    057        }
    058
    059        /**
    060         * Returns the sound this mob makes on death.
    061         */
    062        protected String getDeathSound()
    063        {
    064            return "mob.bat.death";
    065        }
    066
    067        /**
    068         * Returns true if this entity should push and be pushed by other entities when colliding.
    069         */
    070        public boolean canBePushed()
    071        {
    072            return false;
    073        }
    074
    075        protected void collideWithEntity(Entity par1Entity) {}
    076
    077        protected void func_85033_bc() {}
    078
    079        public int getMaxHealth()
    080        {
    081            return 6;
    082        }
    083
    084        public boolean getIsBatHanging()
    085        {
    086            return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0;
    087        }
    088
    089        public void setIsBatHanging(boolean par1)
    090        {
    091            byte var2 = this.dataWatcher.getWatchableObjectByte(16);
    092
    093            if (par1)
    094            {
    095                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 1)));
    096            }
    097            else
    098            {
    099                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -2)));
    100            }
    101        }
    102
    103        /**
    104         * Returns true if the newer Entity AI code should be run
    105         */
    106        protected boolean isAIEnabled()
    107        {
    108            return true;
    109        }
    110
    111        /**
    112         * Called to update the entity's position/logic.
    113         */
    114        public void onUpdate()
    115        {
    116            super.onUpdate();
    117
    118            if (this.getIsBatHanging())
    119            {
    120                this.motionX = this.motionY = this.motionZ = 0.0D;
    121                this.posY = (double)MathHelper.floor_double(this.posY) + 1.0D - (double)this.height;
    122            }
    123            else
    124            {
    125                this.motionY *= 0.6000000238418579D;
    126            }
    127        }
    128
    129        protected void updateAITasks()
    130        {
    131            super.updateAITasks();
    132
    133            if (this.getIsBatHanging())
    134            {
    135                if (!this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    136                {
    137                    this.setIsBatHanging(false);
    138                    this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    139                }
    140                else
    141                {
    142                    if (this.rand.nextInt(200) == 0)
    143                    {
    144                        this.rotationYawHead = (float)this.rand.nextInt(360);
    145                    }
    146
    147                    if (this.worldObj.getClosestPlayerToEntity(this, 4.0D) != null)
    148                    {
    149                        this.setIsBatHanging(false);
    150                        this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    151                    }
    152                }
    153            }
    154            else
    155            {
    156                if (this.currentFlightTarget != null && (!this.worldObj.isAirBlock(this.currentFlightTarget.posX, this.currentFlightTarget.posY, this.currentFlightTarget.posZ) || this.currentFlightTarget.posY < 1))
    157                {
    158                    this.currentFlightTarget = null;
    159                }
    160
    161                if (this.currentFlightTarget == null || this.rand.nextInt(30) == 0 || this.currentFlightTarget.getDistanceSquared((int)this.posX, (int)this.posY, (int)this.posZ) < 4.0F)
    162                {
    163                    this.currentFlightTarget = new ChunkCoordinates((int)this.posX + this.rand.nextInt(7) - this.rand.nextInt(7), (int)this.posY + this.rand.nextInt(6) - 2, (int)this.posZ + this.rand.nextInt(7) - this.rand.nextInt(7));
    164                }
    165
    166                double var1 = (double)this.currentFlightTarget.posX + 0.5D - this.posX;
    167                double var3 = (double)this.currentFlightTarget.posY + 0.1D - this.posY;
    168                double var5 = (double)this.currentFlightTarget.posZ + 0.5D - this.posZ;
    169                this.motionX += (Math.signum(var1) * 0.5D - this.motionX) * 0.10000000149011612D;
    170                this.motionY += (Math.signum(var3) * 0.699999988079071D - this.motionY) * 0.10000000149011612D;
    171                this.motionZ += (Math.signum(var5) * 0.5D - this.motionZ) * 0.10000000149011612D;
    172                float var7 = (float)(Math.atan2(this.motionZ, this.motionX) * 180.0D / Math.PI) - 90.0F;
    173                float var8 = MathHelper.wrapAngleTo180_float(var7 - this.rotationYaw);
    174                this.moveForward = 0.5F;
    175                this.rotationYaw += var8;
    176
    177                if (this.rand.nextInt(100) == 0 && this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    178                {
    179                    this.setIsBatHanging(true);
    180                }
    181            }
    182        }
    183
    184        /**
    185         * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    186         * prevent them from trampling crops
    187         */
    188        protected boolean canTriggerWalking()
    189        {
    190            return false;
    191        }
    192
    193        /**
    194         * Called when the mob is falling. Calculates and applies fall damage.
    195         */
    196        protected void fall(float par1) {}
    197
    198        /**
    199         * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance
    200         * and deal fall damage if landing on the ground.  Args: distanceFallenThisTick, onGround
    201         */
    202        protected void updateFallState(double par1, boolean par3) {}
    203
    204        /**
    205         * Return whether this entity should NOT trigger a pressure plate or a tripwire.
    206         */
    207        public boolean doesEntityNotTriggerPressurePlate()
    208        {
    209            return true;
    210        }
    211
    212        /**
    213         * Called when the entity is attacked.
    214         */
    215        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    216        {
    217            if (this.func_85032_ar())
    218            {
    219                return false;
    220            }
    221            else
    222            {
    223                if (!this.worldObj.isRemote && this.getIsBatHanging())
    224                {
    225                    this.setIsBatHanging(false);
    226                }
    227
    228                return super.attackEntityFrom(par1DamageSource, par2);
    229            }
    230        }
    231
    232        /**
    233         * (abstract) Protected helper method to read subclass entity data from NBT.
    234         */
    235        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    236        {
    237            super.readEntityFromNBT(par1NBTTagCompound);
    238            this.dataWatcher.updateObject(16, Byte.valueOf(par1NBTTagCompound.getByte("BatFlags")));
    239        }
    240
    241        /**
    242         * (abstract) Protected helper method to write subclass entity data to NBT.
    243         */
    244        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    245        {
    246            super.writeEntityToNBT(par1NBTTagCompound);
    247            par1NBTTagCompound.setByte("BatFlags", this.dataWatcher.getWatchableObjectByte(16));
    248        }
    249
    250        /**
    251         * Checks if the entity's current position is a valid location to spawn this entity.
    252         */
    253        public boolean getCanSpawnHere()
    254        {
    255            int var1 = MathHelper.floor_double(this.boundingBox.minY);
    256
    257            if (var1 >= 63)
    258            {
    259                return false;
    260            }
    261            else
    262            {
    263                int var2 = MathHelper.floor_double(this.posX);
    264                int var3 = MathHelper.floor_double(this.posZ);
    265                int var4 = this.worldObj.getBlockLightValue(var2, var1, var3);
    266                byte var5 = 4;
    267                Calendar var6 = this.worldObj.getCurrentDate();
    268
    269                if ((var6.get(2) + 1 != 10 || var6.get(5) < 20) && (var6.get(2) + 1 != 11 || var6.get(5) > 3))
    270                {
    271                    if (this.rand.nextBoolean())
    272                    {
    273                        return false;
    274                    }
    275                }
    276                else
    277                {
    278                    var5 = 7;
    279                }
    280
    281                return var4 > this.rand.nextInt(var5) ? false : super.getCanSpawnHere();
    282            }
    283        }
    284
    285        /**
    286         * Initialize this creature.
    287         */
    288        public void initCreature() {}
    289    }