001 package net.minecraft.src; 002 003 import java.util.ArrayList; 004 import java.util.Iterator; 005 import java.util.List; 006 007 public class Village 008 { 009 private final World worldObj; 010 011 /** list of VillageDoorInfo objects */ 012 private final List villageDoorInfoList = new ArrayList(); 013 014 /** 015 * This is the sum of all door coordinates and used to calculate the actual village center by dividing by the number 016 * of doors. 017 */ 018 private final ChunkCoordinates centerHelper = new ChunkCoordinates(0, 0, 0); 019 020 /** This is the actual village center. */ 021 private final ChunkCoordinates center = new ChunkCoordinates(0, 0, 0); 022 private int villageRadius = 0; 023 private int lastAddDoorTimestamp = 0; 024 private int tickCounter = 0; 025 private int numVillagers = 0; 026 private List villageAgressors = new ArrayList(); 027 private int numIronGolems = 0; 028 029 public Village(World par1World) 030 { 031 this.worldObj = par1World; 032 } 033 034 /** 035 * Called periodically by VillageCollection 036 */ 037 public void tick(int par1) 038 { 039 this.tickCounter = par1; 040 this.removeDeadAndOutOfRangeDoors(); 041 this.removeDeadAndOldAgressors(); 042 043 if (par1 % 20 == 0) 044 { 045 this.updateNumVillagers(); 046 } 047 048 if (par1 % 30 == 0) 049 { 050 this.updateNumIronGolems(); 051 } 052 053 int var2 = this.numVillagers / 16; 054 055 if (this.numIronGolems < var2 && this.villageDoorInfoList.size() > 20 && this.worldObj.rand.nextInt(7000) == 0) 056 { 057 Vec3 var3 = this.tryGetIronGolemSpawningLocation(MathHelper.floor_float((float)this.center.posX), MathHelper.floor_float((float)this.center.posY), MathHelper.floor_float((float)this.center.posZ), 2, 4, 2); 058 059 if (var3 != null) 060 { 061 EntityIronGolem var4 = new EntityIronGolem(this.worldObj); 062 var4.setPosition(var3.xCoord, var3.yCoord, var3.zCoord); 063 this.worldObj.spawnEntityInWorld(var4); 064 ++this.numIronGolems; 065 } 066 } 067 } 068 069 /** 070 * Tries up to 10 times to get a valid spawning location before eventually failing and returning null. 071 */ 072 private Vec3 tryGetIronGolemSpawningLocation(int par1, int par2, int par3, int par4, int par5, int par6) 073 { 074 for (int var7 = 0; var7 < 10; ++var7) 075 { 076 int var8 = par1 + this.worldObj.rand.nextInt(16) - 8; 077 int var9 = par2 + this.worldObj.rand.nextInt(6) - 3; 078 int var10 = par3 + this.worldObj.rand.nextInt(16) - 8; 079 080 if (this.isInRange(var8, var9, var10) && this.isValidIronGolemSpawningLocation(var8, var9, var10, par4, par5, par6)) 081 { 082 return Vec3.getVec3Pool().getVecFromPool((double)var8, (double)var9, (double)var10); 083 } 084 } 085 086 return null; 087 } 088 089 private boolean isValidIronGolemSpawningLocation(int par1, int par2, int par3, int par4, int par5, int par6) 090 { 091 if (!this.worldObj.doesBlockHaveSolidTopSurface(par1, par2 - 1, par3)) 092 { 093 return false; 094 } 095 else 096 { 097 int var7 = par1 - par4 / 2; 098 int var8 = par3 - par6 / 2; 099 100 for (int var9 = var7; var9 < var7 + par4; ++var9) 101 { 102 for (int var10 = par2; var10 < par2 + par5; ++var10) 103 { 104 for (int var11 = var8; var11 < var8 + par6; ++var11) 105 { 106 if (this.worldObj.isBlockNormalCube(var9, var10, var11)) 107 { 108 return false; 109 } 110 } 111 } 112 } 113 114 return true; 115 } 116 } 117 118 private void updateNumIronGolems() 119 { 120 List var1 = this.worldObj.getEntitiesWithinAABB(EntityIronGolem.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)(this.center.posX - this.villageRadius), (double)(this.center.posY - 4), (double)(this.center.posZ - this.villageRadius), (double)(this.center.posX + this.villageRadius), (double)(this.center.posY + 4), (double)(this.center.posZ + this.villageRadius))); 121 this.numIronGolems = var1.size(); 122 } 123 124 private void updateNumVillagers() 125 { 126 List var1 = this.worldObj.getEntitiesWithinAABB(EntityVillager.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)(this.center.posX - this.villageRadius), (double)(this.center.posY - 4), (double)(this.center.posZ - this.villageRadius), (double)(this.center.posX + this.villageRadius), (double)(this.center.posY + 4), (double)(this.center.posZ + this.villageRadius))); 127 this.numVillagers = var1.size(); 128 } 129 130 public ChunkCoordinates getCenter() 131 { 132 return this.center; 133 } 134 135 public int getVillageRadius() 136 { 137 return this.villageRadius; 138 } 139 140 /** 141 * Actually get num village door info entries, but that boils down to number of doors. Called by 142 * EntityAIVillagerMate and VillageSiege 143 */ 144 public int getNumVillageDoors() 145 { 146 return this.villageDoorInfoList.size(); 147 } 148 149 public int getTicksSinceLastDoorAdding() 150 { 151 return this.tickCounter - this.lastAddDoorTimestamp; 152 } 153 154 public int getNumVillagers() 155 { 156 return this.numVillagers; 157 } 158 159 /** 160 * Returns true, if the given coordinates are within the bounding box of the village. 161 */ 162 public boolean isInRange(int par1, int par2, int par3) 163 { 164 return this.center.getDistanceSquared(par1, par2, par3) < (float)(this.villageRadius * this.villageRadius); 165 } 166 167 /** 168 * called only by class EntityAIMoveThroughVillage 169 */ 170 public List getVillageDoorInfoList() 171 { 172 return this.villageDoorInfoList; 173 } 174 175 public VillageDoorInfo findNearestDoor(int par1, int par2, int par3) 176 { 177 VillageDoorInfo var4 = null; 178 int var5 = Integer.MAX_VALUE; 179 Iterator var6 = this.villageDoorInfoList.iterator(); 180 181 while (var6.hasNext()) 182 { 183 VillageDoorInfo var7 = (VillageDoorInfo)var6.next(); 184 int var8 = var7.getDistanceSquared(par1, par2, par3); 185 186 if (var8 < var5) 187 { 188 var4 = var7; 189 var5 = var8; 190 } 191 } 192 193 return var4; 194 } 195 196 /** 197 * Find a door suitable for shelter. If there are more doors in a distance of 16 blocks, then the least restricted 198 * one (i.e. the one protecting the lowest number of villagers) of them is chosen, else the nearest one regardless 199 * of restriction. 200 */ 201 public VillageDoorInfo findNearestDoorUnrestricted(int par1, int par2, int par3) 202 { 203 VillageDoorInfo var4 = null; 204 int var5 = Integer.MAX_VALUE; 205 Iterator var6 = this.villageDoorInfoList.iterator(); 206 207 while (var6.hasNext()) 208 { 209 VillageDoorInfo var7 = (VillageDoorInfo)var6.next(); 210 int var8 = var7.getDistanceSquared(par1, par2, par3); 211 212 if (var8 > 256) 213 { 214 var8 *= 1000; 215 } 216 else 217 { 218 var8 = var7.getDoorOpeningRestrictionCounter(); 219 } 220 221 if (var8 < var5) 222 { 223 var4 = var7; 224 var5 = var8; 225 } 226 } 227 228 return var4; 229 } 230 231 public VillageDoorInfo getVillageDoorAt(int par1, int par2, int par3) 232 { 233 if (this.center.getDistanceSquared(par1, par2, par3) > (float)(this.villageRadius * this.villageRadius)) 234 { 235 return null; 236 } 237 else 238 { 239 Iterator var4 = this.villageDoorInfoList.iterator(); 240 VillageDoorInfo var5; 241 242 do 243 { 244 if (!var4.hasNext()) 245 { 246 return null; 247 } 248 249 var5 = (VillageDoorInfo)var4.next(); 250 } 251 while (var5.posX != par1 || var5.posZ != par3 || Math.abs(var5.posY - par2) > 1); 252 253 return var5; 254 } 255 } 256 257 public void addVillageDoorInfo(VillageDoorInfo par1VillageDoorInfo) 258 { 259 this.villageDoorInfoList.add(par1VillageDoorInfo); 260 this.centerHelper.posX += par1VillageDoorInfo.posX; 261 this.centerHelper.posY += par1VillageDoorInfo.posY; 262 this.centerHelper.posZ += par1VillageDoorInfo.posZ; 263 this.updateVillageRadiusAndCenter(); 264 this.lastAddDoorTimestamp = par1VillageDoorInfo.lastActivityTimestamp; 265 } 266 267 /** 268 * Returns true, if there is not a single village door left. Called by VillageCollection 269 */ 270 public boolean isAnnihilated() 271 { 272 return this.villageDoorInfoList.isEmpty(); 273 } 274 275 public void addOrRenewAgressor(EntityLiving par1EntityLiving) 276 { 277 Iterator var2 = this.villageAgressors.iterator(); 278 VillageAgressor var3; 279 280 do 281 { 282 if (!var2.hasNext()) 283 { 284 this.villageAgressors.add(new VillageAgressor(this, par1EntityLiving, this.tickCounter)); 285 return; 286 } 287 288 var3 = (VillageAgressor)var2.next(); 289 } 290 while (var3.agressor != par1EntityLiving); 291 292 var3.agressionTime = this.tickCounter; 293 } 294 295 public EntityLiving findNearestVillageAggressor(EntityLiving par1EntityLiving) 296 { 297 double var2 = Double.MAX_VALUE; 298 VillageAgressor var4 = null; 299 Iterator var5 = this.villageAgressors.iterator(); 300 301 while (var5.hasNext()) 302 { 303 VillageAgressor var6 = (VillageAgressor)var5.next(); 304 double var7 = var6.agressor.getDistanceSqToEntity(par1EntityLiving); 305 306 if (var7 <= var2) 307 { 308 var4 = var6; 309 var2 = var7; 310 } 311 } 312 313 return var4 != null ? var4.agressor : null; 314 } 315 316 private void removeDeadAndOldAgressors() 317 { 318 Iterator var1 = this.villageAgressors.iterator(); 319 320 while (var1.hasNext()) 321 { 322 VillageAgressor var2 = (VillageAgressor)var1.next(); 323 324 if (!var2.agressor.isEntityAlive() || Math.abs(this.tickCounter - var2.agressionTime) > 300) 325 { 326 var1.remove(); 327 } 328 } 329 } 330 331 private void removeDeadAndOutOfRangeDoors() 332 { 333 boolean var1 = false; 334 boolean var2 = this.worldObj.rand.nextInt(50) == 0; 335 Iterator var3 = this.villageDoorInfoList.iterator(); 336 337 while (var3.hasNext()) 338 { 339 VillageDoorInfo var4 = (VillageDoorInfo)var3.next(); 340 341 if (var2) 342 { 343 var4.resetDoorOpeningRestrictionCounter(); 344 } 345 346 if (!this.isBlockDoor(var4.posX, var4.posY, var4.posZ) || Math.abs(this.tickCounter - var4.lastActivityTimestamp) > 1200) 347 { 348 this.centerHelper.posX -= var4.posX; 349 this.centerHelper.posY -= var4.posY; 350 this.centerHelper.posZ -= var4.posZ; 351 var1 = true; 352 var4.isDetachedFromVillageFlag = true; 353 var3.remove(); 354 } 355 } 356 357 if (var1) 358 { 359 this.updateVillageRadiusAndCenter(); 360 } 361 } 362 363 private boolean isBlockDoor(int par1, int par2, int par3) 364 { 365 int var4 = this.worldObj.getBlockId(par1, par2, par3); 366 return var4 <= 0 ? false : var4 == Block.doorWood.blockID; 367 } 368 369 private void updateVillageRadiusAndCenter() 370 { 371 int var1 = this.villageDoorInfoList.size(); 372 373 if (var1 == 0) 374 { 375 this.center.set(0, 0, 0); 376 this.villageRadius = 0; 377 } 378 else 379 { 380 this.center.set(this.centerHelper.posX / var1, this.centerHelper.posY / var1, this.centerHelper.posZ / var1); 381 int var2 = 0; 382 VillageDoorInfo var4; 383 384 for (Iterator var3 = this.villageDoorInfoList.iterator(); var3.hasNext(); var2 = Math.max(var4.getDistanceSquared(this.center.posX, this.center.posY, this.center.posZ), var2)) 385 { 386 var4 = (VillageDoorInfo)var3.next(); 387 } 388 389 this.villageRadius = Math.max(32, (int)Math.sqrt((double)var2) + 1); 390 } 391 } 392 }