001 package net.minecraft.world.gen.structure;
002
003 import java.util.List;
004 import java.util.Random;
005 import net.minecraft.block.Block;
006 import net.minecraft.entity.passive.EntityVillager;
007 import net.minecraft.world.World;
008
009 import net.minecraftforge.common.*;
010 import net.minecraftforge.event.Event.*;
011 import net.minecraftforge.event.terraingen.*;
012
013 public abstract class ComponentVillage extends StructureComponent
014 {
015 /** The number of villagers that have been spawned in this component. */
016 private int villagersSpawned;
017
018 /** The starting piece of the village. */
019 protected ComponentVillageStartPiece startPiece;
020
021 protected ComponentVillage(ComponentVillageStartPiece par1ComponentVillageStartPiece, int par2)
022 {
023 super(par2);
024 this.startPiece = par1ComponentVillageStartPiece;
025 }
026
027 /**
028 * Gets the next village component, with the bounding box shifted -1 in the X and Z direction.
029 */
030 protected StructureComponent getNextComponentNN(ComponentVillageStartPiece par1ComponentVillageStartPiece, List par2List, Random par3Random, int par4, int par5)
031 {
032 switch (this.coordBaseMode)
033 {
034 case 0:
035 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX - 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 1, this.getComponentType());
036 case 1:
037 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.minZ - 1, 2, this.getComponentType());
038 case 2:
039 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX - 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 1, this.getComponentType());
040 case 3:
041 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.minZ - 1, 2, this.getComponentType());
042 default:
043 return null;
044 }
045 }
046
047 /**
048 * Gets the next village component, with the bounding box shifted +1 in the X and Z direction.
049 */
050 protected StructureComponent getNextComponentPP(ComponentVillageStartPiece par1ComponentVillageStartPiece, List par2List, Random par3Random, int par4, int par5)
051 {
052 switch (this.coordBaseMode)
053 {
054 case 0:
055 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.maxX + 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 3, this.getComponentType());
056 case 1:
057 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.maxZ + 1, 0, this.getComponentType());
058 case 2:
059 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.maxX + 1, this.boundingBox.minY + par4, this.boundingBox.minZ + par5, 3, this.getComponentType());
060 case 3:
061 return StructureVillagePieces.getNextStructureComponent(par1ComponentVillageStartPiece, par2List, par3Random, this.boundingBox.minX + par5, this.boundingBox.minY + par4, this.boundingBox.maxZ + 1, 0, this.getComponentType());
062 default:
063 return null;
064 }
065 }
066
067 /**
068 * Discover the y coordinate that will serve as the ground level of the supplied BoundingBox. (A median of all the
069 * levels in the BB's horizontal rectangle).
070 */
071 protected int getAverageGroundLevel(World par1World, StructureBoundingBox par2StructureBoundingBox)
072 {
073 int var3 = 0;
074 int var4 = 0;
075
076 for (int var5 = this.boundingBox.minZ; var5 <= this.boundingBox.maxZ; ++var5)
077 {
078 for (int var6 = this.boundingBox.minX; var6 <= this.boundingBox.maxX; ++var6)
079 {
080 if (par2StructureBoundingBox.isVecInside(var6, 64, var5))
081 {
082 var3 += Math.max(par1World.getTopSolidOrLiquidBlock(var6, var5), par1World.provider.getAverageGroundLevel());
083 ++var4;
084 }
085 }
086 }
087
088 if (var4 == 0)
089 {
090 return -1;
091 }
092 else
093 {
094 return var3 / var4;
095 }
096 }
097
098 protected static boolean canVillageGoDeeper(StructureBoundingBox par0StructureBoundingBox)
099 {
100 return par0StructureBoundingBox != null && par0StructureBoundingBox.minY > 10;
101 }
102
103 /**
104 * Spawns a number of villagers in this component. Parameters: world, component bounding box, x offset, y offset, z
105 * offset, number of villagers
106 */
107 protected void spawnVillagers(World par1World, StructureBoundingBox par2StructureBoundingBox, int par3, int par4, int par5, int par6)
108 {
109 if (this.villagersSpawned < par6)
110 {
111 for (int var7 = this.villagersSpawned; var7 < par6; ++var7)
112 {
113 int var8 = this.getXWithOffset(par3 + var7, par5);
114 int var9 = this.getYWithOffset(par4);
115 int var10 = this.getZWithOffset(par3 + var7, par5);
116
117 if (!par2StructureBoundingBox.isVecInside(var8, var9, var10))
118 {
119 break;
120 }
121
122 ++this.villagersSpawned;
123 EntityVillager var11 = new EntityVillager(par1World, this.getVillagerType(var7));
124 var11.setLocationAndAngles((double)var8 + 0.5D, (double)var9, (double)var10 + 0.5D, 0.0F, 0.0F);
125 par1World.spawnEntityInWorld(var11);
126 }
127 }
128 }
129
130 /**
131 * Returns the villager type to spawn in this component, based on the number of villagers already spawned.
132 */
133 protected int getVillagerType(int par1)
134 {
135 return 0;
136 }
137
138 /**
139 * Gets the replacement block for the current biome
140 */
141 protected int getBiomeSpecificBlock(int par1, int par2)
142 {
143 BiomeEvent.GetVillageBlockID event = new BiomeEvent.GetVillageBlockID(startPiece.biome, par1, par2);
144 MinecraftForge.TERRAIN_GEN_BUS.post(event);
145 if (event.getResult() == Result.DENY) return event.replacement;
146
147 if (this.startPiece.inDesert)
148 {
149 if (par1 == Block.wood.blockID)
150 {
151 return Block.sandStone.blockID;
152 }
153
154 if (par1 == Block.cobblestone.blockID)
155 {
156 return Block.sandStone.blockID;
157 }
158
159 if (par1 == Block.planks.blockID)
160 {
161 return Block.sandStone.blockID;
162 }
163
164 if (par1 == Block.stairCompactPlanks.blockID)
165 {
166 return Block.stairsSandStone.blockID;
167 }
168
169 if (par1 == Block.stairCompactCobblestone.blockID)
170 {
171 return Block.stairsSandStone.blockID;
172 }
173
174 if (par1 == Block.gravel.blockID)
175 {
176 return Block.sandStone.blockID;
177 }
178 }
179
180 return par1;
181 }
182
183 /**
184 * Gets the replacement block metadata for the current biome
185 */
186 protected int getBiomeSpecificBlockMetadata(int par1, int par2)
187 {
188 BiomeEvent.GetVillageBlockMeta event = new BiomeEvent.GetVillageBlockMeta(startPiece.biome, par1, par2);
189 MinecraftForge.TERRAIN_GEN_BUS.post(event);
190 if (event.getResult() == Result.DENY) return event.replacement;
191
192 if (this.startPiece.inDesert)
193 {
194 if (par1 == Block.wood.blockID)
195 {
196 return 0;
197 }
198
199 if (par1 == Block.cobblestone.blockID)
200 {
201 return 0;
202 }
203
204 if (par1 == Block.planks.blockID)
205 {
206 return 2;
207 }
208 }
209
210 return par2;
211 }
212
213 /**
214 * current Position depends on currently set Coordinates mode, is computed here
215 */
216 protected void placeBlockAtCurrentPosition(World par1World, int par2, int par3, int par4, int par5, int par6, StructureBoundingBox par7StructureBoundingBox)
217 {
218 int var8 = this.getBiomeSpecificBlock(par2, par3);
219 int var9 = this.getBiomeSpecificBlockMetadata(par2, par3);
220 super.placeBlockAtCurrentPosition(par1World, var8, var9, par4, par5, par6, par7StructureBoundingBox);
221 }
222
223 /**
224 * arguments: (World worldObj, StructureBoundingBox structBB, int minX, int minY, int minZ, int maxX, int maxY, int
225 * maxZ, int placeBlockId, int replaceBlockId, boolean alwaysreplace)
226 */
227 protected void fillWithBlocks(World par1World, StructureBoundingBox par2StructureBoundingBox, int par3, int par4, int par5, int par6, int par7, int par8, int par9, int par10, boolean par11)
228 {
229 int var12 = this.getBiomeSpecificBlock(par9, 0);
230 int var13 = this.getBiomeSpecificBlockMetadata(par9, 0);
231 int var14 = this.getBiomeSpecificBlock(par10, 0);
232 int var15 = this.getBiomeSpecificBlockMetadata(par10, 0);
233 super.fillWithMetadataBlocks(par1World, par2StructureBoundingBox, par3, par4, par5, par6, par7, par8, var12, var13, var14, var15, par11);
234 }
235
236 /**
237 * Overwrites air and liquids from selected position downwards, stops at hitting anything else.
238 */
239 protected void fillCurrentPositionBlocksDownwards(World par1World, int par2, int par3, int par4, int par5, int par6, StructureBoundingBox par7StructureBoundingBox)
240 {
241 int var8 = this.getBiomeSpecificBlock(par2, par3);
242 int var9 = this.getBiomeSpecificBlockMetadata(par2, par3);
243 super.fillCurrentPositionBlocksDownwards(par1World, var8, var9, par4, par5, par6, par7StructureBoundingBox);
244 }
245 }