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    
027        public TileEntityMobSpawner()
028        {
029            this.delay = 20;
030        }
031    
032        @SideOnly(Side.CLIENT)
033        public String getMobID()
034        {
035            return this.mobID;
036        }
037    
038        public void setMobID(String par1Str)
039        {
040            this.mobID = par1Str;
041        }
042    
043        /**
044         * Returns true if there is a player in range (using World.getClosestPlayer)
045         */
046        public boolean anyPlayerInRange()
047        {
048            return this.worldObj.getClosestPlayer((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D, 16.0D) != null;
049        }
050    
051        /**
052         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
053         * ticks and creates a new spawn inside its implementation.
054         */
055        public void updateEntity()
056        {
057            if (this.anyPlayerInRange())
058            {
059                if (this.worldObj.isRemote)
060                {
061                    double var1 = (double)((float)this.xCoord + this.worldObj.rand.nextFloat());
062                    double var3 = (double)((float)this.yCoord + this.worldObj.rand.nextFloat());
063                    double var5 = (double)((float)this.zCoord + this.worldObj.rand.nextFloat());
064                    this.worldObj.spawnParticle("smoke", var1, var3, var5, 0.0D, 0.0D, 0.0D);
065                    this.worldObj.spawnParticle("flame", var1, var3, var5, 0.0D, 0.0D, 0.0D);
066                    this.yaw2 = this.yaw % 360.0D;
067                    this.yaw += 4.545454502105713D;
068                }
069                else
070                {
071                    if (this.delay == -1)
072                    {
073                        this.updateDelay();
074                    }
075    
076                    if (this.delay > 0)
077                    {
078                        --this.delay;
079                        return;
080                    }
081    
082                    for (int var11 = 0; var11 < this.spawnCount; ++var11)
083                    {
084                        Entity var2 = EntityList.createEntityByName(this.mobID, this.worldObj);
085    
086                        if (var2 == null)
087                        {
088                            return;
089                        }
090    
091                        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(8.0D, 4.0D, 8.0D)).size();
092    
093                        if (var12 >= 6)
094                        {
095                            this.updateDelay();
096                            return;
097                        }
098    
099                        if (var2 != null)
100                        {
101                            double var4 = (double)this.xCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * 4.0D;
102                            double var6 = (double)(this.yCoord + this.worldObj.rand.nextInt(3) - 1);
103                            double var8 = (double)this.zCoord + (this.worldObj.rand.nextDouble() - this.worldObj.rand.nextDouble()) * 4.0D;
104                            EntityLiving var10 = var2 instanceof EntityLiving ? (EntityLiving)var2 : null;
105                            var2.setLocationAndAngles(var4, var6, var8, this.worldObj.rand.nextFloat() * 360.0F, 0.0F);
106    
107                            if (var10 == null || var10.getCanSpawnHere())
108                            {
109                                this.writeNBTTagsTo(var2);
110                                this.worldObj.spawnEntityInWorld(var2);
111                                this.worldObj.playAuxSFX(2004, this.xCoord, this.yCoord, this.zCoord, 0);
112    
113                                if (var10 != null)
114                                {
115                                    var10.spawnExplosionParticle();
116                                }
117    
118                                this.updateDelay();
119                            }
120                        }
121                    }
122                }
123    
124                super.updateEntity();
125            }
126        }
127    
128        public void writeNBTTagsTo(Entity par1Entity)
129        {
130            if (this.spawnerTags != null)
131            {
132                NBTTagCompound var2 = new NBTTagCompound();
133                par1Entity.addEntityID(var2);
134                Iterator var3 = this.spawnerTags.getTags().iterator();
135    
136                while (var3.hasNext())
137                {
138                    NBTBase var4 = (NBTBase)var3.next();
139                    var2.setTag(var4.getName(), var4.copy());
140                }
141    
142                par1Entity.readFromNBT(var2);
143            }
144        }
145    
146        /**
147         * Sets the delay before a new spawn (base delay of 200 + random number up to 600).
148         */
149        private void updateDelay()
150        {
151            this.delay = this.minSpawnDelay + this.worldObj.rand.nextInt(this.maxSpawnDelay - this.minSpawnDelay);
152        }
153    
154        /**
155         * Reads a tile entity from NBT.
156         */
157        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
158        {
159            super.readFromNBT(par1NBTTagCompound);
160            this.mobID = par1NBTTagCompound.getString("EntityId");
161            this.delay = par1NBTTagCompound.getShort("Delay");
162    
163            if (par1NBTTagCompound.hasKey("SpawnData"))
164            {
165                this.spawnerTags = par1NBTTagCompound.getCompoundTag("SpawnData");
166            }
167            else
168            {
169                this.spawnerTags = null;
170            }
171    
172            if (par1NBTTagCompound.hasKey("MinSpawnDelay"))
173            {
174                this.minSpawnDelay = par1NBTTagCompound.getShort("MinSpawnDelay");
175                this.maxSpawnDelay = par1NBTTagCompound.getShort("MaxSpawnDelay");
176                this.spawnCount = par1NBTTagCompound.getShort("SpawnCount");
177            }
178        }
179    
180        /**
181         * Writes a tile entity to NBT.
182         */
183        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
184        {
185            super.writeToNBT(par1NBTTagCompound);
186            par1NBTTagCompound.setString("EntityId", this.mobID);
187            par1NBTTagCompound.setShort("Delay", (short)this.delay);
188            par1NBTTagCompound.setShort("MinSpawnDelay", (short)this.minSpawnDelay);
189            par1NBTTagCompound.setShort("MaxSpawnDelay", (short)this.maxSpawnDelay);
190            par1NBTTagCompound.setShort("SpawnCount", (short)this.spawnCount);
191    
192            if (this.spawnerTags != null)
193            {
194                par1NBTTagCompound.setCompoundTag("SpawnData", this.spawnerTags);
195            }
196        }
197    
198        @SideOnly(Side.CLIENT)
199    
200        /**
201         * will create the entity from the internalID the first time it is accessed
202         */
203        public Entity getMobEntity()
204        {
205            if (this.spawnedMob == null)
206            {
207                Entity var1 = EntityList.createEntityByName(this.getMobID(), (World)null);
208                this.writeNBTTagsTo(var1);
209                this.spawnedMob = var1;
210            }
211    
212            return this.spawnedMob;
213        }
214    
215        /**
216         * signs and mobSpawners use this to send text and meta-data
217         */
218        public Packet getAuxillaryInfoPacket()
219        {
220            NBTTagCompound var1 = new NBTTagCompound();
221            this.writeToNBT(var1);
222            return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, var1);
223        }
224    }