• Journey's End on PC - Find info here and here. Please report bugs and issues for PC 1.4 and 1.4.1 to Re-Logic here.
  • Journey's End on Mobile - Find info here. Report bugs for Mobile 1.4 to DR Studios at this link and give as much detail as possible.
  • 1.4 will bring many changes to the PC version. We strongly advise making plans to back up your worlds and players prior to updating your game. More details here.
  • Console and Switch - The latest news can be found here. To report a bug, please use this link.

tAPI [Tutorial] Custom Dust

blushiemagic

Retinazer
tModLoader
TAPI makes modding extremely easy and adds hooks for many things such as items and projectiles; however, one thing it doesn't seem to have an obvious hook for is dust (the particles that are made by things like torches, terra blade, etc). This can get extremely frustrating when one realizes that nearly everything about dust (shape, color, behavior, light color, etc.) is very hard-coded into the game. This tutorial will teach you how to add custom dust to the game and completely control its behavior. (Warning: everything will be done with .cs files, so you actually need to know how to program.)

First, you will need to create a class for your dust (actually, you don't need to, but it makes organization much, much easier). As an example, I will use the mod I am currently working on at the time of writing this. You will need to add several things: a field to keep track of the texture for your custom dust, and a method to assign the texture to the field.
Code:
using System;
using Microsoft.Xna.Framework; //This will help you control the behavior of the dust, which we'll go over later.
using Microsoft.Xna.Framework.Graphics; //This is where Texture2D is located.
using Terraria;
using TAPI;

namespace Bluemagic {
public class BluemagicDust
{
    private static Texture2D texture; //This stores the custom dust textures for your class to use.

    public static void Load(ModBase modBase) //You can name this anything you want; just make sure it takes TAPI.ModBase as a parameter.
    {
        texture = modBase.textures["Dust"]; //This gets a texture from Dust.png in your mod folder then assigns it to texture.
    }
}}

Next, in your ModBase class, you will need to add the following to your OnLoad method in order for your dust class to actually be able to access the texture:
Code:
using System;
using Terraria;
using TAPI;

namespace Bluemagic {
public class Bluemagic : ModBase
{
    public override void OnLoad()
    {
        BluemagicDust.Load(this); //Use whatever you named your method from the previous part.
        //Your other loading stuff
    }
    //Your other methods
}}

Now you have everything you need to start creating your custom dust. Now for actually creating custom dust, go back to the custom dust class. I feel that the easiest way to teach you will be to show an example:
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using TAPI;

namespace Bluemagic {
public class BluemagicDust
{
    private static Texture2D texture;

    public static void Load(ModBase modBase)
    {
        texture = modBase.textures["Dust"];
    }

    public static int CreateSpectreDust(float x, float y, int width, int height) //This is the method your other classes will use in order to spawn this dust.
    {
        Color color = new Color(200, 220, 230); //This is the color multiplier of your dust; The dust image you create will get "multiplied" by this color. If you don't know what the numbers mean, go look up RGB values.
        int dust = Dust.NewDust(new Vector2(x, y), width, height, 0, 0f, 0f, 100, color, 1.2f); //The parameters are (Microsoft.Xna.Framework.Vector2 position, int width, int height, int type, float xVelocity, float yVelocity, int alpha, Microsoft.Xna.Framework.Color color, float scale).
        //The method returns the index of your dust, so to access the new dust, all you need to do is call Main.dust[whatever was returned].
        //I'm hoping that position and the velocities are self-explanatory.
        //The width and height are basically the range of positions in which the dust will randomly spawn. Useful if you want a dust to spawn at any random point within a projectile, or something like that.
        //The type is basically the texture your dust will use. We will go over this later.
        //Alpha is the transparency of your dust. 0 is fully opaque, and 255 is fully invisible.
        //Color is the color multiplier on your dust.
        //Scale is the size of your dust; the size of the image will get multiplied by the scale.
        Main.dust[dust].noGravity = true; //Self-explanatory.
        Main.dust[dust].velocity /= 2; //This halves the speed of my dust when it spawns.
        Main.dust[dust].OverrideTexture = texture; //This is necessary for your dust to use your custom texture.
        Main.dust[dust].OverrideLightColor = color; //This makes the dust always appear a certain color, regardless of what kind of light is hitting it.
        Main.dust[dust].OverrideUpdate = UpdateSpectreDust; //This is what controls the behavior of the dust. See next method for details.
        return dust; //This is so whatever creates your dust can access it, similar to how Dust.NewDust returns the same thing.
    }

    private static void UpdateSpectreDust(Dust dust) //This is the method I use to control the behavior of my dust. Make sure it takes Terraria.Dust as the one and only parameter. This method will get called for every game tick.
    {
        dust.position += dust.velocity; //Necessary for the dust to actually move.
        dust.rotation += dust.velocity.X; //Rotating your dust may make it look more realistic; it's up to you how you do so.
        Lighting.AddLight((int)(dust.position.X / 16f), (int)(dust.position.Y / 16f), 0.05f, 0.15f, 0.2f); //The last three parameters are RGB values, except instead of integers from 0 to 255 it's real numbers from 0 to 1 (you could make it more than 1 although that would be really bright).
        dust.scale -= 0.03f; //This makes the dust shrink as time passes.
        if(dust.scale < 0.5f)
        {
            dust.active = false; //This removes the dust; you don't want dust to last forever.
        }
    }
}}
You can look through the Terraria.Dust class for more examples of dust behavior (although admittedly it's hard to look through). Basically, using these two methods, you can completely control the behavior of your dust. Then to spawn the dust, just call the create method.

There is still one thing we're missing; the actual texture for your dust. Now to explain how to make a texture file for your dust. The dust must have a size of 8 x 8 pixels (it can be smaller, just make sure it stays within the 8 x 8 square). Now, whenever dust spawns, it is given one out of three textures at random. So draw your first image in the 8 x 8 square location at the coordinates (0, 0) of the image. Then, two pixels below this 8 x 8 square, draw the second image, also in an 8 x 8 square. For the third image, draw it in another 8 x 8 square two pixels below the second image. Here is the example from my mod:
BldG7jy.png

I basically gave the three dusts different brightnesses; you might want to be more creative with your differences, depending on what you need.
Remember how in your code, you had to specify the type of dust? These are the textures that type 0 will use. If you want another type of dust with a different texture, give it a type of 1. Then 2 pixels to the right of the type 0 textures, repeat the same process. You can keep repeating this for more and more dusts. There is one catch: if you end up having more than 100 dust types, then place type 100 2 pixels below type 0, instead of further to the right. Then add the next dust textures to the right of that, repeat for the next 100 dusts. For example, you can see the Dust.png that the vanilla game uses. Finally, remember that the dust textures are completely contained within the 8 x 8 squares; when I say 2 pixels to the right or down, I mean an 8 x 8 square 2 pixels away from another 8 x 8 square.

Here is the end result of the dust in my mod:
s2Z3txu.jpg

Remember, to create the dust, just call your create method for the type of dust and provide the coordinates. Since the method returns the dust's index, you can customize it even more after you create it (i.e. if you want it to behave differently when produced from different sources). Feel free to ask any questions you have :happy:
 
Last edited:

Drok

Spazmatism
Cool i was wondering how i would do this thanks!

EDIT: how would you make the effect that you used in the picture?
 

blushiemagic

Retinazer
tModLoader
Cool i was wondering how i would do this thanks!

EDIT: how would you make the effect that you used in the picture?
Basically, the dust was the exact same as what I showed in the example. Then, for the blade emitting the dust, in order to make the blade super long, I actually made it out of a bunch of square-sized projectiles. So every time each projectile updated, I just had it call the method to create my dust based on a random chance.

For a normal sword, I'd assume you create the particles in the item's UseItem method or something like that.
 

blushiemagic

Retinazer
tModLoader
bluemagic, do you know how to make your custom npc to shoot/project custom projectiles?
This isn't really dust-related, but you simply call Projectile.NewProjectile(float x, float y, float speedX, float speedY, int type, int damage, float knockback, int owner, float ai0, float ai1). X and y are the position, speedX and speedY are self-explanatory (a negative speedY means upwards), and damage and knockback are self-explanatory. The type is the type of projectile; if you want to use a custom projectile, then use ProjDef.byName["YourMod:NameOfProjectile"].type to get its type. The owner should be Main.myPlayer. Finally, ai0 and ai1 are for if your projectile uses the ai array; otherwise it's fine to just set them to 0. If it's an NPC that's making the projectile, make sure that you place this call inside an if statement to make sure Main.netMode != 1.
 

Rattle Ziddler

Terrarian
This isn't really dust-related, but you simply call Projectile.NewProjectile(float x, float y, float speedX, float speedY, int type, int damage, float knockback, int owner, float ai0, float ai1). X and y are the position, speedX and speedY are self-explanatory (a negative speedY means upwards), and damage and knockback are self-explanatory. The type is the type of projectile; if you want to use a custom projectile, then use ProjDef.byName["YourMod:NameOfProjectile"].type to get its type. The owner should be Main.myPlayer. Finally, ai0 and ai1 are for if your projectile uses the ai array; otherwise it's fine to just set them to 0. If it's an NPC that's making the projectile, make sure that you place this call inside an if statement to make sure Main.netMode != 1.
Silly me, What I did is "ProjectileDef.byName[......]" XD
well thank you very much by the way, it really did help me a lot! :)

Edit:
How about making an NPC change it's texture in-game? :/
How to make Items Texture Change even if In-use?
How to Make an NPC change to it's specific animation frame?

and sorry for the rush answer it whenever you want I totally need those info (If you know how) if not I still thank you :).
 
