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 }