tModLoader [Tutorial] Projectile Guide and Implementation: tModLoader Edition

I would like to create a type of weapon that can shoot certain ammunition. For example, let's say that my weapon has the name of "Pixel Weapon" what I'd like to do is create "Pixel Bullet A" "Pixel Bullet B" and "Pixel Bullet C" so "Pixel Weapon" is only going to be able to use those types of ammunition. How should I do it? Thanks!
 
How do I make this sword shoot projectiles?
Code:
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace TerraSword.Items
{
    public class TerraSword : ModItem
    {
        public override void SetStaticDefaults()
        {
            Tooltip.SetDefault("This is a basic Sword");
        }

        public override void SetDefaults()
        {
            item.damage = 13;
            item.melee = true;
            item.width = 10;
            item.heigth = 30;
            item.useTime = 10;
            item.useAnimation = 10;
            item.useStyle = 1;
            item.knockBack = 15;
            item.value = Item.buyPrice(gold: 1);
            item.rare = 3;
            item.UseSound = SoundID.Item1;
            item.autoReuse = true;
        }

        public override void AddRecipes()
        {
            recipe.AddIngredient(mod.ItemType("TerraSteel"), 10);
            recipe.AddTile(mod.TileType("TerraInfuser"));
            recipe.SetResult(this);
            recipe.AddRecipe();
        }
    }
}
 
Hi guys, i'd like to know if is it possible to use the Lightning Orb as a projectile without being damaged...everytime i try to use it as a ammo for my weapon it focuses me.
The idea is of a weapon that shoots something but that has a % to shoot lightning Orb

Right now this is my code:

using System;
using Terraria;
using Microsoft.Xna.Framework;
using Terraria.ID;
using Terraria.ModLoader;

namespace Mod.Items.Weapons
{
public class ThunderLord : ModItem
{
public override void SetStaticDefaults()
{
DisplayName.SetDefault("ThunderLord");
Tooltip.SetDefault("Uh.");
}
public override void SetDefaults()
{
item.useStyle = 5;
item.autoReuse = true;
item.useAnimation = 30;
item.useTime = 30;

item.width = 50;
item.height = 18;
item.shootSpeed = 10;
item.shoot = 1;
item.UseSound = SoundID.Item41;
item.damage = 73;
item.noMelee = true;
item.value = Item.sellPrice(0, 5, 0, 0);
item.rare = 10;

item.knockBack = 10;
item.ranged = true;
}

public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack)
{
type = 1;

if (Main.rand.NextBool(5))
{
int a = Projectile.NewProjectile(position.X, position.Y, speedX, speedY, 465, damage, knockBack, Main.myPlayer);
Main.projectile[a].friendly = true;
Main.projectile[a].hostile = false;
}

return base.Shoot(player, ref position, ref speedX, ref speedY, ref type, ref damage, ref knockBack);
}
 
Hi guys, i'd like to know if is it possible to use the Lightning Orb as a projectile without being damaged...everytime i try to use it as a ammo for my weapon it focuses me.
The idea is of a weapon that shoots something but that has a % to shoot lightning Orb

Right now this is my code:

using System;
using Terraria;
using Microsoft.Xna.Framework;
using Terraria.ID;
using Terraria.ModLoader;

namespace Mod.Items.Weapons
{
public class ThunderLord : ModItem
{
public override void SetStaticDefaults()
{
DisplayName.SetDefault("ThunderLord");
Tooltip.SetDefault("Uh.");
}
public override void SetDefaults()
{
item.useStyle = 5;
item.autoReuse = true;
item.useAnimation = 30;
item.useTime = 30;

item.width = 50;
item.height = 18;
item.shootSpeed = 10;
item.shoot = 1;
item.UseSound = SoundID.Item41;
item.damage = 73;
item.noMelee = true;
item.value = Item.sellPrice(0, 5, 0, 0);
item.rare = 10;

item.knockBack = 10;
item.ranged = true;
}

public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack)
{
type = 1;

if (Main.rand.NextBool(5))
{
int a = Projectile.NewProjectile(position.X, position.Y, speedX, speedY, 465, damage, knockBack, Main.myPlayer);
Main.projectile[a].friendly = true;
Main.projectile[a].hostile = false;
}

return base.Shoot(player, ref position, ref speedX, ref speedY, ref type, ref damage, ref knockBack);
}

You got a discord? It's illegal to pass decompiled code around here.
[doublepost=1552784570,1552784397][/doublepost]
How do I make this sword shoot projectiles?
Code:
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace TerraSword.Items
{
    public class TerraSword : ModItem
    {
        public override void SetStaticDefaults()
        {
            Tooltip.SetDefault("This is a basic Sword");
        }

        public override void SetDefaults()
        {
            item.damage = 13;
            item.melee = true;
            item.width = 10;
            item.heigth = 30;
            item.useTime = 10;
            item.useAnimation = 10;
            item.useStyle = 1;
            item.knockBack = 15;
            item.value = Item.buyPrice(gold: 1);
            item.rare = 3;
            item.UseSound = SoundID.Item1;
            item.autoReuse = true;
        }

        public override void AddRecipes()
        {
            recipe.AddIngredient(mod.ItemType("TerraSteel"), 10);
            recipe.AddTile(mod.TileType("TerraInfuser"));
            recipe.SetResult(this);
            recipe.AddRecipe();
        }
    }
}
Simply add : item.shoot= "id of projectile"; in the code
 
Hello, I currently need help on a projectile that has these functions...
*)Homing
*)Deals a number of hits instead of just one hit per projectile used

