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