tModLoader [Tutorial] Projectile Guide and Implementation: tModLoader Edition

During attempts to make something working ( And i succeeded in this. Thanks very much for help) I noticed one feature. I tried to change the velocity and extra updates of the bullet. I was just adding an item.velocity or item.extraUpdates. After 10 minutes of this process, I realized that it was wrong. How can I change velocity and extraUpdates for example here ? As I understand it here are the speed characteristics of a normal bullet (4 velocity and 1 extra update). But the chlorophytic bullet has 5 velocity and 2 extra updates . How can I change these characteristics ?
using Terraria.ID;
using Terraria.ModLoader;

namespace Wares.Items
{
public class BloomingStone : ModItem
{
public override void SetStaticDefaults()
{

Tooltip.SetDefault("Leafy, glimmering pouch of nature bullets. Let them fly and chase");
}

public override void SetDefaults()
{
item.damage = 10;
item.ranged = true;
item.width = 8;
item.height = 8;
item.maxStack = 1;
item.consumable = false;
item.knockBack = 1f;
item.value = 100;
item.rare = 7;
item.shoot = ProjectileID.ChlorophyteBullet;
item.ammo = AmmoID.Bullet;
}

public override void AddRecipes()
{
ModRecipe recipe = new ModRecipe(mod);
recipe.AddIngredient(ItemID.DirtBlock, 10);
recipe.AddTile(TileID.WorkBenches);
recipe.SetResult(this);
recipe.AddRecipe();
}
}
}
 
[Tutorial] Projectile Guide and Implementation
tModLoader Edition
by: Sin Costan

Introduction:
Hello TCF community, by a request, I have imported the original tAPI guide to tModLoader, with a few changes of course.


This page looks pretty empty boss, where's the tutorial?
By the power of Google Docs, I have made it in that, though reading code will be a pain, so you might want to look at MPT.zip instead if you want to read code. The Google Doc for the guide is VERY detailed, reaching nearly 20 PAGES! Of course, you can just skip through the reading portions, but I highly recommend reading through them if you have little to no experience with modding or coding. The advanced concepts will be on this thread. If you want to learn something from my original guide or something from Vanilla Terraria, then comment on the thread and if multiple people like it, I will add it. Also, if you need any help, go ahead and post a comment and either me or experts will try and help, just remember this is for Projectiles and their Implements (though you can implement projectiles on nearly everything...)


The Google Docs Link:
Projectile Guide and Implementation

Resources:
Dust and Sound Catalogue
Sin Costan's Collection of Fun Projectiles: Once Again
im trying to make a shot gun and its not really working. here is my code. help would be much appreciated :) i did this to show what is marked red (this is marked red ---^)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Microsoft.Xna.Framework;

namespace Modding2.Meteor
{
class MeteorShoty : ModItem
{

public override bool MeteorShoty.Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack)
(This is marked red)-------------------^
{ for (int x = 4; x < int shotAmount; x++)}
(This is marked red)---^-------^-------^---^
public override void SetDefaults()

item.Size = new Microsoft.Xna.Framework.Vector2(12, 24);
item.rare = ItemRarityID.Blue;
item.value = Item.sellPrice(silver: 25);

item.useTime = 25;
item.useAnimation = 25;
item.useStyle = ItemUseStyleID.HoldingOut;
item.UseSound = SoundID.Item14;

item.noMelee = true;
item.ranged = true;
item.damage = 16;

item.useAmmo = AmmoID.Bullet;
item.shoot = 10;
item.shootSpeed = 4.5f;
item.autoReuse = false;

}





}
}
 
Last edited:
[Tutorial] Projectile Guide and Implementation
tModLoader Edition
by: Sin Costan

Introduction:
Hello TCF community, by a request, I have imported the original tAPI guide to tModLoader, with a few changes of course.


