Modding: Custom crop part 5: Bonemeal

In this tutorial I’m going to show you how to use bonemeal on one of your plants. A part of this code is done inside of your Block file and also a part in your mod file. This is the block file I will start with.


package Tutorial.common;

import java.util.Random;

import net.minecraft.src.Block;
import net.minecraft.src.BlockFlower;
import net.minecraft.src.CreativeTabs;
import net.minecraft.src.EntityItem;
import net.minecraft.src.ItemStack;
import net.minecraft.src.World;

public class BlockCropTutorial extends BlockFlower
{
protected BlockCropTutorial(int par1, int par2)
    {
        super(par1, par2);
        blockIndexInTexture = par2;
        setTickRandomly(true);
        float f = 0.5F;
        setBlockBounds(0.5F – f, 0.0F, 0.5F – f, 0.5F + f, 0.25F, 0.5F + f);
        this.setCreativeTab((CreativeTabs)null);
        this.disableStats();
        this.setRequiresSelfNotify();
    }

public String getTextureFile()
    {
            return “/TutTextures.png”;
    }

public int getRenderType()
    {
        return 6;
    }

public int getBlockTextureFromSideAndMetadata(int par1, int par2)
    {
switch(par2)
{
case 0:
return 2;
case 1:
return 3;
case 2:
return 4;
default:
return 0;
}
    }

public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
    {
        super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0);

        if (par1World.isRemote)
        {
            return;
        }

        int i = 3 + par7;

        for (int j = 0; j < i; j++)
        {
            if (par1World.rand.nextInt(5) == 0)
            {
                float f = 0.7F;
                float f1 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                float f2 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                float f3 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                EntityItem entityitem = new EntityItem(par1World, (float)par2 + f1, (float)par3 + f2, (float)par4 + f3, new ItemStack(Tutorial.cropseed));
                entityitem.delayBeforeCanPickup = 10;
                par1World.spawnEntityInWorld(entityitem);
            }
        }
    }

    public int idDropped(int par1, Random par2Random, int par3)
    {
        if (par1 == 2)
        {
            return Tutorial.yourfood.shiftedIndex;
        }
        else
        {
            return -1;
        }
    }
    
    public int quantityDropped(Random par1Random)
    {
        return 1;
    }
    
    public int idPicked(World par1World, int par2, int par3, int par4)
    {
        return Tutorial.cropseed.shiftedIndex;
    }

protected boolean canThisPlantGrowOnThisBlockID(int par1)
    {
        return par1 == Block.grass.blockID;
    }

public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
    {
        super.updateTick(par1World, par2, par3, par4, par5Random);

        if (par1World.getBlockLightValue(par2, par3 + 1, par4) >= 9)
        {
            int i = par1World.getBlockMetadata(par2, par3, par4);

            if (i < 2)
            {
                float f = getGrowthRate(par1World, par2, par3, par4);

                if (par5Random.nextInt((int)(25F / f) + 1) == 0)
                {
                    i++;
                    par1World.setBlockMetadataWithNotify(par2, par3, par4, i);
                }
            }
        }
    }

private float getGrowthRate(World par1World, int par2, int par3, int par4)
    {
        float f = 1.0F;
        int i = par1World.getBlockId(par2, par3, par4 – 1);
        int j = par1World.getBlockId(par2, par3, par4 + 1);
        int k = par1World.getBlockId(par2 – 1, par3, par4);
        int l = par1World.getBlockId(par2 + 1, par3, par4);
        int i1 = par1World.getBlockId(par2 – 1, par3, par4 – 1);
        int j1 = par1World.getBlockId(par2 + 1, par3, par4 – 1);
        int k1 = par1World.getBlockId(par2 + 1, par3, par4 + 1);
        int l1 = par1World.getBlockId(par2 – 1, par3, par4 + 1);
        boolean flag = k == blockID || l == blockID;
        boolean flag1 = i == blockID || j == blockID;
        boolean flag2 = i1 == blockID || j1 == blockID || k1 == blockID || l1 == blockID;

        for (int i2 = par2 – 1; i2 <= par2 + 1; i2++)
        {
            for (int j2 = par4 – 1; j2 <= par4 + 1; j2++)
            {
                int k2 = par1World.getBlockId(i2, par3 – 1, j2);
                float f1 = 0.0F;

                if (k2 == Block.grass.blockID)
                {
                    f1 = 1.0F;

                    if (par1World.getBlockMetadata(i2, par3 – 1, j2) > 0)
                    {
                        f1 = 3F;
                    }
                }

                if (i2 != par2 || j2 != par4)
                {
                    f1 /= 4F;
                }

                f += f1;
            }
        }

        if (flag2 || flag && flag1)
        {
            f /= 2.0F;
        }

        return f;
    }
}


And this is the mod file.


