    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    }