Last edited:

blushiemagic

Retinazer
tModLoader
I should have done this long ago, but updated the tutorial with more accurate information on width and height.

Silly me, What I did is "ProjectileDef.byName[......]" XD
well thank you very much by the way, it really did help me a lot! :)

Edit:
How about making an NPC change it's texture in-game? :/
How to make Items Texture Change even if In-use?
How to Make an NPC change to it's specific animation frame?

and sorry for the rush answer it whenever you want I totally need those info (If you know how) if not I still thank you :).
To make an NPC change its texture, you just need to change its animation frame.
Assuming you already know how to make multiple frames for an NPC, in order to select the frame, you will need to override the SelectFrame(int frameSize) method. You can use the npc's velocity or other information to determine the frame. Just as an example:
Code:
public override void SelectFrame(int frameSize)
{
    if(npc.velocity.X == 0)
    {
        npc.frame.Y = 0; //Use the first frame
    }
    else
    {
        npc.frame.Y = frameSize; //Use the second frame
    }
    if(npc.ai[0] == 0f)
    {
        npc.frame.Y = frameSize * 2; //Use the third frame
    }
}

As for changing the texture of an item, I've never tried that so I have no idea how to do it; sorry about that.
 

Rattle Ziddler

Terrarian
I should have done this long ago, but updated the tutorial with more accurate information on width and height.


