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 }