001 package net.minecraft.tileentity; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.ArrayList; 006 import java.util.Iterator; 007 import java.util.List; 008 import net.minecraft.entity.Entity; 009 import net.minecraft.entity.EntityList; 010 import net.minecraft.entity.EntityLiving; 011 import net.minecraft.nbt.NBTBase; 012 import net.minecraft.nbt.NBTTagCompound; 013 import net.minecraft.nbt.NBTTagList; 014 import net.minecraft.network.packet.Packet; 015 import net.minecraft.network.packet.Packet132TileEntityData; 016 import net.minecraft.util.AxisAlignedBB; 017 import net.minecraft.util.WeightedRandom; 018 import net.minecraft.world.World; 019 020 public class TileEntityMobSpawner extends TileEntity 021 { 022 /** The stored delay before a new spawn. */ 023 public int delay = -1; 024 025 /** 026 * The string ID of the mobs being spawned from this spawner. Defaults to pig, apparently. 027 */ 028 private String mobID = "Pig"; 029 private List field_92016_e = null; 030 031 /** The extra NBT data to add to spawned entities */ 032 private TileEntityMobSpawnerSpawnData spawnerTags = null; 033 public double yaw; 034 public double yaw2 = 0.0D; 035 private int minSpawnDelay = 200; 036 private int maxSpawnDelay = 800; 037 private int spawnCount = 4; 038 private Entity field_92017_j; 039 private int field_82350_j = 6; 040 private int field_82349_r = 16; 041 private int field_82348_s = 4; 042 043 public TileEntityMobSpawner() 044 { 045 this.delay = 20; 046 } 047 048 public String func_92015_a() 049 { 050 return this.spawnerTags == null ? this.mobID : this.spawnerTags.field_92033_c; 051 } 052 053 public void setMobID(String par1Str) 054 { 055 this.mobID = par1Str; 056 } 057 058 /** 059 * Returns true if there is a player in range (using World.getClosestPlayer) 060 */ 061 public boolean anyPlayerInRange() 062 { 063 return this.worldObj.getClosestPlayer((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D, (double)this.field_82349_r) != null; 064 } 065 066 /** 067 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count 068 * ticks and creates a new spawn inside its implementation. 069 */ 070 public void updateEntity() 071 { 072 if (this.anyPlayerInRange()) 073 { 074 double var5; 075 076 if (this.worldObj.isRemote) 077 { 078 double var1 = (double)((float)this.xCoord + this.worldObj.rand.nextFloat()); 079 double var3 = (double)((float)this.yCoord + this.worldObj.rand.nextFloat()); 080 var5 = (double)((float)this.zCoord + this.worldObj.rand.nextFloat()); 081 this.worldObj.spawnParticle("smoke", var1, var3, var5, 0.0D, 0.0D, 0.0D); 082 this.worldObj.spawnParticle("flame", var1, var3, var5, 0.0D, 0.0D, 0.0D); 083 084 if (this.delay > 0) 085 { 086 --this.delay; 087 } 088 089 this.yaw2 = this.yaw; 090 this.yaw = (this.yaw + (double)(1000.0F / ((float)this.delay + 200.0F))) % 360.0D; 091 } 092 else 093 { 094 if (this.delay == -1) 095 { 096 this.updateDelay(); 097 } 098 099 if (this.delay > 0) 100 { 101 --this.delay; 102 return; 103 } 104 105 boolean var12 = false; 106 107 for (int var2 = 0; var2 < this.spawnCount; ++var2) 108 { 109 Entity var13 = EntityList.createEntityByName(this.func_92015_a(), this.worldObj); 110 111 if (var13 == null) 112 { 113 return; 114 } 115 116 int var4 = this.worldObj.getEntitiesWithinAABB(var13.getClass(), AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)this.xCoord, (double)this.yCoord, (double)this.zCoord, (double)(this.xCoord + 1), (double)(this.yCoord + 1), (double)(this.zCoord + 1)).expand((double)(this.field_82348_s * 2), 4.0D, (double)(this.field_82348_s * 2))).size(); 117 118 if (var4 >= this.field_82350_j) 119 { 120 this.updateDelay(); 121 return; 122 } 123 124 if (var13 != null) 125 { 126 var5 = (double)this.xCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * (double)this.field_82348_s; 127 double var7 = (double)(this.yCoord + this.worldObj.rand.nextInt(3) - 1); 128 double var9 = (double)this.zCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * (double)this.field_82348_s; 129 EntityLiving var11 = var13 instanceof EntityLiving ? (EntityLiving)var13 : null; 130 var13.setLocationAndAngles(var5, var7, var9, this.worldObj.rand.nextFloat() * 360.0F, 0.0F); 131 132 if (var11 == null || var11.getCanSpawnHere()) 133 { 134 this.writeNBTTagsTo(var13); 135 this.worldObj.spawnEntityInWorld(var13); 136 this.worldObj.playAuxSFX(2004, this.xCoord, this.yCoord, this.zCoord, 0); 137 138 if (var11 != null) 139 { 140 var11.spawnExplosionParticle(); 141 } 142 143 var12 = true; 144 } 145 } 146 } 147 148 if (var12) 149 { 150 this.updateDelay(); 151 } 152 } 153 154 super.updateEntity(); 155 } 156 } 157 158 public void writeNBTTagsTo(Entity par1Entity) 159 { 160 if (this.spawnerTags != null) 161 { 162 NBTTagCompound var2 = new NBTTagCompound(); 163 par1Entity.addEntityID(var2); 164 Iterator var3 = this.spawnerTags.field_92032_b.getTags().iterator(); 165 166 while (var3.hasNext()) 167 { 168 NBTBase var4 = (NBTBase)var3.next(); 169 var2.setTag(var4.getName(), var4.copy()); 170 } 171 172 par1Entity.readFromNBT(var2); 173 } 174 else if (par1Entity instanceof EntityLiving && par1Entity.worldObj != null) 175 { 176 ((EntityLiving)par1Entity).initCreature(); 177 } 178 } 179 180 /** 181 * Sets the delay before a new spawn (base delay of 200 + random number up to 600). 182 */ 183 private void updateDelay() 184 { 185 if (this.maxSpawnDelay <= this.minSpawnDelay) 186 { 187 this.delay = this.minSpawnDelay; 188 } 189 else 190 { 191 this.delay = this.minSpawnDelay + this.worldObj.rand.nextInt(this.maxSpawnDelay - this.minSpawnDelay); 192 } 193 194 if (this.field_92016_e != null && this.field_92016_e.size() > 0) 195 { 196 this.spawnerTags = (TileEntityMobSpawnerSpawnData)WeightedRandom.getRandomItem(this.worldObj.rand, this.field_92016_e); 197 this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); 198 } 199 200 this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, 0); 201 } 202 203 /** 204 * Reads a tile entity from NBT. 205 */ 206 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 207 { 208 super.readFromNBT(par1NBTTagCompound); 209 this.mobID = par1NBTTagCompound.getString("EntityId"); 210 this.delay = par1NBTTagCompound.getShort("Delay"); 211 212 if (par1NBTTagCompound.hasKey("SpawnPotentials")) 213 { 214 this.field_92016_e = new ArrayList(); 215 NBTTagList var2 = par1NBTTagCompound.getTagList("SpawnPotentials"); 216 217 for (int var3 = 0; var3 < var2.tagCount(); ++var3) 218 { 219 this.field_92016_e.add(new TileEntityMobSpawnerSpawnData(this, (NBTTagCompound)var2.tagAt(var3))); 220 } 221 } 222 else 223 { 224 this.field_92016_e = null; 225 } 226 227 if (par1NBTTagCompound.hasKey("SpawnData")) 228 { 229 this.spawnerTags = new TileEntityMobSpawnerSpawnData(this, par1NBTTagCompound.getCompoundTag("SpawnData"), this.mobID); 230 } 231 else 232 { 233 this.spawnerTags = null; 234 } 235 236 if (par1NBTTagCompound.hasKey("MinSpawnDelay")) 237 { 238 this.minSpawnDelay = par1NBTTagCompound.getShort("MinSpawnDelay"); 239 this.maxSpawnDelay = par1NBTTagCompound.getShort("MaxSpawnDelay"); 240 this.spawnCount = par1NBTTagCompound.getShort("SpawnCount"); 241 } 242 243 if (par1NBTTagCompound.hasKey("MaxNearbyEntities")) 244 { 245 this.field_82350_j = par1NBTTagCompound.getShort("MaxNearbyEntities"); 246 this.field_82349_r = par1NBTTagCompound.getShort("RequiredPlayerRange"); 247 } 248 249 if (par1NBTTagCompound.hasKey("SpawnRange")) 250 { 251 this.field_82348_s = par1NBTTagCompound.getShort("SpawnRange"); 252 } 253 254 if (this.worldObj != null && this.worldObj.isRemote) 255 { 256 this.field_92017_j = null; 257 } 258 } 259 260 /** 261 * Writes a tile entity to NBT. 262 */ 263 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 264 { 265 super.writeToNBT(par1NBTTagCompound); 266 par1NBTTagCompound.setString("EntityId", this.func_92015_a()); 267 par1NBTTagCompound.setShort("Delay", (short)this.delay); 268 par1NBTTagCompound.setShort("MinSpawnDelay", (short)this.minSpawnDelay); 269 par1NBTTagCompound.setShort("MaxSpawnDelay", (short)this.maxSpawnDelay); 270 par1NBTTagCompound.setShort("SpawnCount", (short)this.spawnCount); 271 par1NBTTagCompound.setShort("MaxNearbyEntities", (short)this.field_82350_j); 272 par1NBTTagCompound.setShort("RequiredPlayerRange", (short)this.field_82349_r); 273 par1NBTTagCompound.setShort("SpawnRange", (short)this.field_82348_s); 274 275 if (this.spawnerTags != null) 276 { 277 par1NBTTagCompound.setCompoundTag("SpawnData", (NBTTagCompound)this.spawnerTags.field_92032_b.copy()); 278 } 279 280 if (this.spawnerTags != null || this.field_92016_e != null && this.field_92016_e.size() > 0) 281 { 282 NBTTagList var2 = new NBTTagList(); 283 284 if (this.field_92016_e != null && this.field_92016_e.size() > 0) 285 { 286 Iterator var3 = this.field_92016_e.iterator(); 287 288 while (var3.hasNext()) 289 { 290 TileEntityMobSpawnerSpawnData var4 = (TileEntityMobSpawnerSpawnData)var3.next(); 291 var2.appendTag(var4.func_92030_a()); 292 } 293 } 294 else 295 { 296 var2.appendTag(this.spawnerTags.func_92030_a()); 297 } 298 299 par1NBTTagCompound.setTag("SpawnPotentials", var2); 300 } 301 } 302 303 @SideOnly(Side.CLIENT) 304 305 /** 306 * will create the entity from the internalID the first time it is accessed 307 */ 308 public Entity getMobEntity() 309 { 310 if (this.field_92017_j == null) 311 { 312 Entity var1 = EntityList.createEntityByName(this.func_92015_a(), (World)null); 313 this.writeNBTTagsTo(var1); 314 this.field_92017_j = var1; 315 } 316 317 return this.field_92017_j; 318 } 319 320 /** 321 * Overriden in a sign to provide the text. 322 */ 323 public Packet getDescriptionPacket() 324 { 325 NBTTagCompound var1 = new NBTTagCompound(); 326 this.writeToNBT(var1); 327 var1.removeTag("SpawnPotentials"); 328 return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, var1); 329 } 330 331 /** 332 * Called when a client event is received with the event number and argument, see World.sendClientEvent 333 */ 334 public void receiveClientEvent(int par1, int par2) 335 { 336 if (par1 == 1 && this.worldObj.isRemote) 337 { 338 this.delay = this.minSpawnDelay; 339 } 340 } 341 }