This page looks pretty empty boss, where's the tutorial?
By the power of Google Docs, I have made it in that, though reading code will be a pain, so you might want to look at MPT.zip instead if you want to read code. The Google Doc for the guide is VERY detailed, reaching nearly 20 PAGES! Of course, you can just skip through the reading portions, but I highly recommend reading through them if you have little to no experience with modding or coding. The advanced concepts will be on this thread. If you want to learn something from my original guide or something from Vanilla Terraria, then comment on the thread and if multiple people like it, I will add it. Also, if you need any help, go ahead and post a comment and either me or experts will try and help, just remember this is for Projectiles and their Implements (though you can implement projectiles on nearly everything...)


The Google Docs Link:
Projectile Guide and Implementation

Resources:
Dust and Sound Catalogue
Sin Costan's Collection of Fun Projectiles: Once Again
so i need help. im making a shotgun and i cant really figure it out. help would be much appreciated.
Here is the code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Microsoft.Xna.Framework;
using Microsoft.Azure.Amqp.Framing;

namespace Modding2.Meteor
{
class MeteorShoty1 : ModItem
{
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
{
int spread = 30;
float spreadMult = 0.1f;
for (int i = 0; i < 3; i++) ;


}


public override void SetDefaults()
{
item.Size = new Microsoft.Xna.Framework.Vector2(12, 24);
item.rare = ItemRarityID.Blue;
item.value = Item.sellPrice(silver: 25);

item.useTime = 25;
item.useAnimation = 25;
item.useStyle = ItemUseStyleID.HoldingOut;
item.UseSound = SoundID.Item14;

item.noMelee = true;
item.ranged = true;
item.damage = 16;

item.useAmmo = AmmoID.Bullet;
item.shoot = 10;
item.shootSpeed = 4.5f;
item.autoReuse = false;


}
}
}
 
Hello! I know this may be a bit complicated, but how would I make a projectile bounce off an enemy, then start homing?
 
I don't know why for me target.hostile not working, it say "Terraria.NPC not contain any definition of "hostile" etc." but npc.friendly work..
I also have a problem with this.

code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;



namespace knives.projectiles
{
public class Sulfp : ModProjectile
{
public override void SetStaticDefaults()
{
DisplayName.SetDefault("Sulfp");
}

public override void SetDefaults()
{
projectile.width = 50;

projectile.height = 50;
projectile.friendly = true;
projectile.ranged = true;
projectile.penetrate = 8;
projectile.light = 0.75f;
projectile.ignoreWater = true;
projectile.usesLocalNPCImmunity = true;
projectile.localNPCHitCooldown = 0;


}


public override void AI()
{
for (int i = 0; i < 1200; i++)
{
NPC target = Main.npc;
//If the npc is hostile
if (target.hostile)

{
//Get the shoot trajectory from the projectile and target
float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
float shootToY = target.position.Y - projectile.Center.Y;
float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));

//If the distance between the live targeted npc and the projectile is less than 480 pixels
if (distance < 480f && !target.friendly && target.active)
{
//Divide the factor, 3f, which is the desired velocity
distance = 3f / distance;

//Multiply the distance by a multiplier if you wish the projectile to have go faster
shootToX *= distance * 5;
shootToY *= distance * 5;

//Set the velocities to the shoot values
projectile.velocity.X = shootToX;
projectile.velocity.Y = shootToY;
}
}
}
projectile.rotation = (float)Math.Atan2((double)projectile.velocity.Y, (double)projectile.velocity.X) + 1.57f;
if (Main.rand.Next(1) == 0) // only spawn 20% of the time
{
int choice = Main.rand.Next(2); // choose a random number: 0, 1, or 2
if (choice == 0) // use that number to select dustID: 15, 57, or 58
{
choice = 36;
}
else if (choice == 1)
{
choice = 175;
}
// Spawn the dust
Dust.NewDust(projectile.position, projectile.width, projectile.height, choice, projectile.velocity.X * 0.25f, projectile.velocity.Y * 0.25f, 150, default(Color), 0.7f);
}

}
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, 1800); //On Fire! debuff for 3 seconds

}
else if (rand == 1)
{
n.AddBuff(24, 1800); //On Fire! debuff for 3 seconds
}
for (int i = 0; i < 3; i++)
{
// Calculate new speeds for other projectiles.
// Rebound at 40% to 70% speed, plus a random amount between -8 and 8
float speedX = -projectile.velocity.X * Main.rand.NextFloat(.8f, .9f) + Main.rand.NextFloat(-8f, 8f);
float speedY = -projectile.velocity.Y * Main.rand.Next(80, 90) * 0.01f + Main.rand.Next(-20, 21) * 0.4f; // This is Vanilla code, a little more obscure.
// Spawn the Projectile.
Projectile.NewProjectile(projectile.position.X + speedX, projectile.position.Y + speedY, speedX, speedY, 90, (int)(projectile.damage * 0.5), 0f, projectile.owner, 0f, 0f);
}
}
}

}
 
