Creating a Nuke

Okay, so now let’s do something really fun!  One of the pleasures of Minecraft (although a bit psychopathic) is to blow big holes in a virtual world!  So let’s go ahead and create our own nuclear explosion.  We will start with existing Minecraft TNT classes, and then make some changes to those classes.  The classes we will use are:

  • net.minecraft.block.BlockTNT
  • net.minecraft.entity.item.EntityTNTPrimed

There are two things we are going to need to make our Nuke.  The first will be the ability to increase the explosion size to something worthy of being called a Nuke.  The second would be to increase the length of time the fuse takes to ignite.  The fuse is pretty easy.  In the EntityTNTPrimed class, there is a public property, called fuse, which is used for this very purpose.  Unfortunately, for the explosion size, we are not so lucky.  That is done with the explode() method in EntityTNTPrimed.  The bad news is that method is defined as private and we will not be able to directly override that method.  Now the explode() method is only called by the onUpdate() method, which is public and could overridden. 

However, we may want to make other changes down the road and not be directly tied to the current TNT classes, so instead of extending those classes and working around this limitation, let’s fork these classes, and be free to take our own path.  We will create two new classes:

  • reddiamond.block.BlockNuke
  • reddiamond.entity.NukePrimed

The reddiamond.entity Java package will of course need to be created, before creating the NukePrimed class.  Once these two classes have been created, then copy source code from the BlockTNT into BlockNuke, and then the source code from EntityPrimedTNTPrimed to NukePrimed.  You will need to do the copy in two parts.  First copy all the import statements, and then copy everything inside the class definition.  Don’t forget to make sure BlockNuke extends Block and NukePrimed extends Entity. 

Now let’s go through the specific changes we will need to make to convert these into a Nuke.  Starting with the BlockNuke

1.      Change the constructor to BlockNuke, because it will be BlockTNT from the copy

2.      Add class properties to identify the block

public static int id = 3001;
public static String internalName = "nuke";
public static String externalName = "Nuke";

3.      Define class property for the fuse, which will be passed to the NukePrimed

public int fuse;

4.      Change the constructor to initialize the fuse

public BlockNuke(int par1, int fuse) {
        super(par1, Material.tnt);
        this.setCreativeTab(CreativeTabs.tabRedstone);
        this.fuse = fuse;
}

5.      Change the onBlockDestroyedByExplosion() method to use the fuse and NukePrimed class

public void onBlockDestroyedByExplosion(World par1World, 
        int par2, int par3, int par4, 
        Explosion par5Explosion) {
    if (!par1World.isRemote) {
        NukePrimed nukePrimed = new NukePrimed(par1World, 
            (double)((float)par2 + 0.5F), 
            (double)((float)par3 + 0.5F), 
            (double)((float)par4 + 0.5F), 
            par5Explosion.getExplosivePlacedBy());
        nukePrimed.setFuse(fuse);
        nukePrimed.fuse = par1World.rand.nextInt(
             nukePrimed.fuse / 4) + nukePrimed.fuse / 8;
        par1World.spawnEntityInWorld(nukePrimed);
    }
}

6.      Change the primeTnt() method to use the fuse and NukePrimed class

public void primeTnt(World par1World, int par2, int par3, 
        int par4, int par5, 
        EntityLivingBase par6EntityLivingBase) {
    if (!par1World.isRemote) {
        if ((par5 & 1) == 1) {
            NukePrimed nukePrimed = new 
                NukePrimed(par1World, 
                (double)((float)par2 + 0.5F), 
                (double)((float)par3 + 0.5F), 
                (double)((float)par4 + 0.5F), 
                par6EntityLivingBase);
            nukePrimed.setFuse(fuse);
            par1World.spawnEntityInWorld(nukePrimed);
            par1World.playSoundAtEntity(nukePrimed, 
                "random.fuse", 1.0F, 1.0F);
        }
    }
}

7.      Change the names of the texture properties to make more sense

@SideOnly(Side.CLIENT)
private Icon topIcon;
@SideOnly(Side.CLIENT)
private Icon bottomIcon;

 

8.      Change the getIcon() method to use the new variable names

public Icon getIcon(int par1, int par2){
    return par1 == 0 ? this.bottomIcon : (par1 == 1 ? 
        this.topIcon : this.blockIcon);
}

9.      Change the registerIcons() method to use the new variable names and custom texture files

public void registerIcons(IconRegister iconRegister) {
    this.blockIcon = iconRegister.registerIcon(
        RedDiamondInfo.MOD_ID + ":Nuke_side");
    this.topIcon = iconRegister.registerIcon(
        RedDiamondInfo.MOD_ID + ":Nuke_top");
    this.bottomIcon = iconRegister.registerIcon(
        RedDiamondInfo.MOD_ID + ":Nuke_bottom");
}

The texture files were taken from Technic, but Technic will not be discussed.  However, they were edited using the approach described earlier with GIMP.  Naturally, the files will need to be placed in assests directory. 

Now, let’s make the changes to the NukePrimed

1.      Change the two constructor names to NukePrimed

2.      Added a getter and setter for the fuse property

public int getFuse() {
    return fuse;
}
public void setFuse(int fuse) {
    this.fuse = fuse;
}

3.      Change the explode() method to increase the damage

private void explode(){
    float f = 50.0F;
    this.worldObj.createExplosion(this, this.posX,
       this.posY, this.posZ, f, true);
}

Finally, we will need to register our Nuke with the base mod class:

public static Block blockNuke = new BlockNuke(BlockNuke.id, 
    200);

GameRegistry.registerBlock(blockNuke, BlockNuke.internalName);
LanguageRegistry.addName(blockNuke, BlockNuke.externalName);

This will register a Nuke that will wait 200 ticks before exploding.