    001    package net.minecraft.src;
    002
    003    import java.util.ArrayList;
    004    import java.util.Collections;
    005    import java.util.HashMap;
    006    import java.util.Iterator;
    007    import java.util.List;
    008    import java.util.Random;
    009
    010    import net.minecraftforge.common.MinecraftForge;
    011    import net.minecraftforge.event.entity.living.LivingSpecialSpawnEvent;
    012
    013    public final class SpawnerAnimals
    014    {
    015        /** The 17x17 area around the player where mobs can spawn */
    016        private static HashMap eligibleChunksForSpawning = new HashMap();
    017
    018        /** An array of entity classes that spawn at night. */
    019        protected static final Class[] nightSpawnEntities = new Class[] {EntitySpider.class, EntityZombie.class, EntitySkeleton.class};
    020
    021        /**
    022         * Given a chunk, find a random position in it.
    023         */
    024        protected static ChunkPosition getRandomSpawningPointInChunk(World par0World, int par1, int par2)
    025        {
    026            Chunk var3 = par0World.getChunkFromChunkCoords(par1, par2);
    027            int var4 = par1 * 16 + par0World.rand.nextInt(16);
    028            int var5 = par2 * 16 + par0World.rand.nextInt(16);
    029            int var6 = par0World.rand.nextInt(var3 == null ? par0World.getActualHeight() : var3.getTopFilledSegment() + 16 - 1);
    030            return new ChunkPosition(var4, var6, var5);
    031        }
    032
    033        /**
    034         * adds all chunks within the spawn radius of the players to eligibleChunksForSpawning. pars: the world,
    035         * hostileCreatures, passiveCreatures. returns number of eligible chunks.
    036         */
    037        public static final int findChunksForSpawning(WorldServer par0WorldServer, boolean par1, boolean par2)
    038        {
    039            if (!par1 && !par2)
    040            {
    041                return 0;
    042            }
    043            else
    044            {
    045                eligibleChunksForSpawning.clear();
    046                int var3;
    047                int var6;
    048
    049                for (var3 = 0; var3 < par0WorldServer.playerEntities.size(); ++var3)
    050                {
    051                    EntityPlayer var4 = (EntityPlayer)par0WorldServer.playerEntities.get(var3);
    052                    int var5 = MathHelper.floor_double(var4.posX / 16.0D);
    053                    var6 = MathHelper.floor_double(var4.posZ / 16.0D);
    054                    byte var7 = 8;
    055
    056                    for (int var8 = -var7; var8 <= var7; ++var8)
    057                    {
    058                        for (int var9 = -var7; var9 <= var7; ++var9)
    059                        {
    060                            boolean var10 = var8 == -var7 || var8 == var7 || var9 == -var7 || var9 == var7;
    061                            ChunkCoordIntPair var11 = new ChunkCoordIntPair(var8 + var5, var9 + var6);
    062
    063                            if (!var10)
    064                            {
    065                                eligibleChunksForSpawning.put(var11, Boolean.valueOf(false));
    066                            }
    067                            else if (!eligibleChunksForSpawning.containsKey(var11))
    068                            {
    069                                eligibleChunksForSpawning.put(var11, Boolean.valueOf(true));
    070                            }
    071                        }
    072                    }
    073                }
    074
    075                var3 = 0;
    076                ChunkCoordinates var31 = par0WorldServer.getSpawnPoint();
    077                EnumCreatureType[] var32 = EnumCreatureType.values();
    078                var6 = var32.length;
    079
    080                for (int var33 = 0; var33 < var6; ++var33)
    081                {
    082                    EnumCreatureType var34 = var32[var33];
    083
    084                    if ((!var34.getPeacefulCreature() || par2) && (var34.getPeacefulCreature() || par1) && par0WorldServer.countEntities(var34.getCreatureClass()) <= var34.getMaxNumberOfCreature() * eligibleChunksForSpawning.size() / 256)
    085                    {
    086                        Iterator var35 = eligibleChunksForSpawning.keySet().iterator();
    087                        ArrayList<ChunkCoordIntPair> tmp = new ArrayList(eligibleChunksForSpawning.keySet());
    088                        Collections.shuffle(tmp);
    089                        var35 = tmp.iterator();
    090                        label108:
    091
    092                        while (var35.hasNext())
    093                        {
    094                            ChunkCoordIntPair var37 = (ChunkCoordIntPair)var35.next();
    095
    096                            if (!((Boolean)eligibleChunksForSpawning.get(var37)).booleanValue())
    097                            {
    098                                ChunkPosition var36 = getRandomSpawningPointInChunk(par0WorldServer, var37.chunkXPos, var37.chunkZPos);
    099                                int var12 = var36.x;
    100                                int var13 = var36.y;
    101                                int var14 = var36.z;
    102
    103                                if (!par0WorldServer.isBlockNormalCube(var12, var13, var14) && par0WorldServer.getBlockMaterial(var12, var13, var14) == var34.getCreatureMaterial())
    104                                {
    105                                    int var15 = 0;
    106                                    int var16 = 0;
    107
    108                                    while (var16 < 3)
    109                                    {
    110                                        int var17 = var12;
    111                                        int var18 = var13;
    112                                        int var19 = var14;
    113                                        byte var20 = 6;
    114                                        SpawnListEntry var21 = null;
    115                                        int var22 = 0;
    116
    117                                        while (true)
    118                                        {
    119                                            if (var22 < 4)
    120                                            {
    121                                                label101:
    122                                                {
    123                                                    var17 += par0WorldServer.rand.nextInt(var20) - par0WorldServer.rand.nextInt(var20);
    124                                                    var18 += par0WorldServer.rand.nextInt(1) - par0WorldServer.rand.nextInt(1);
    125                                                    var19 += par0WorldServer.rand.nextInt(var20) - par0WorldServer.rand.nextInt(var20);
    126
    127                                                    if (canCreatureTypeSpawnAtLocation(var34, par0WorldServer, var17, var18, var19))
    128                                                    {
    129                                                        float var23 = (float)var17 + 0.5F;
    130                                                        float var24 = (float)var18;
    131                                                        float var25 = (float)var19 + 0.5F;
    132
    133                                                        if (par0WorldServer.getClosestPlayer((double)var23, (double)var24, (double)var25, 24.0D) == null)
    134                                                        {
    135                                                            float var26 = var23 - (float)var31.posX;
    136                                                            float var27 = var24 - (float)var31.posY;
    137                                                            float var28 = var25 - (float)var31.posZ;
    138                                                            float var29 = var26 * var26 + var27 * var27 + var28 * var28;
    139
    140                                                            if (var29 >= 576.0F)
    141                                                            {
    142                                                                if (var21 == null)
    143                                                                {
    144                                                                    var21 = par0WorldServer.spawnRandomCreature(var34, var17, var18, var19);
    145
    146                                                                    if (var21 == null)
    147                                                                    {
    148                                                                        break label101;
    149                                                                    }
    150                                                                }
    151
    152                                                                EntityLiving var38;
    153
    154                                                                try
    155                                                                {
    156                                                                    var38 = (EntityLiving)var21.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0WorldServer});
    157                                                                }
    158                                                                catch (Exception var30)
    159                                                                {
    160                                                                    var30.printStackTrace();
    161                                                                    return var3;
    162                                                                }
    163
    164                                                                var38.setLocationAndAngles((double)var23, (double)var24, (double)var25, par0WorldServer.rand.nextFloat() * 360.0F, 0.0F);
    165
    166                                                                if (var38.getCanSpawnHere())
    167                                                                {
    168                                                                    ++var15;
    169                                                                    par0WorldServer.spawnEntityInWorld(var38);
    170                                                                    creatureSpecificInit(var38, par0WorldServer, var23, var24, var25);
    171
    172                                                                    if (var15 >= var38.getMaxSpawnedInChunk())
    173                                                                    {
    174                                                                        continue label108;
    175                                                                    }
    176                                                                }
    177
    178                                                                var3 += var15;
    179                                                            }
    180                                                        }
    181                                                    }
    182
    183                                                    ++var22;
    184                                                    continue;
    185                                                }
    186                                            }
    187
    188                                            ++var16;
    189                                            break;
    190                                        }
    191                                    }
    192                                }
    193                            }
    194                        }
    195                    }
    196                }
    197
    198                return var3;
    199            }
    200        }
    201
    202        /**
    203         * Returns whether or not the specified creature type can spawn at the specified location.
    204         */
    205        public static boolean canCreatureTypeSpawnAtLocation(EnumCreatureType par0EnumCreatureType, World par1World, int par2, int par3, int par4)
    206        {
    207            if (par0EnumCreatureType.getCreatureMaterial() == Material.water)
    208            {
    209                return par1World.getBlockMaterial(par2, par3, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4);
    210            }
    211            else if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4))
    212            {
    213                return false;
    214            }
    215            else
    216            {
    217                int var5 = par1World.getBlockId(par2, par3 - 1, par4);
    218                boolean spawnBlock = (Block.blocksList[var5] != null && Block.blocksList[var5].canCreatureSpawn(par0EnumCreatureType, par1World, par2, par3 - 1, par4));
    219                return spawnBlock && var5 != Block.bedrock.blockID && !par1World.isBlockNormalCube(par2, par3, par4) && !par1World.getBlockMaterial(par2, par3, par4).isLiquid() && !par1World.isBlockNormalCube(par2, par3 + 1, par4);
    220            }
    221        }
    222
    223        /**
    224         * determines if a skeleton spawns on a spider, and if a sheep is a different color
    225         */
    226        private static void creatureSpecificInit(EntityLiving par0EntityLiving, World par1World, float par2, float par3, float par4)
    227        {
    228            LivingSpecialSpawnEvent event = new LivingSpecialSpawnEvent(par0EntityLiving, par1World, par2, par3, par4);
    229            MinecraftForge.EVENT_BUS.post(event);
    230            if (event.isHandeled())
    231            {
    232                return;
    233            }
    234
    235            if (par0EntityLiving instanceof EntitySpider && par1World.rand.nextInt(100) == 0)
    236            {
    237                EntitySkeleton var7 = new EntitySkeleton(par1World);
    238                var7.setLocationAndAngles((double)par2, (double)par3, (double)par4, par0EntityLiving.rotationYaw, 0.0F);
    239                par1World.spawnEntityInWorld(var7);
    240                var7.mountEntity(par0EntityLiving);
    241            }
    242            else if (par0EntityLiving instanceof EntitySheep)
    243            {
    244                ((EntitySheep)par0EntityLiving).setFleeceColor(EntitySheep.getRandomFleeceColor(par1World.rand));
    245            }
    246            else if (par0EntityLiving instanceof EntityOcelot && par1World.rand.nextInt(7) == 0)
    247            {
    248                for (int var5 = 0; var5 < 2; ++var5)
    249                {
    250                    EntityOcelot var6 = new EntityOcelot(par1World);
    251                    var6.setLocationAndAngles((double)par2, (double)par3, (double)par4, par0EntityLiving.rotationYaw, 0.0F);
    252                    var6.setGrowingAge(-24000);
    253                    par1World.spawnEntityInWorld(var6);
    254                }
    255            }
    256        }
    257
    258        /**
    259         * Called during chunk generation to spawn initial creatures.
    260         */
    261        public static void performWorldGenSpawning(World par0World, BiomeGenBase par1BiomeGenBase, int par2, int par3, int par4, int par5, Random par6Random)
    262        {
    263            List var7 = par1BiomeGenBase.getSpawnableList(EnumCreatureType.creature);
    264
    265            if (!var7.isEmpty())
    266            {
    267                while (par6Random.nextFloat() < par1BiomeGenBase.getSpawningChance())
    268                {
    269                    SpawnListEntry var8 = (SpawnListEntry)WeightedRandom.getRandomItem(par0World.rand, var7);
    270                    int var9 = var8.minGroupCount + par6Random.nextInt(1 + var8.maxGroupCount - var8.minGroupCount);
    271                    int var10 = par2 + par6Random.nextInt(par4);
    272                    int var11 = par3 + par6Random.nextInt(par5);
    273                    int var12 = var10;
    274                    int var13 = var11;
    275
    276                    for (int var14 = 0; var14 < var9; ++var14)
    277                    {
    278                        boolean var15 = false;
    279
    280                        for (int var16 = 0; !var15 && var16 < 4; ++var16)
    281                        {
    282                            int var17 = par0World.getTopSolidOrLiquidBlock(var10, var11);
    283
    284                            if (canCreatureTypeSpawnAtLocation(EnumCreatureType.creature, par0World, var10, var17, var11))
    285                            {
    286                                float var18 = (float)var10 + 0.5F;
    287                                float var19 = (float)var17;
    288                                float var20 = (float)var11 + 0.5F;
    289                                EntityLiving var21;
    290
    291                                try
    292                                {
    293                                    var21 = (EntityLiving)var8.entityClass.getConstructor(new Class[] {World.class}).newInstance(new Object[] {par0World});
    294                                }
    295                                catch (Exception var23)
    296                                {
    297                                    var23.printStackTrace();
    298                                    continue;
    299                                }
    300
    301                                var21.setLocationAndAngles((double)var18, (double)var19, (double)var20, par6Random.nextFloat() * 360.0F, 0.0F);
    302                                par0World.spawnEntityInWorld(var21);
    303                                creatureSpecificInit(var21, par0World, var18, var19, var20);
    304                                var15 = true;
    305                            }
    306
    307                            var10 += par6Random.nextInt(5) - par6Random.nextInt(5);
    308
    309                            for (var11 += par6Random.nextInt(5) - par6Random.nextInt(5); var10 < par2 || var10 >= par2 + par4 || var11 < par3 || var11 >= par3 + par4; var11 = var13 + par6Random.nextInt(5) - par6Random.nextInt(5))
    310                            {
    311                                var10 = var12 + par6Random.nextInt(5) - par6Random.nextInt(5);
    312                            }
    313                        }
    314                    }
    315                }
    316            }
    317        }
    318    }