package Tutorial.common;

import net.minecraft.src.Block;
import net.minecraft.src.EnumToolMaterial;
import net.minecraft.src.Item;
import net.minecraft.src.ItemStack;
import net.minecraftforge.common.DungeonHooks;
import net.minecraftforge.common.EnumHelper;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid = “YourName_ModName”, name = “ModName”, version = “Version number”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial 
{
//blocks
public static Block oreblock;
public static Block cropblock;

public static int oreblockId = 230;

//items
public static Item youritem;
public static Item yourfood;
public static Item yoursword;
public static Item yourpick;
public static Item yourshovel;
public static Item cropseed;

//proxy
@SidedProxy(clientSide = “Tutorial.client.ClientProxyTutorial”, serverSide = “Tutorial.common.CommonProxyTutorial”)
    public static CommonProxyTutorial proxy;

//enums
static EnumToolMaterial yourtoolmaterial = EnumHelper.addToolMaterial(“yourmaterial”, 2, 500, 7F, 2, 14);

@Init
public void load(FMLInitializationEvent event)
{
//proxy
proxy.registerRenderThings();

//blocks
oreblock = new BlockOres(oreblockId, 0).setStepSound(Block.soundStoneFootstep).setHardness(3F).setResistance(1.0F).setBlockName(“oreblock”);
cropblock = new BlockCropTutorial(231, 1).setStepSound(Block.soundGrassFootstep).setHardness(0.0F).setBlockName(“cropblock”);

GameRegistry.registerBlock(cropblock);

//metadata register
Item.itemsList[oreblockId] = new ItemBlockOres(oreblockId-256, oreblock).setItemName(“oreblock”);

//block names
LanguageRegistry.instance().addStringLocalization(“tile.oreblock.ore.name”, “Your Ore”);
LanguageRegistry.instance().addStringLocalization(“tile.oreblock.netherore.name”, “Your Nether Ore”);
LanguageRegistry.addName(cropblock, “Custom Crop”);

//items
youritem = new ItemTutorial(550).setIconIndex(1).setItemName(“youritem”);
yourfood = new ItemTutorialFood(551, 8, true).setIconIndex(3).setItemName(“yourfood”);
yoursword = new ItemYourSword(552, yourtoolmaterial).setIconIndex(4).setItemName(“yoursword”);
yourpick = new ItemYourPick(553, yourtoolmaterial).setIconIndex(5).setItemName(“yourpick”);
yourshovel = new ItemYourShovel(554, yourtoolmaterial).setIconIndex(6).setItemName(“yourshovel”);
cropseed = new Itemcropseed(555, cropblock.blockID, Block.grass.blockID).setIconIndex(7).setItemName(“flaxseed”);

//item names
LanguageRegistry.addName(youritem, “Your Item”);
LanguageRegistry.addName(yourfood, “Your Food”);
LanguageRegistry.addName(yoursword, “Your Sword”);
LanguageRegistry.addName(yourpick, “Your Pickaxe”);
LanguageRegistry.addName(yourshovel, “Your Shovel”);
LanguageRegistry.addName(cropseed, “Your Crop Seed”);

//dungeon
DungeonHooks.addDungeonLoot(new ItemStack(youritem), 10, 2, 5);
DungeonHooks.setDungeonLootTries(50);

//game registry
GameRegistry.registerFuelHandler(new TutorialFuel());
GameRegistry.registerWorldGenerator(new WorldgeneratorTutorial());

//recipes
GameRegistry.addRecipe(new ItemStack(yoursword), new Object[]
{
“X”, “X”, “Z”, ‘X’, youritem, ‘Z’, Item.stick
});
GameRegistry.addRecipe(new ItemStack(yourpick), new Object[]
{
“XXX”, ” Z “, ” Z “, ‘X’, youritem, ‘Z’, Item.stick
});
GameRegistry.addRecipe(new ItemStack(yourshovel), new Object[]
{
“X”, “Z”, “Z”, ‘X’, youritem, ‘Z’, Item.stick
});
}
}


To make sure that bonemeal changes the metadata of the crop to the one you want you will have to add this method to your block file.


public void fertilize(World par1World, int par2, int par3, int par4)
    {
        par1World.setBlockMetadataWithNotify(par2, par3, par4, 2);
    }


The 2 at the end of the line is the metadata. If you want the metadata to become 5 you change the 2 into a 5. The whole file should now look like this.


package Tutorial.common;

import java.util.Random;

import net.minecraft.src.Block;
import net.minecraft.src.BlockFlower;
import net.minecraft.src.CreativeTabs;
import net.minecraft.src.EntityItem;
import net.minecraft.src.ItemStack;
import net.minecraft.src.World;

