• Hello Guest! Did you know that ProjectKorra has an official Discord server? A lot of discussion about the official server, development process, and community discussion happens over there. Feel free to join now by clicking the link below.

    Join the Discord Server

[Outdated] Tutorial: How to create an ability in ProjectKorra

Finn_Bueno_

Staff member
Plugin Developer
Verified Member
THIS TUTORIAL IS OUTDATED. DO NOT USE. AN ALTERNATIVE CAN BE FOUND HERE

Hey there,

since coolade's tutorial on addon coding is now outdated, I'll try to write a new one. We'll be making the same ability "Ignite".
Let's begin!

(I am in no way stealing Coolade's code)

Step 1
If you don't have any experience with Java coding, you'll have to learn that first. Google and YouTube are your friends. Also, this site might help.
Step 2
Now, if you don't have any experience with bukkit, you'll have to work on that first as well. Here are some videos on bukkit/spigot coding. This channel has more videos, so you can check out more of them. Make sure that you get to listeners at least.

These are general things that are useful for this. Also, make sure you have spigot. You can find it at www.spigotmc.org.

Step 3
Now, we're starting our ability. Just like Coolade's tutorial, we'll be making an ability called ignite. Download the latest ProjectKorra build (The one your server uses at least) and you're ready to start!

Open Eclipse

Create a new project
Name it Ignite. Then hit enter.

Right click the project, and click 'Properties'.
Then under 'Resource', go to 'Java Build Path', then click 'Libraries'. Then add both spigot and ProjectKorra.

Good job, you have created the project! Now, let's get into creating the files and code.

Step 4
Right click the ignite project, and create a new package. (new > package)
Name the package "me.insert name here.korra.ignite", so in my case, "me.finnbueno.korra.ignite".

Right click the package, and create a new class. (new > class)
We're going to do this 2 times.

Name the first class 'IgniteInformation'.
Name the second class 'IgniteListener'.

Then, right click the project again (Not the package!). Create a new file now. (new > file)
Name it 'path.yml'. Click finish.

Now you should have 2 classes, named 'IgniteInformation' and 'IgniteListener'. You should also have a file called 'path.yml'. If so, good job. Now we'll start the real coding, I promise! :p

Step 5
First, we'll be doing the IgnoreInformation class.

This class will contain all the code needed to register the ability.
First, extend the class 'AbilityModule':
Code:
public class IngiteInformation extends AbilityModule {

}
Import AbilityModule. Now there should be a red line under IngiteInformation. To fix this, we'll have to add a constructor, which calls the super constructor with the name of the ability:
Code:
public class IngiteInformation extends AbilityModule {
 
    public IgniteInformation() {
        super("Ignite");
    }

}
Now, IgniteInformation should still give an error. That's because there are more methods needed. Hover over IgniteInformation and clicked, "Add unimplented methods." Then, you should get this:
Code:
public class IgniteInformation extends AbilityModule {

    public IngiteInformation() {
        super("Ignite");
    }

    @Override
    public String getAuthor() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getElement() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getVersion() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isHarmlessAbility() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isShiftAbility() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void onThisLoad() {
     
    }
}
I'll try to go over each method as detailed as possible.
the author method:
Code:
@Override
    public String getAuthor() {
        // TODO Auto-generated method stub
        return null;
    }
This tells the plugin who made the ability. Mainly used for debugging. Replace null with a string containing your name. In my case, "Finn_Bueno_" (Including the brackets of course!).

The description method:
Code:
@Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return null;
    }
This is shown when the player types /bending help ignite. It automatically gets the element's colour, so you dont have to worry about that. For this ability, replace null with:
"This ability allows a firebender to set someone on fire by simply punching them!"
(Again, including brackets!)

The element method:
Code:
@Override
    public String getElement() {
        // TODO Auto-generated method stub
        return null;
    }
This method tells the plugin for what element the ability is. Note that it wants a string, so we'll have to covert the element to a string. (Or just type "Fire"). Replace null with Element.Fire.toString();

The version method:
Code:
@Override
    public String getVersion() {
        // TODO Auto-generated method stub
        return null;
    }
This method isn't too important. It simply gets the version of the ability. Mainly for debugging. Replace null with "1.0V" (Including brackets!)

The harmless and shift method:
Code:
    @Override
    public boolean isHarmlessAbility() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isShiftAbility() {
        // TODO Auto-generated method stub
        return false;
    }
They are pretty self-explanatory. If isHarmlessAbility is set to true, players will be able to use this in protected areas. (If set so in the config.). If isSneakAbility is set to true, people will be able to use swiftswim or other passives like that while on that ability.

The onThisLoad method:
Code:
    @Override
    public void isHarmlessAbility() {
        // TODO Auto-generated method stub
    }
In my opinion, the most important of all. The code in this method will be called when the ability loads. In this method, we'll register our listener class, add a permission, and set the permission default.

First, add this in the onThisLoad method.
Code:
ProjectKorra.plugin.getServer().getPluginManager().registerEvents(new IgniteListener(), ProjectKorra.plugin);
Since we're not coding a plugin, we'll assign it to ProjectKorra.
This tells spigot/the server/idk that we want to listen for events in IgniteListener.

Now, to add the permission, type the following.
Code:
ProjectKorra.plugin.getServer().getPluginManager().addPermission(new Permission("bending.ability.Ignite"));
This adds a new permission, "bending.ability.Ignite". Adding this to a player or group will give them access to the ability.

Now, this is a basic ability so we want players to be allowed to use it by default. To do this, type the following.
Code:
ProjectKorra.plugin.getServer().getPluginManager().getPermission("bending.ability.Ignite").setDefault(PermissionDefault.TRUE);
If you still want a group or player to not have access to the ability, add "-bending.ability.Ignite" to them.