To make an NPC change its texture, you just need to change its animation frame.
Assuming you already know how to make multiple frames for an NPC, in order to select the frame, you will need to override the SelectFrame(int frameSize) method. You can use the npc's velocity or other information to determine the frame. Just as an example:
Code:
public override void SelectFrame(int frameSize)
{
    if(npc.velocity.X == 0)
    {
        npc.frame.Y = 0; //Use the first frame
    }
    else
    {
        npc.frame.Y = frameSize; //Use the second frame
    }
    if(npc.ai[0] == 0f)
    {
        npc.frame.Y = frameSize * 2; //Use the third frame
    }
}

As for changing the texture of an item, I've never tried that so I have no idea how to do it; sorry about that.


Oh, now for this one what I've done to make it change is to "Transform("npcID")" XD
so I do not need more textures but what I need is more frames then. :p
I tried reading the terraria codings however it's kinda difficult to see what I needed.
well thank you very much for answering the first and the third question. I'll just go "experiment" with this code for now. :)
 
TAPI makes modding extremely easy and adds hooks for many things such as items and projectiles; however, one thing it doesn't seem to have an obvious hook for is dust (the particles that are made by things like torches, terra blade, etc). This can get extremely frustrating when one realizes that nearly everything about dust (shape, color, behavior, light color, etc.) is very hard-coded into the game. This tutorial will teach you how to add custom dust to the game and completely control its behavior. (Warning: everything will be done with .cs files, so you actually need to know how to program.)

First, you will need to create a class for your dust (actually, you don't need to, but it makes organization much, much easier). As an example, I will use the mod I am currently working on at the time of writing this. You will need to add several things: a field to keep track of the texture for your custom dust, and a method to assign the texture to the field.
Code:
using System;
using Microsoft.Xna.Framework; //This will help you control the behavior of the dust, which we'll go over later.
using Microsoft.Xna.Framework.Graphics; //This is where Texture2D is located.
using Terraria;
using TAPI;

namespace Bluemagic {
public class BluemagicDust
{
    private static Texture2D texture; //This stores the custom dust textures for your class to use.

    public static void Load(ModBase modBase) //You can name this anything you want; just make sure it takes TAPI.ModBase as a parameter.
    {
        texture = modBase.textures["Dust"]; //This gets a texture from Dust.png in your mod folder then assigns it to texture.
    }
}}
:happy:
Do I just put this in file in ym mod folder under Dust.cs? or is it something different?
 

blushiemagic

Retinazer
tModLoader
Do I just put this in file in ym mod folder under Dust.cs? or is it something different?
Just place it in your mod folder. Don't actually call it Dust.cs though, because a Terraria class has the same name. Name is something like ModNameDust, or whatever you want as long as there's no conflicts.
 
You call YourDustClass.YourCreateMethod(your parameters).
I keep getting these two errors. not sure what I'm doing wrong
HaloMod.cs (3,14)
The name 'HaloModDust' does not exist in the current context
HaloModDust.Load(this);
^
FuelRod.cs (21,14)
No overload for method 'CreateFuelDust' takes 0 arguments
int dust = HaloModDust.CreateFuelDust();
 

blushiemagic

Retinazer
tModLoader
I keep getting these two errors. not sure what I'm doing wrong
HaloMod.cs (3,14)
The name 'HaloModDust' does not exist in the current context
HaloModDust.Load(this);
^
FuelRod.cs (21,14)
No overload for method 'CreateFuelDust' takes 0 arguments
int dust = HaloModDust.CreateFuelDust();
For the first error, your ModBase class and your Dust class are in the same namespace, right?
For the second error, what are the parameters for CreateFuelDust? Make sure to pass the parameters when you call the method.
 
For the first error, your ModBase class and your Dust class are in the same namespace, right?
For the second error, what are the parameters for CreateFuelDust? Make sure to pass the parameters when you call the method.
How do I pass particular these particular parameters (projectile.position, projectile.width, projectile.height) I'm pretty new to terraria modding
 

blushiemagic

Retinazer
tModLoader
How do I pass particular these particular parameters (projectile.position, projectile.width, projectile.height) I'm pretty new to terraria modding
It depends on your method. What you have right there looks like it should work if your method has a signature of (Vector2 position, int width, int height).
 
Top Bottom