public class BlockCropTutorial extends BlockFlower
{
protected BlockCropTutorial(int par1, int par2)
    {
        super(par1, par2);
        blockIndexInTexture = par2;
        setTickRandomly(true);
        float f = 0.5F;
        setBlockBounds(0.5F – f, 0.0F, 0.5F – f, 0.5F + f, 0.25F, 0.5F + f);
        this.setCreativeTab((CreativeTabs)null);
        this.disableStats();
        this.setRequiresSelfNotify();
    }

public String getTextureFile()
    {
            return “/TutTextures.png”;
    }

public int getRenderType()
    {
        return 6;
    }

public int getBlockTextureFromSideAndMetadata(int par1, int par2)
    {
switch(par2)
{
case 0:
return 2;
case 1:
return 3;
case 2:
return 4;
default:
return 0;
}
    }

public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7)
    {
        super.dropBlockAsItemWithChance(par1World, par2, par3, par4, par5, par6, 0);

        if (par1World.isRemote)
        {
            return;
        }

        int i = 3 + par7;

        for (int j = 0; j < i; j++)
        {
            if (par1World.rand.nextInt(5) == 0)
            {
                float f = 0.7F;
                float f1 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                float f2 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                float f3 = par1World.rand.nextFloat() * f + (1.0F – f) * 0.5F;
                EntityItem entityitem = new EntityItem(par1World, (float)par2 + f1, (float)par3 + f2, (float)par4 + f3, new ItemStack(Tutorial.cropseed));
                entityitem.delayBeforeCanPickup = 10;
                par1World.spawnEntityInWorld(entityitem);
            }
        }
    }

    public int idDropped(int par1, Random par2Random, int par3)
    {
        if (par1 == 2)
        {
            return Tutorial.yourfood.shiftedIndex;
        }
        else
        {
            return -1;
        }
    }
    
    public int quantityDropped(Random par1Random)
    {
        return 1;
    }
    
    public int idPicked(World par1World, int par2, int par3, int par4)
    {
        return Tutorial.cropseed.shiftedIndex;
    }

protected boolean canThisPlantGrowOnThisBlockID(int par1)
    {
        return par1 == Block.grass.blockID;
    }

public void fertilize(World par1World, int par2, int par3, int par4)
    {
        par1World.setBlockMetadataWithNotify(par2, par3, par4, 2);
    }

public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
    {
        super.updateTick(par1World, par2, par3, par4, par5Random);

        if (par1World.getBlockLightValue(par2, par3 + 1, par4) >= 9)
        {
            int i = par1World.getBlockMetadata(par2, par3, par4);

            if (i < 2)
            {
                float f = getGrowthRate(par1World, par2, par3, par4);

                if (par5Random.nextInt((int)(25F / f) + 1) == 0)
                {
                    i++;
                    par1World.setBlockMetadataWithNotify(par2, par3, par4, i);
                }
            }
        }
    }

private float getGrowthRate(World par1World, int par2, int par3, int par4)
    {
        float f = 1.0F;
        int i = par1World.getBlockId(par2, par3, par4 – 1);
        int j = par1World.getBlockId(par2, par3, par4 + 1);
        int k = par1World.getBlockId(par2 – 1, par3, par4);
        int l = par1World.getBlockId(par2 + 1, par3, par4);
        int i1 = par1World.getBlockId(par2 – 1, par3, par4 – 1);
        int j1 = par1World.getBlockId(par2 + 1, par3, par4 – 1);
        int k1 = par1World.getBlockId(par2 + 1, par3, par4 + 1);
        int l1 = par1World.getBlockId(par2 – 1, par3, par4 + 1);
        boolean flag = k == blockID || l == blockID;
        boolean flag1 = i == blockID || j == blockID;
        boolean flag2 = i1 == blockID || j1 == blockID || k1 == blockID || l1 == blockID;

        for (int i2 = par2 – 1; i2 <= par2 + 1; i2++)
        {
            for (int j2 = par4 – 1; j2 <= par4 + 1; j2++)
            {
                int k2 = par1World.getBlockId(i2, par3 – 1, j2);
                float f1 = 0.0F;

                if (k2 == Block.grass.blockID)
                {
                    f1 = 1.0F;

                    if (par1World.getBlockMetadata(i2, par3 – 1, j2) > 0)
                    {
                        f1 = 3F;
                    }
                }

                if (i2 != par2 || j2 != par4)
                {
                    f1 /= 4F;
                }

                f += f1;
            }
        }

        if (flag2 || flag && flag1)
        {
            f /= 2.0F;
        }

        return f;
    }
}


Now you just need to make sure that that method gets called when you right click bonemeal on it. To do that you will have to add this line to your mod file.


MinecraftForge.EVENT_BUS.register(new TutorialEvent());


The only thing you can change with this line is the TutorialEvent. That is the class name and could be anything you want.
The whole file should now look something like this.


package Tutorial.common;

