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