That's it for the onThisLoad().

IgniteListener will be continued in the next post. (10000 character cap)
 
Last edited:

Finn_Bueno_

Staff member
Plugin Developer
Verified Member
Ok, let's start with the IngiteListener class.

Step 6
Now, we'll be writing the code that executes the ability. First, we implement Listener in our IgniteListener class.
Code:
public class IgniteListener implements Listener {

}
Then, we add a listener for when a player left clicks.
Code:
public class IgniteListener implements Listener {
 
    @EventHandler(priority = EventPriority.NORMAL)
    public void leftClick(PlayerAnimationEvent e) {
 
    }
 
}
Now inside this listener, we want to get the player that clicked, and the entity they are targeting.
Code:
public class IgniteListener implements Listener {

    @EventHandler(priority = EventHandler.NORMAL)
    public void leftClick(PlayerAnimationEvent e) {
       Player player = e.getPlayer();
       Entity entity = GeneralMethods.getTargetEntity(player, 7, new ArrayList<Entity>());
    }

}

Now, we want to check if the player isn't targeting an entity. If they aren't targeting an entity, we will return. This code checks if they are targeting an entity within 7 blocks.
Code:
public class IgniteListener implements Listener {

    @EventHandler(priority = EventHandler.NORMAL)
    public void leftClick(PlayerAnimationEvent e) {
       Player player = e.getPlayer();
       Entity entity = GeneralMethods.getTargetedEntity(player, 7, new ArrayList<Entity>);
       if(entity == null) return;
    }

}

After that, we are sure they are targeting an entity.
Then we check if the entity is an instance of LivingEntity. If this is true we will damage the entity and set them on fire.
Code:
public class IgniteListener implements Listener {

    @EventHandler(priority = EventHandler.NORMAL)
    public void leftClick(PlayerAnimationEvent e) {
       Player player = e.getPlayer();
       Entity entity = GeneralMethods.getTargetEntity(player, 7, new ArrayList<Entity>);
       if(entity == null) return;
     
       if(entity instanceof LivingEntity) {
              GeneralMethods.damageEntity(player, entity, 1, "Ignite"); // the number is the damage.
              entity.setFireTicks(40); // this sets the entity on fire for 40 ticks = 2 seconds.
       }
    }

}
Now, the technical part is done, but maybe you want a few fire particles to appear and a firebending sound to be played.
For that, add the following.
Code:
public class IgniteListener implements Listener {

    @EventHandler(priority = EventHandler.NORMAL)
    public void leftClick(PlayerAnimationEvent e) {
       Player player = e.getPlayer();
       Entity entity = GeneralMethods.getTargetEntity(player, 7, new ArrayList<Entity>);
       if(entity == null) return;
     
       if(entity instanceof LivingEntity) {
              GeneralMethods.damageEntity(player, entity, 1, "Ignite"); // the number is the damage.
              entity.setFireTicks(40); // this sets the entity on fire for 40 ticks = 2 seconds.
             FireMethods.playFirebendingParticles(entity.getLocation());
             FireMethods.playFirebendingSound(entity.getLocation());
       }
    }

}

Congratulations! The code for the ability is done! Now, let's get to the path.yml.

step 7
Right click your path.yml, and open it. Then, add the following line.
main-class: package name.IgniteInformation
Let me explain it.
This tells the plugin where the information for the ability is. In our case, that's in 'IgniteInformation'. So we define, me.your name here.korra.ignite.IgniteInformation , then save the file and close it.

step 8
Right click the project and click 'Export'.
Click Java.
Click JAR file.
Click Next >.
Define where you want the file to be exported to.
Click Finish.

Now put the ability in your ability folder on your server. Reload or restart the server, and you're done!
You've made your own ability! Congratulations!

If the ability doesn’t work check the console and see if it is giving you errors. Make sure that the path.yml matches the same path as your package.

If you see a mistake in this tutorial please tell me and I will fix it. Also this hasn't been tested so the chance that there are a few typos/mistakes is of course there. Anyway I hope this tutorial helped to get you started!

(Releasing this as an addon is not allowed)


- Finn
 
Last edited:

Sorin

Verified Member
Directions where un-clear, got my head stuck in a mail box, sen help please. (Jk, really good tutorial, I think this will help a lot of people.)
 

Sketz

Verified Member
The signature though takes up so much of the screen, its hard to read, so I just skimmed through to see the post lol.
 

Sorin

Verified Member
The signature though takes up so much of the screen, its hard to read, so I just skimmed through to see the post lol.
Lol the signature isn't even that bad xD I can read it perfectly. Do you have a super small monitor or something?
 

HydroMan

Verified Member
Thanks Finn for this amazing tutorial. I think it gonna help me make an upgraded version of default Suffocate, thanks :). Gotta get to work! ;)
 

Finn_Bueno_

Staff member
Plugin Developer
Verified Member
Why not? And Finn thanks for this tutorial. I finally learn how to make an airbending ability in a few seconds, just by reading this tutorial. Thank so much :)
Because an ability like firebreath or plantwhip needs more than just an info class and a listener.
 

jedk1

New Member
Might explain your Dagger throw?
Uhm... Whats stopping a chi blocker from throwing daggers?
Being able to throw daggers makes sense... Airbenders setting people on fire doesnt make sense.
Why not? And Finn thanks for this tutorial. I finally learn how to make an airbending ability in a few seconds, just by reading this tutorial. Thank so much :)
This only has a listener. I mean, you COULD make an ability based on this.... but it would be terrible (look at my very first abilities). To make an actual ability you need more than what finn has showed.
 
Top