I'll post my code if someone answered my help on this. Thank you for your time.
 
¿Cómo podría hacer un proyecto para cuchillos de vampiro?
[doublepost=1553359376,1553359293][/doublepost]How could I make a projectile for vampire knives?
 
PC\Documents\My Games\Terraria\ModLoader\Mod Sources\ModItem\Items\ModName.cs(32,43) : error CS0839: Argument missing
 
Hello there! I've been skimming through many different sites, trying to find the answer to my problem, but I don't seem to be able to find it. I'm sort of new to coding C#, so I'm just using bits and pieces of code from multiple files to make the majority of my weapons, combined with what knowledge I have to try to create something unique.
My problem is I'm trying to create a space gun-like weapon, and I followed everything like normal, but the laser comes slightly from the left of my character, which is most noticeable when firing straight up or down. It also deviates from my cursor in the same way; aiming and firing a laser to the left of it. Is there anything I can do to fix this? Thank you!
 
Last edited:
You can just download the example mod on the first post of this thread. The file is called "MPT.zip". You need to open and extract it to any location and then you should be able to look through the code in any of the folders. The rotation thing that you are looking for would be in the folder called something like "projectiles" and go open "Example Bullet A" with your IDE or Notepad or NotePad++. From there it will describe with comments (the stuff after "//") on how to use such items. If you are still confused/cannot open the file, then here is the example cs codes for the most important stuff.

Projectiles
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Terraria;
using Terraria.ModLoader;

namespace MPT.Projectiles //We need this to basically indicate the folder where it is to be read from, so you the texture will load correctly
{
    public class ExampleBulletA : ModProjectile
    {
        public override void SetDefaults()
        {
            projectile.name = "Example Bullet A"; //Name of the projectile, only shows this if you get killed by it
            projectile.width = 36; //Set the hitbox width
            projectile.height = 36; //Set the hitbox height
            projectile.timeLeft = 60; //The amount of time the projectile is alive for
            projectile.penetrate = 1; //Tells the game how many enemies it can hit before being destroyed
            projectile.friendly = true; //Tells the game whether it is friendly to players/friendly npcs or not
            projectile.hostile = false; //Tells the game whether it is hostile to players or not
            projectile.tileCollide = true; //Tells the game whether or not it can collide with a tile
            projectile.ignoreWater = true; //Tells the game whether or not projectile will be affected by water
            projectile.ranged = true; //Tells the game whether it is a ranged projectile or not
            projectile.aiStyle = 0; //How the projectile works, 0 makes the projectile just go straight towards your cursor
        }
    