Last edited:
So I am currently working on a sword called Stormweaver. It is a projectile sword, and the projectile it shoots is call Stormweaverlightning. I am trying to make the lightning projectile rotate to the direction of the mouse and go in a line towards the mouse. I do not know how to code it in. Here is my current code for the projectile and sword:

using Terraria.ID;
using Terraria.ModLoader;

namespace Beans.Items
{
public class Stormweaver : ModItem
{
public override void SetStaticDefaults()
{
// DisplayName.SetDefault("Stormweaver");
Tooltip.SetDefault("'Do not submerge'");
}

public override void SetDefaults()
{
item.damage = 95;
item.melee = true;
item.width = 50;
item.height = 60;
item.useTime = 20;
item.useAnimation = 20;
item.useStyle = ItemUseStyleID.SwingThrow;
item.knockBack = 8;
item.value = 10000;
item.rare = ItemRarityID.LightPurple;
item.UseSound = SoundID.Item14;
item.autoReuse = true;
item.shoot = mod.ProjectileType("Stormweaverlightning");
item.shootSpeed = 10f;

}
public override void AddRecipes()
{
ModRecipe recipe = new ModRecipe(mod);
recipe.AddIngredient(ItemID.DirtBlock, 10);
recipe.AddTile(TileID.WorkBenches);
recipe.SetResult(this);
recipe.AddRecipe();
}


}
}

and for the projectile:

using Terraria.ModLoader;
namespace Beans.Projectiles
{
public class Stormweaverlightning : ModProjectile

{

public override void SetDefaults()
{
projectile.Name = "Stormweaverlightning";
projectile.width = 100;
projectile.height = 10;
projectile.friendly = true;
projectile.melee = true;
projectile.tileCollide = false;
projectile.penetrate = 30;
projectile.timeLeft = 500;
projectile.light = 0.75f;
projectile.extraUpdates = 4;
projectile.ignoreWater = true;
projectile.damage = 95;
projectile.knockBack = 0;
projectile.aiStyle = -1;

}
public override void AI()
{
float velXMult = 1.9f;
projectile.velocity.X = velXMult;

float velYMult = 1f;
projectile.velocity.Y = velYMult;
if (projectile.timeLeft <= 3)
{
projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
projectile.width = 200;
projectile.height = 40;
}
}


}
}
 
How do you make a boss npc shoot a projectile that is already in-game?

Try Again Mod
BossHead.png

To Many Monsters
 
Is there a way to check how much projectiles are on screen?
[Tutorial] Projectile Guide and Implementation
tModLoader Edition
by: Sin Costan

Introduction:
Hello TCF community, by a request, I have imported the original tAPI guide to tModLoader, with a few changes of course.


