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