        //How the projectile works
        public override void AI()
        {
            Player owner = Main.player[projectile.owner]; //Makes a player variable of owner set as the player using the projectile
            projectile.light = 0.9f; //Lights up the whole room
            projectile.alpha = 128; //Semi Transparent
            projectile.rotation += (float)projectile.direction * 0.8f; //Spins in a good speed
            int DustID = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y + 2f), projectile.width + 4, projectile.height + 4, 36, projectile.velocity.X * 0.2f, projectile.velocity.Y * 0.2f, 120, default(Color), 0.75f); //Spawns dust
            Main.dust[DustID].noGravity = true; //Makes dust not fall
            if(projectile.timeLeft % 15 == 0) //If the remainder of the timeLeft divided 15 is 0, then make the projectile; Every 15 seconds, projectile spawns another projectile
            {
                Projectile.NewProjectile(projectile.position.X, projectile.position.Y, MathHelper.Lerp(-1f, 1f, (float)Main.rand.NextDouble()), MathHelper.Lerp(-1f, 1f, (float)Main.rand.NextDouble()), mod.ProjectileType("ExampleBulletB"), 5 * (int)owner.rangedDamage, projectile.knockBack, Main.myPlayer); //owner.rangedDamage is basically the damage multiplier for ranged weapons
            }
        }
    
        //When you hit an NPC
        public override void OnHitNPC(NPC n, int damage, float knockback, bool crit)
        {
            Player owner = Main.player[projectile.owner];
            int rand = Main.rand.Next(2); //Generates an integer from 0 to 1
            if(rand == 0)
            {
                n.AddBuff(24, 180); //On Fire! debuff for 3 seconds
            }
            else if (rand == 1)
            {
                owner.statLife += 5; //Gives 5 Health
                owner.HealEffect(5, true); //Shows you have healed by 5 health
            }
        }
    
        //When the projectile hits a tile
        public override bool OnTileCollide(Vector2 velocityChange)
        {
            if (projectile.velocity.X != velocityChange.X)
            {
                projectile.velocity.X = -velocityChange.X/2; //Goes in the opposite direction with half of its x velocity
            }
            if (projectile.velocity.Y != velocityChange.Y)
            {
                projectile.velocity.Y = -velocityChange.Y/2; //Goes in the opposite direction with half of its y velocity
            }
            return false;
        }
    
        //After the projectile is dead
        public override void Kill(int timeLeft)
        {
            int rand = Main.rand.Next(5); //Generates integers from 0 to 4
            Projectile.NewProjectile(projectile.position.X, projectile.position.Y, 0, 0, 296, (int) (projectile.damage * 1.5), projectile.knockBack, Main.myPlayer); // 296 is the explosion from the Inferno Fork
            if(rand == 0)
            {
                Item.NewItem((int)projectile.position.X, (int)projectile.position.Y, projectile.width, projectile.height, mod.ItemType("ExampleBulletA"), 1, false, 0, false); //Spawns a bullet
            }
        }
    }
}

Items
Code:
using System;
using Microsoft.Xna.Framework;

using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace MPT.Items
{
    public class ExampleBulletA : ModItem
    {
        public override void SetDefaults()
        {
            item.name = "Example Bullet A";
            item.damage = 10; //This is added with the weapon's damage
            item.ranged = true;
            item.width = 14;
            item.height = 32;
            item.maxStack = 999;
            item.toolTip = "Example Bullet A";
            item.consumable = true; //Tells the game that this should be used up once fired
            item.knockBack = 1f; //Added with the weapon's knockback
            item.value = 500;
            item.rare = 2;
            item.shoot = mod.ProjectileType("ExampleBulletA");
            item.shootSpeed = 7f; //Added to the weapon's shoot speed
            item.ammo = mod.ItemType("ExampleBulletA"); //Tells the game that it should be considered the same type of ammo as this item
        }

        public override void AddRecipes()
        {
            ModRecipe recipe = new ModRecipe(mod);
            recipe.AddIngredient(ItemID.DirtBlock);
            recipe.SetResult(this, 111);
            recipe.AddRecipe();
        }
    }
}
Code:
using System;
using Microsoft.Xna.Framework;

using Terraria;
using Terraria.ID; //We are borrowing properties from IDs to easily make a Recipe
using Terraria.ModLoader;