This page looks pretty empty boss, where's the tutorial?
By the power of Google Docs, I have made it in that, though reading code will be a pain, so you might want to look at MPT.zip instead if you want to read code. The Google Doc for the guide is VERY detailed, reaching nearly 20 PAGES! Of course, you can just skip through the reading portions, but I highly recommend reading through them if you have little to no experience with modding or coding. The advanced concepts will be on this thread. If you want to learn something from my original guide or something from Vanilla Terraria, then comment on the thread and if multiple people like it, I will add it. Also, if you need any help, go ahead and post a comment and either me or experts will try and help, just remember this is for Projectiles and their Implements (though you can implement projectiles on nearly everything...)


The Google Docs Link:
Projectile Guide and Implementation

Resources:
Dust and Sound Catalogue
Sin Costan's Collection of Fun Projectiles: Once Agai
 
Advanced Concepts:

For those who want to make a homing projectile without the use of an aiStyle try this. This is a modified version of my PDT Bullet in COFP. This should go inside the AI hook.
Code:
//For all of the NPC slots in Main.npc
//Note, you can replace NPC with other entities such as Projectiles and Players
public override void AI()
{
    for(int i = 0; i < 200; i++)
    {
       NPC target = Main.npc[i];
       //If the npc is hostile
       if(target.hostile)
       {
           //Get the shoot trajectory from the projectile and target
           float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
           float shootToY = target.position.Y - projectile.Center.Y;
           float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));

           //If the distance between the live targeted npc and the projectile is less than 480 pixels
           if(distance < 480f && !target.friendly && target.active)
           {
               //Divide the factor, 3f, which is the desired velocity
               distance = 3f / distance;
  
               //Multiply the distance by a multiplier if you wish the projectile to have go faster
               shootToX *= distance * 5;
               shootToY *= distance * 5;

               //Set the velocities to the shoot values
               projectile.velocity.X = shootToX;
               projectile.velocity.Y = shootToY;
           }
       }
    }
}

I see this a lot on the forums, asking how to make things shoot at a target so, here you guys go. This is a modified version of my PDT from COFP. This should be inside the AI hook.
Code:
//Note, you can use this with an NPC to shoot at a Player also
//For every npc slot in Main.npc
public override void AI()
{
    for(int i = 0; i < 200; i++)
    {
       //Enemy NPC variable being set
       NPC target = Main.npc[i];

       //Getting the shooting trajectory
       float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
       float shootToY = target.position.Y - projectile.Center.Y;
       float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));

       //If the distance between the projectile and the live target is active
       if(distance < 480f && !target.friendly && target.active)
       {
           if(projectile.ai[0] > 4f) //Assuming you are already incrementing this in AI outside of for loop
           {
               //Dividing the factor of 3f which is the desired velocity by distance
               distance = 3f / distance;
  
               //Multiplying the shoot trajectory with distance times a multiplier if you so choose to
               shootToX *= distance * 5;
               shootToY *= distance * 5;
  
               //Shoot projectile and set ai back to 0
               Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, shootToX, shootToY, 1, 0, 0, Main.myPlayer, 0f, 0f); //Spawning a projectile
               Main.PlaySound(2, (int)projectile.position.X, (int)projectile.position.Y, 11); //Bullet noise
               projectile.ai[0] = 0f;
           }
       }
    }
    projectile.ai[0] += 1f;
}

I just figured this out, and I felt really dumb because it was really simple... with the power of Math: Trigonometry Edition, here's how you can make a projectile orbit around something. This example involves orbiting the player.
Code:
public override void AI()
{
    //Making player variable "p" set as the projectile's owner
    Player p = Main.player[projectile.owner];

    //Factors for calculations
    double deg = (double) projectile.ai[1]; //The degrees, you can multiply projectile.ai[1] to make it orbit faster, may be choppy depending on the value
    double rad = deg * (Math.PI / 180); //Convert degrees to radians
    double dist = 64; //Distance away from the player
 
    /*Position the player based on where the player is, the Sin/Cos of the angle times the /
    /distance for the desired distance away from the player minus the projectile's width   /
    /and height divided by two so the center of the projectile is at the right place.     */
    projectile.position.X = player.Center.X - (int)(Math.Cos(rad) * dist) - projectile.width/2;
    projectile.position.Y = player.Center.Y - (int)(Math.Sin(rad) * dist) - projectile.height/2;
 
    //Increase the counter/angle in degrees by 1 point, you can change the rate here too, but the orbit may look choppy depending on the value
    projectile.ai[1] += 1f;
}
Is this outdated?
 
