001package net.minecraft.world.gen.structure;
002
003import java.util.List;
004import java.util.Random;
005import net.minecraft.block.Block;
006import net.minecraft.entity.passive.EntityVillager;
007import net.minecraft.world.World;
008
009import net.minecraftforge.common.*;
010import net.minecraftforge.event.Event.*;
011import net.minecraftforge.event.terraingen.*;
012
013public 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 i = 0;
074        int j = 0;
075
076        for (int k = this.boundingBox.minZ; k <= this.boundingBox.maxZ; ++k)
077        {
078            for (int l = this.boundingBox.minX; l <= this.boundingBox.maxX; ++l)
079            {
080                if (par2StructureBoundingBox.isVecInside(l, 64, k))
081                {
082                    i += Math.max(par1World.getTopSolidOrLiquidBlock(l, k), par1World.provider.getAverageGroundLevel());
083                    ++j;
084                }
085            }
086        }
087
088        if (j == 0)
089        {
090            return -1;
091        }
092        else
093        {
094            return i / j;
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 i1 = this.villagersSpawned; i1 < par6; ++i1)
112            {
113                int j1 = this.getXWithOffset(par3 + i1, par5);
114                int k1 = this.getYWithOffset(par4);
115                int l1 = this.getZWithOffset(par3 + i1, par5);
116
117                if (!par2StructureBoundingBox.isVecInside(j1, k1, l1))
118                {
119                    break;
120                }
121
122                ++this.villagersSpawned;
123                EntityVillager entityvillager = new EntityVillager(par1World, this.getVillagerType(i1));
124                entityvillager.setLocationAndAngles((double)j1 + 0.5D, (double)k1, (double)l1 + 0.5D, 0.0F, 0.0F);
125                par1World.spawnEntityInWorld(entityvillager);
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 j1 = this.getBiomeSpecificBlock(par2, par3);
219        int k1 = this.getBiomeSpecificBlockMetadata(par2, par3);
220        super.placeBlockAtCurrentPosition(par1World, j1, k1, 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 i2 = this.getBiomeSpecificBlock(par9, 0);
230        int j2 = this.getBiomeSpecificBlockMetadata(par9, 0);
231        int k2 = this.getBiomeSpecificBlock(par10, 0);
232        int l2 = this.getBiomeSpecificBlockMetadata(par10, 0);
233        super.fillWithMetadataBlocks(par1World, par2StructureBoundingBox, par3, par4, par5, par6, par7, par8, i2, j2, k2, l2, 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 j1 = this.getBiomeSpecificBlock(par2, par3);
242        int k1 = this.getBiomeSpecificBlockMetadata(par2, par3);
243        super.fillCurrentPositionBlocksDownwards(par1World, j1, k1, par4, par5, par6, par7StructureBoundingBox);
244    }
245}