Modding: Custom crop part 2: The crop file

In this tutorial I will show you how to create your own crops. In part 1 of this tutorial I stopped with this 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;

//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”);

//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”);

//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
});
}
}


In this part I will show you how to create the BlockCropTutorial file.
The first thing you have to do is hover you mouse over the BlockCropTutorial name and click create file.
You will get a file that looks like this.


package Tutorial.common;

public class BlockCropTutorial 
{

}


The first thing that you will have to do is make this file extend BlockFlower. When you do this it will give you an error under BlockCropTutorial. This is because you haven’t added a method that is needed for this block. The method you should add should look like this.


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();
    }


Make sure that the name of it is the same as your file name, because it is the constructor.
super(par1, par2) is the same with every block. It just gives the id and texture to the extended block.
blockIndexInTexture = par2; sets the texture variable (blockIndexInTexture) to the number you set it to in your mod file.
setTickRandomly(true) is used to let the block tick randomly. Those random ticks are used for growth etc.
The 2 lines after this are used to set the hitbox of the plant. I suggest playing around with this for a while to find out the perfect size for your block.
this.setCreativeTab((CreativeTabs)null); sets the tab this block is shown on to nothing. This is because you don’t want this one to show up. You only want the seed item which I will show you how to make in a later tutorial.
this.disableStats() and this.setRequiresSelfNotify() are both needed for a plant like this. It has something to do with the metadata.

Another method that you will have to add is this one.


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);
                }
            }
        }
    }


This method handles the growth of the block. There are only 2 parts of this code that are interesting.
The first one is the par1World.getBlockLightValue. this method gets the light value of a block. If you want a crop that only grows in the light you can use this. In this example it will only grow with a light value that is the same as or higher than 9.
The second important part is the i < 2. This part of the code handles the amount of stages of the plant. In this case there will be a metadata of 0 and of 1 and 2. If you change the 2 into a 3 there will also be metadata 3. The metadata’s are the growth stages of the block.

When you add this code you will get an error under getGrowthRate. To fix this you have to add this method.


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;
    }


This method does 2 things. The first is to get the growth speed. The second is to make sure that the block below is the block it should be. In this case the block should be grass.

To make sure that this block can only stay on grass you can add this method.


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


If you want your plant to grow on for example stone you change the Block.grass into Block.stone. Another thing you need to make sure is that you change the Block.grass from getGrowthRate into Block.stone.

In the next tutorial I will show you how to do the rendering, textures and items dropping.

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="">