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 }