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 }