    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         * Returns the sound this mob makes while it's alive.
    037         */
    038        protected String getLivingSound()
    039        {
    040            return "mob.bat.idle";
    041        }
    042
    043        /**
    044         * Returns the sound this mob makes when it is hurt.
    045         */
    046        protected String getHurtSound()
    047        {
    048            return "mob.bat.hurt";
    049        }
    050
    051        /**
    052         * Returns the sound this mob makes on death.
    053         */
    054        protected String getDeathSound()
    055        {
    056            return "mob.bat.death";
    057        }
    058
    059        public int getMaxHealth()
    060        {
    061            return 6;
    062        }
    063
    064        public boolean getIsBatHanging()
    065        {
    066            return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0;
    067        }
    068
    069        public void setIsBatHanging(boolean par1)
    070        {
    071            byte var2 = this.dataWatcher.getWatchableObjectByte(16);
    072
    073            if (par1)
    074            {
    075                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 | 1)));
    076            }
    077            else
    078            {
    079                this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var2 & -2)));
    080            }
    081        }
    082
    083        /**
    084         * Returns true if the newer Entity AI code should be run
    085         */
    086        protected boolean isAIEnabled()
    087        {
    088            return true;
    089        }
    090
    091        /**
    092         * Called to update the entity's position/logic.
    093         */
    094        public void onUpdate()
    095        {
    096            super.onUpdate();
    097
    098            if (this.getIsBatHanging())
    099            {
    100                this.motionX = this.motionY = this.motionZ = 0.0D;
    101                this.posY = (double)MathHelper.floor_double(this.posY) + 1.0D - (double)this.height;
    102            }
    103            else
    104            {
    105                this.motionY *= 0.6000000238418579D;
    106            }
    107        }
    108
    109        protected void updateAITasks()
    110        {
    111            super.updateAITasks();
    112
    113            if (this.getIsBatHanging())
    114            {
    115                if (!this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    116                {
    117                    this.setIsBatHanging(false);
    118                    this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    119                }
    120                else
    121                {
    122                    if (this.rand.nextInt(200) == 0)
    123                    {
    124                        this.rotationYawHead = (float)this.rand.nextInt(360);
    125                    }
    126
    127                    if (this.worldObj.getClosestPlayerToEntity(this, 4.0D) != null)
    128                    {
    129                        this.setIsBatHanging(false);
    130                        this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1015, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    131                    }
    132                }
    133            }
    134            else
    135            {
    136                if (this.currentFlightTarget != null && (!this.worldObj.isAirBlock(this.currentFlightTarget.posX, this.currentFlightTarget.posY, this.currentFlightTarget.posZ) || this.currentFlightTarget.posY < 1))
    137                {
    138                    this.currentFlightTarget = null;
    139                }
    140
    141                if (this.currentFlightTarget == null || this.rand.nextInt(30) == 0 || this.currentFlightTarget.getDistanceSquared((int)this.posX, (int)this.posY, (int)this.posZ) < 4.0F)
    142                {
    143                    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));
    144                }
    145
    146                double var1 = (double)this.currentFlightTarget.posX + 0.5D - this.posX;
    147                double var3 = (double)this.currentFlightTarget.posY + 0.1D - this.posY;
    148                double var5 = (double)this.currentFlightTarget.posZ + 0.5D - this.posZ;
    149                this.motionX += (Math.signum(var1) * 0.5D - this.motionX) * 0.10000000149011612D;
    150                this.motionY += (Math.signum(var3) * 0.699999988079071D - this.motionY) * 0.10000000149011612D;
    151                this.motionZ += (Math.signum(var5) * 0.5D - this.motionZ) * 0.10000000149011612D;
    152                float var7 = (float)(Math.atan2(this.motionZ, this.motionX) * 180.0D / Math.PI) - 90.0F;
    153                float var8 = MathHelper.wrapAngleTo180_float(var7 - this.rotationYaw);
    154                this.moveForward = 0.5F;
    155                this.rotationYaw += var8;
    156
    157                if (this.rand.nextInt(100) == 0 && this.worldObj.isBlockNormalCube(MathHelper.floor_double(this.posX), (int)this.posY + 1, MathHelper.floor_double(this.posZ)))
    158                {
    159                    this.setIsBatHanging(true);
    160                }
    161            }
    162        }
    163
    164        /**
    165         * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    166         * prevent them from trampling crops
    167         */
    168        protected boolean canTriggerWalking()
    169        {
    170            return false;
    171        }
    172
    173        /**
    174         * Called when the mob is falling. Calculates and applies fall damage.
    175         */
    176        protected void fall(float par1) {}
    177
    178        /**
    179         * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance
    180         * and deal fall damage if landing on the ground.  Args: distanceFallenThisTick, onGround
    181         */
    182        protected void updateFallState(double par1, boolean par3) {}
    183
    184        /**
    185         * Return whether this entity should NOT trigger a pressure plate or a tripwire.
    186         */
    187        public boolean doesEntityNotTriggerPressurePlate()
    188        {
    189            return true;
    190        }
    191
    192        /**
    193         * Called when the entity is attacked.
    194         */
    195        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    196        {
    197            if (!this.worldObj.isRemote && this.getIsBatHanging())
    198            {
    199                this.setIsBatHanging(false);
    200            }
    201
    202            return super.attackEntityFrom(par1DamageSource, par2);
    203        }
    204
    205        /**
    206         * (abstract) Protected helper method to read subclass entity data from NBT.
    207         */
    208        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    209        {
    210            super.readEntityFromNBT(par1NBTTagCompound);
    211            this.dataWatcher.updateObject(16, Byte.valueOf(par1NBTTagCompound.getByte("BatFlags")));
    212        }
    213
    214        /**
    215         * (abstract) Protected helper method to write subclass entity data to NBT.
    216         */
    217        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    218        {
    219            super.writeEntityToNBT(par1NBTTagCompound);
    220            par1NBTTagCompound.setByte("BatFlags", this.dataWatcher.getWatchableObjectByte(16));
    221        }
    222
    223        /**
    224         * Checks if the entity's current position is a valid location to spawn this entity.
    225         */
    226        public boolean getCanSpawnHere()
    227        {
    228            int var1 = MathHelper.floor_double(this.boundingBox.minY);
    229
    230            if (var1 >= 63)
    231            {
    232                return false;
    233            }
    234            else
    235            {
    236                int var2 = MathHelper.floor_double(this.posX);
    237                int var3 = MathHelper.floor_double(this.posZ);
    238                int var4 = this.worldObj.getBlockLightValue(var2, var1, var3);
    239                byte var5 = 4;
    240                Calendar var6 = this.worldObj.getCurrentDate();
    241
    242                if ((var6.get(2) + 1 != 10 || var6.get(5) < 20) && (var6.get(2) + 1 != 11 || var6.get(5) > 3))
    243                {
    244                    if (this.rand.nextBoolean())
    245                    {
    246                        return false;
    247                    }
    248                }
    249                else
    250                {
    251                    var5 = 7;
    252                }
    253
    254                return var4 > this.rand.nextInt(var5) ? false : super.getCanSpawnHere();
    255            }
    256        }
    257
    258        /**
    259         * Initialize this creature.
    260         */
    261        public void initCreature() {}
    262    }