Should still work.
It'll work, but this guide is indeed VERY dated and the code is not good

as an example, lets dissent the homing code example:
Code:
//For all of the NPC slots in Main.npc
//Note, you can replace NPC with other entities such as Projectiles and Players
public override void AI()
{
    for(int i = 0; i < 200; i++)
    {
       NPC target = Main.npc[i];
       //If the npc is hostile
       if(target.hostile)
       {
           //Get the shoot trajectory from the projectile and target
           float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
           float shootToY = target.position.Y - projectile.Center.Y;
           float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));

           //If the distance between the live targeted npc and the projectile is less than 480 pixels
           if(distance < 480f && !target.friendly && target.active)
           {
               //Divide the factor, 3f, which is the desired velocity
               distance = 3f / distance;
 
               //Multiply the distance by a multiplier if you wish the projectile to have go faster
               shootToX *= distance * 5;
               shootToY *= distance * 5;

               //Set the velocities to the shoot values
               projectile.velocity.X = shootToX;
               projectile.velocity.Y = shootToY;
           }
       }
    }
}

1: even if this finds a target, it still keeps cycling through all npcs, meaning 2 things:
A: it will only ever home in on the last NPC index who exists, not even the closest enemy either
B: it runs the ENTIRE NPC array all the time, which is alot of extra processing power
2:
Code:
float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
he uses Center in the 2nd part but does it the long way in the 1st? use target.Center-projectile.Center
3:
Code:
float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));
This one is mostly ok, but unless you need to specifically show the distance, you always being used squared values here, as calculating a square root is very slow
4:
Code:
if(distance < 480f && !target.friendly && target.active)
You need more values than this, like npc.dontTakeDamage, also this doesn't even check if the NPC is chasable to begin with, use npc.chasable == true here
Furthermore, these values should be up there where target.hostile is, otherwise your going to calculate the distance even if the enemy cannot be chased
5: ffs use Normalized Vectors here, this distance dividing is overly complicated

Yeah, this guide is very dated with bad coding by a guy who wasn't great at coding to begin with. You should not use it, period.[/code]
 
Last edited:
Just have the shoot value of the item as the ID number or use TerrariaID like this...

Code:
item.shoot = 405; //Literal integer ID of Flairon Bubble
item.shoot = ProjectileID.FlaironBubble; //Must have "using Terraria.ID;" at the top
So i was wondering if you could hemp me with this? ive been trying to make an upgraded zenith, im stuck on trying to get it to do the same animation as the zenith.
 

Attachments

  • Screenshot 2022-08-28 214957.png
    Screenshot 2022-08-28 214957.png
    90.6 KB · Views: 51
use this
Code:
if(!target.friendly)

This will check if the target is not friendly (i.e. town npc) but this will also make it so it targets critters too. It's not the greatest solution, but it should work.
 
would anyone be willing to show me how to make a laser weapon like the last prism? all the guides I could find are in the 1.3 syntax.
the one that sort of works shoots an invisible beam, but it still emits light and does damage.
 
would anyone be willing to show me how to make a laser weapon like the last prism? all the guides I could find are in the 1.3 syntax.
the one that sort of works shoots an invisible beam, but it still emits light and does damage.
Check 1.4 Example mod, should still have a laser weapon example you can use.

But yeah, by the time 1.4 came out nobody was writing public forum coding guides anymore, you'll either need to go to discord or learn off how other mods do it such as example mod. Atleast there's more open source mods now-a-days on github you can look at!
 
Back
Top Bottom