    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    }