    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}