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 }