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