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    }