import net.minecraft.src.Block;
import net.minecraft.src.EnumToolMaterial;
import net.minecraft.src.Item;
import net.minecraft.src.ItemStack;
import net.minecraftforge.common.DungeonHooks;
import net.minecraftforge.common.EnumHelper;
import net.minecraftforge.common.MinecraftForge;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid = “YourName_ModName”, name = “ModName”, version = “Version number”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial 
{
//blocks
public static Block oreblock;
public static Block cropblock;

public static int oreblockId = 230;

//items
public static Item youritem;
public static Item yourfood;
public static Item yoursword;
public static Item yourpick;
public static Item yourshovel;
public static Item cropseed;

//proxy
@SidedProxy(clientSide = “Tutorial.client.ClientProxyTutorial”, serverSide = “Tutorial.common.CommonProxyTutorial”)
    public static CommonProxyTutorial proxy;

//enums
static EnumToolMaterial yourtoolmaterial = EnumHelper.addToolMaterial(“yourmaterial”, 2, 500, 7F, 2, 14);

@Init
public void load(FMLInitializationEvent event)
{
//proxy
proxy.registerRenderThings();

//blocks
oreblock = new BlockOres(oreblockId, 0).setStepSound(Block.soundStoneFootstep).setHardness(3F).setResistance(1.0F).setBlockName(“oreblock”);
cropblock = new BlockCropTutorial(231, 1).setStepSound(Block.soundGrassFootstep).setHardness(0.0F).setBlockName(“cropblock”);

GameRegistry.registerBlock(cropblock);

//metadata register
Item.itemsList[oreblockId] = new ItemBlockOres(oreblockId-256, oreblock).setItemName(“oreblock”);

//block names
LanguageRegistry.instance().addStringLocalization(“tile.oreblock.ore.name”, “Your Ore”);
LanguageRegistry.instance().addStringLocalization(“tile.oreblock.netherore.name”, “Your Nether Ore”);
LanguageRegistry.addName(cropblock, “Custom Crop”);

//items
youritem = new ItemTutorial(550).setIconIndex(1).setItemName(“youritem”);
yourfood = new ItemTutorialFood(551, 8, true).setIconIndex(3).setItemName(“yourfood”);
yoursword = new ItemYourSword(552, yourtoolmaterial).setIconIndex(4).setItemName(“yoursword”);
yourpick = new ItemYourPick(553, yourtoolmaterial).setIconIndex(5).setItemName(“yourpick”);
yourshovel = new ItemYourShovel(554, yourtoolmaterial).setIconIndex(6).setItemName(“yourshovel”);
cropseed = new Itemcropseed(555, cropblock.blockID, Block.grass.blockID).setIconIndex(7).setItemName(“flaxseed”);

//item names
LanguageRegistry.addName(youritem, “Your Item”);
LanguageRegistry.addName(yourfood, “Your Food”);
LanguageRegistry.addName(yoursword, “Your Sword”);
LanguageRegistry.addName(yourpick, “Your Pickaxe”);
LanguageRegistry.addName(yourshovel, “Your Shovel”);
LanguageRegistry.addName(cropseed, “Your Crop Seed”);

MinecraftForge.EVENT_BUS.register(new TutorialEvent());

//dungeon
DungeonHooks.addDungeonLoot(new ItemStack(youritem), 10, 2, 5);
DungeonHooks.setDungeonLootTries(50);

//game registry
GameRegistry.registerFuelHandler(new TutorialFuel());
GameRegistry.registerWorldGenerator(new WorldgeneratorTutorial());

//recipes
GameRegistry.addRecipe(new ItemStack(yoursword), new Object[]
{
“X”, “X”, “Z”, ‘X’, youritem, ‘Z’, Item.stick
});
GameRegistry.addRecipe(new ItemStack(yourpick), new Object[]
{
“XXX”, ” Z “, ” Z “, ‘X’, youritem, ‘Z’, Item.stick
});
GameRegistry.addRecipe(new ItemStack(yourshovel), new Object[]
{
“X”, “Z”, “Z”, ‘X’, youritem, ‘Z’, Item.stick
});
}
}


The TutorialEvent class should use like this.


package Tutorial.common;

import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.player.BonemealEvent;

public class TutorialEvent 
{
@ForgeSubscribe
    public void bonemealUsed(BonemealEvent event)
    {
if(event.world.getBlockId(event.X, event.Y, event.Z)== Tutorial.cropblock.blockID)
        {
        ((BlockCropTutorial)Tutorial.cropblock).fertilize(event.world, event.X, event.Y, event.Z);
        }
    }
}


Tutorial.cropblock has to be your mod file and block that you would like to fertilize. BlockCropTutorial has to be the file that that block is inside.
That is everything you have to do to get bonemeal to work on a crop block.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">