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