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    }