namespace MPT.Items
{
public class ExampleGun : ModItem
{
        public override void SetDefaults()
        {
            item.name = "Example Gun"; //Its display name
            item.damage = 20; //The damage
            item.ranged = true; //Whether or not it is a ranged weapon
            item.width = 60; //Item width
            item.height = 60; //Item height
            item.maxStack = 1; //How many of this item you can stack
            item.toolTip = "An example gun."; //The item’s tooltip
            item.useTime = 10; //How long it takes for the item to be used
            item.useAnimation = 39; //How long the animation of the item takes
            item.knockBack = 7f; //How much knockback the item produces
            item.useSound = 12; //The soundeffect played when used
            item.noMelee = true; //Whether the weapon should do melee damage or not
            item.useStyle = 5; //How the weapon is held, 5 is the gun hold style
            item.value = 1; //How much the item is worth
            item.rare = 1; //The rarity of the item
            item.shoot = mod.ProjectileType("ExampleBulletA"); //What the item shoots, retains an int value | *
            item.shootSpeed = 1f; //How fast the projectile fires
            item.useAmmo = mod.ItemType("ExampleBulletA"); //Tells the game what type of ammo to use    
            item.autoReuse = true; //Whether it automatically uses the item again after its done being used/animated
        }
        public override void AddRecipes() //Adding recipes
        {
            ModRecipe recipe = new ModRecipe(mod); //Creating a new recipe to be added to
            recipe.AddIngredient(ItemID.DirtBlock); //Setting the ingredient to the item as a Dirt Block
            recipe.SetResult(this); //Set the result of the recipe to this item (this refers to the class itself)
            recipe.AddRecipe(); //Add this recipe
        }
        public override bool ConsumeAmmo(Player p) //Tells the game whether the item consumes ammo or not
        {
            int rand = Main.rand.Next(9); //A random chance... once again
            if(p.itemAnimation < p.inventory[p.selectedItem].useAnimation - 25) //Consumes ammo near the end of the item's animation
            {
                    return true; //Ammo is consumed
            }
            else
            {
                return false; //Ammo is not consumed before animation is finished
            }
        }
        public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack) //This lets you modify the firing of the item
        {
            /*Code is made by berberborscing*/
            int spread = 30; //The angle of random spread.
            float spreadMult = 0.1f; //Multiplier for bullet spread, set it higher and it will make for some outrageous spread.
            for (int i = 0; i < 3; i++)
            {
                float vX = speedX +(float)Main.rand.Next(-spread,spread+1) * spreadMult;
                float vY = speedY +(float)Main.rand.Next(-spread,spread+1) * spreadMult;
                Projectile.NewProjectile(position.X, position.Y, vX, vY, type, damage, knockBack, Main.myPlayer);
            }
            return false; //Makes sure to not spawn the original projectile
        }
    }
}
Fot ExampleGun
All I'm getting is error CS0246 The type or namespace name 'Player' could not be found (are you missing a using directive or an assembly reverence?)
Same issue with Vector 2
 
How do I set a projectile summoned via 'special ability' to fire at the cursor, much like the 'Forbidden Armor' ancient storm attack? I've looked far and wide, and just can't seem to find the solution (although I'm willing to bet that it's probably simple), and I have the myPlayer file, too. Here's a snippet of it:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public override void ProcessTriggers(TriggersSet triggersSet)
{
if (TestMod.EBonusKey.JustPressed)
{
if (cloakAndDagger && player.FindBuffIndex(mod.BuffType("EquipCooldown")) < 0)
{
player.AddBuff(mod.BuffType("EquipCooldown"), 900);
Projectile.NewProjectile(player.Center.X, player.Center.Y, 0, 0, mod.ProjectileType("CloakDagger"), Main.hardMode ? 40 : 20, 0, player.whoAmI);
}
}
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The two 0s are just there until I have the problem fixed. I've tried several options, but none of them fire straight at the cursor. Thank you in advance.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nevermind, I figured it out myself, with a rather sloppy code bit. In case of future questions like this, I'll just leave a snippet for those of you who need it:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vector2 velocity = Main.MouseWorld - player.Center;
float length = velocity.Length();
length = 1 / length;
velocity *= length;
velocity *= 5;
Projectile.NewProjectileDirect(player.Center, velocity, mod.ProjectileType("YourProjectileName"), damage, knockBack, player.whoAmI);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thank you and have a good day, y'all.
 
Last edited:
I have an error:

Compiling EvanMod.XNA.dll failed with 1 errors and C:\Users\EvanKrusher948\Documents\My Games\Terraria\ModLoader\Mod Sources\EvanMod\Projectiles\KillComfirmP.cs(61,30) : error CS0266: Cannot implicitly convert type 'float' to 'int'. An explicit conversion exists (are you missing a cast?) warnings

My Code:

Code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Terraria;
using Terraria.DataStructures;
using Terraria.GameInput;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.ModLoader.IO;

namespace EvanMod.Projectiles
{
    public class KillConfirmP : ModProjectile
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("The Almighty Knife");
        }

        public override void SetDefaults()
        {
            projectile.width = 10;
            projectile.height = 24;
            projectile.aiStyle = 0;
            projectile.penetrate = -1;
            projectile.melee = false;
            projectile.ranged = false;
            projectile.magic = false;
            projectile.thrown = true;
            projectile.tileCollide = true;
            projectile.friendly = true;
        }

        public override void AI()
        {
            projectile.rotation = projectile.velocity.ToRotation() + MathHelper.PiOver2;
            Lighting.AddLight(projectile.Center, 0f, 0.4f, 0f); // R G B values from 0 to 1f.

            projectile.ai[0] += 1f; // Use a timer to wait 15 ticks before applying gravity.
            if (projectile.ai[0] >= 25f)
            {
                projectile.ai[0] = 25f;
                projectile.velocity.Y = projectile.velocity.Y + 0.4f;
            }
            if (projectile.velocity.Y > 16f)
            {
                projectile.velocity.Y = 16f;
            }
        }

        public override void ModifyHitNPC(NPC target, ref int damage, ref float knockback, ref bool crit, ref int hitDirection)
        {
            if (target.type == NPCID.TargetDummy)
            {
                projectile.damage += 20;
            }
            else
            {
                target.life = 0f; //this line gives me the error
            }
        }
    }
}
 
I have an error:

Compiling EvanMod.XNA.dll failed with 1 errors and C:\Users\EvanKrusher948\Documents\My Games\Terraria\ModLoader\Mod Sources\EvanMod\Projectiles\KillComfirmP.cs(61,30) : error CS0266: Cannot implicitly convert type 'float' to 'int'. An explicit conversion exists (are you missing a cast?) warnings

My Code:

Code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Terraria;
using Terraria.DataStructures;
using Terraria.GameInput;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.ModLoader.IO;

namespace EvanMod.Projectiles
{
    public class KillConfirmP : ModProjectile
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("The Almighty Knife");
        }

        public override void SetDefaults()
        {
            projectile.width = 10;
            projectile.height = 24;
            projectile.aiStyle = 0;
            projectile.penetrate = -1;
            projectile.melee = false;
            projectile.ranged = false;
            projectile.magic = false;
            projectile.thrown = true;
            projectile.tileCollide = true;
            projectile.friendly = true;
        }

        public override void AI()
        {
            projectile.rotation = projectile.velocity.ToRotation() + MathHelper.PiOver2;
            Lighting.AddLight(projectile.Center, 0f, 0.4f, 0f); // R G B values from 0 to 1f.

            projectile.ai[0] += 1f; // Use a timer to wait 15 ticks before applying gravity.
            if (projectile.ai[0] >= 25f)
            {
                projectile.ai[0] = 25f;
                projectile.velocity.Y = projectile.velocity.Y + 0.4f;
            }
            if (projectile.velocity.Y > 16f)
            {
                projectile.velocity.Y = 16f;
            }
        }

        public override void ModifyHitNPC(NPC target, ref int damage, ref float knockback, ref bool crit, ref int hitDirection)
        {
            if (target.type == NPCID.TargetDummy)
            {
                projectile.damage += 20;
            }
            else
            {
                target.life = 0f; //this line gives me the error
            }
        }
    }
}


Remove the 'f' from the last line. Alternatively, you can do something like this: (int)("insert something with a 'float' value here").
 
Back
Top Bottom