tModLoader [Tutorial] Projectile Guide and Implementation: tModLoader Edition

Ah of course that makes sense....
One thing you can try is the following:
Code:
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 = ProjectileID.BlackBolt;
    return true;
}
You'll want to place this method in your item class.

If you do not know what this does:
We basically intercept this weapon shooting his projectile right before it actually happens, which allows us to change around some variables (such as the position it's shot from, the velocity it's shot with, damage, knockback, etc.) including the type of the bullet that is shot. In this case it overrides every bullet type (with some if statements, you can check if a specific type of bullet is fired). returning true at the end of the method allows vanilla code to execute (if you return false, you can do your own projectile spawning).

Hope this helps!
Should I put numbers in for speedX, speedY, and all the other things?
 
And when i compile it I get error cs1513 (expected "}" )
But in Visual Studio I get an error where it is expecting a comma.
Here is my code

Code:
using Terraria.ID;
using Terraria.ModLoader;

namespace TerrariaUnlimited.Items
{
    public class OnyxRepeater : ModItem
    {
        public override void SetDefaults()
        {
            item.name = "Onyx Repeater";
            item.damage = 38;
            item.ranged = true;
            item.width = 68;
            item.height = 25;
            item.toolTip = "This is currently a test";
            item.useTime = 10;
            item.useAnimation = 20;
            item.useStyle = 5;
            item.noMelee = true;
            item.knockBack = 4;
            item.value = 10000;
            item.rare = 5;
            item.UseSound = SoundID.Item38;
            item.autoReuse = true;
            item.shoot = ProjectileID.BlackBolt; //The Onyx Blaster's projectile
            item.shootSpeed = 4f;
            item.useAmmo = AmmoID.Bullet;
            public override bool Shoot(Player player, ref 10, ref float 10, ref float 10, ref int 10, ref int 10, ref float 10)
        {
            type = ProjectileID.BlackBolt;
            return true;
        }
    }

        public override void AddRecipes()
        {
            ModRecipe recipe = new ModRecipe(mod);
            recipe.AddIngredient(ItemID.OnyxBlaster, 1);
            recipe.AddIngredient(ItemID.HallowedBar, 15);
            recipe.AddTile(TileID.MythrilAnvil);
            recipe.SetResult(this);
            recipe.AddRecipe();
        }
    }
}
 
And when i compile it I get error cs1513 (expected "}" )
But in Visual Studio I get an error where it is expecting a comma.
Here is my code

Code:
using Terraria.ID;
using Terraria.ModLoader;

namespace TerrariaUnlimited.Items
{
    public class OnyxRepeater : ModItem
    {
        public override void SetDefaults()
        {
            item.name = "Onyx Repeater";
            item.damage = 38;
            item.ranged = true;
            item.width = 68;
            item.height = 25;
            item.toolTip = "This is currently a test";
            item.useTime = 10;
            item.useAnimation = 20;
            item.useStyle = 5;
            item.noMelee = true;
            item.knockBack = 4;
            item.value = 10000;
            item.rare = 5;
            item.UseSound = SoundID.Item38;
            item.autoReuse = true;
            item.shoot = ProjectileID.BlackBolt; //The Onyx Blaster's projectile
            item.shootSpeed = 4f;
            item.useAmmo = AmmoID.Bullet;
            public override bool Shoot(Player player, ref 10, ref float 10, ref float 10, ref int 10, ref int 10, ref float 10)
        {
            type = ProjectileID.BlackBolt;
            return true;
        }
    }

        public override void AddRecipes()
        {
            ModRecipe recipe = new ModRecipe(mod);
            recipe.AddIngredient(ItemID.OnyxBlaster, 1);
            recipe.AddIngredient(ItemID.HallowedBar, 15);
            recipe.AddTile(TileID.MythrilAnvil);
            recipe.SetResult(this);
            recipe.AddRecipe();
        }
    }
}
You do not want to put a method inside a method. Do it like follows:
Code:
public override void SetDefaults()
{
    item.name = "Onyx Repeater";
    item.damage = 38;
    item.ranged = true;
    item.width = 68;
    item.height = 25;
    item.toolTip = "This is currently a test";
    item.useTime = 10;
    item.useAnimation = 20;
    item.useStyle = 5;
    item.noMelee = true;
    item.knockBack = 4;
    item.value = 10000;
    item.rare = 5;
    item.UseSound = SoundID.Item38;
    item.autoReuse = true;
    item.shoot = ProjectileID.BlackBolt; //The Onyx Blaster's projectile
    item.shootSpeed = 4f;
    item.useAmmo = AmmoID.Bullet;
}

public override bool Shoot(Player player, ref 10, ref float 10, ref float 10, ref int 10, ref int 10, ref float 10) // <- revert this.
{
    type = ProjectileID.BlackBolt;
    return true;
}

And no, you do not have to fill anything in for the parameters. Just keep the variable names as they are.
 
You do not want to put a method inside a method. Do it like follows:
Code:
public override void SetDefaults()
{
    item.name = "Onyx Repeater";
    item.damage = 38;
    item.ranged = true;
    item.width = 68;
    item.height = 25;
    item.toolTip = "This is currently a test";
    item.useTime = 10;
    item.useAnimation = 20;
    item.useStyle = 5;
    item.noMelee = true;
    item.knockBack = 4;
    item.value = 10000;
    item.rare = 5;
    item.UseSound = SoundID.Item38;
    item.autoReuse = true;
    item.shoot = ProjectileID.BlackBolt; //The Onyx Blaster's projectile
    item.shootSpeed = 4f;
    item.useAmmo = AmmoID.Bullet;
}

public override bool Shoot(Player player, ref 10, ref float 10, ref float 10, ref int 10, ref int 10, ref float 10) // <- revert this.
{
    type = ProjectileID.BlackBolt;
    return true;
}

And no, you do not have to fill anything in for the parameters. Just keep the variable names as they are.
Ahhh. Thank you so much. Now I can put my cool sprites to good use.
 
You do not want to put a method inside a method. Do it like follows:
Code:
public override void SetDefaults()
{
    item.name = "Onyx Repeater";
    item.damage = 38;
    item.ranged = true;
    item.width = 68;
    item.height = 25;
    item.toolTip = "This is currently a test";
    item.useTime = 10;
    item.useAnimation = 20;
    item.useStyle = 5;
    item.noMelee = true;
    item.knockBack = 4;
    item.value = 10000;
    item.rare = 5;
    item.UseSound = SoundID.Item38;
    item.autoReuse = true;
    item.shoot = ProjectileID.BlackBolt; //The Onyx Blaster's projectile
    item.shootSpeed = 4f;
    item.useAmmo = AmmoID.Bullet;
}

public override bool Shoot(Player player, ref 10, ref float 10, ref float 10, ref int 10, ref int 10, ref float 10) // <- revert this.
{
    type = ProjectileID.BlackBolt;
    return true;
}

And no, you do not have to fill anything in for the parameters. Just keep the variable names as they are.
Okay one last thing I promise.
When I compile the mod it gives me this error. I have checked the code and it all works, am I supposed to put something at the top like using Terraria.Player; ?
c:\Users\username\Documents\My Games\Terraria\ModLoader\Mod Sources\TerrariaUnlimited\Items\OnyxRepeater.cs(29,36) : error CS0246: The type or namespace name 'Player' could not be found (are you missing a using directive or an assembly reference?)
 
Okay one last thing I promise.
When I compile the mod it gives me this error. I have checked the code and it all works, am I supposed to put something at the top like using Terraria.Player; ?
c:\Users\username\Documents\My Games\Terraria\ModLoader\Mod Sources\TerrariaUnlimited\Items\OnyxRepeater.cs(29,36) : error CS0246: The type or namespace name 'Player' could not be found (are you missing a using directive or an assembly reference?)
using Terraria;
 
hi guys! So i am trying to make a weapon that fires the lunatic cultist lightning orb and I added the it should be friendlly, but when i tested it, it hurts me insted of the enemies! How should I fix it? Here is my code:​

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

namespace YourModName.Projectiles
{
public class Shattern : ModProjectile
{
public override void SetDefaults()
{
projectile.CloneDefaults(ProjectileID.CultistBossLightningOrb);
projectile.name = "Spirit Sphere";
projectile.friendly = true;
projectile.hostile = false;
projectile.penetrate = 20;
aiType = ProjectileID.CultistBossLightningOrb;

}

public override void AI()
{
if (Main.rand.Next(10) == 0)
{
Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y - 5f, Main.rand.Next(-7, 9) * 5f, Main.rand.Next(-8, -3) * .5f, ProjectileID.CultistBossLightningOrb, (int)(projectile.damage * 1f), 0, projectile.owner);

if (Main.rand.Next(1) == 0)
{
int dust = Dust.NewDust(projectile.position, projectile.width, projectile.height, mod.DustType(""));
Main.dust[dust].velocity /= 1f;
}
}
}
}
}

PS: I don't know why the "curly brackets" are not in the perfect place but in my code, it has different alignment and as well as the codes.
 
hi guys! So i am trying to make a weapon that fires the lunatic cultist lightning orb and I added the it should be friendlly, but when i tested it, it hurts me insted of the enemies! How should I fix it? Here is my code:​

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

namespace YourModName.Projectiles
{
public class Shattern : ModProjectile
{
public override void SetDefaults()
{
projectile.CloneDefaults(ProjectileID.CultistBossLightningOrb);
projectile.name = "Spirit Sphere";
projectile.friendly = true;
projectile.hostile = false;
projectile.penetrate = 20;
aiType = ProjectileID.CultistBossLightningOrb;

}

public override void AI()
{
if (Main.rand.Next(10) == 0)
{
Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y - 5f, Main.rand.Next(-7, 9) * 5f, Main.rand.Next(-8, -3) * .5f, ProjectileID.CultistBossLightningOrb, (int)(projectile.damage * 1f), 0, projectile.owner);

if (Main.rand.Next(1) == 0)
{
int dust = Dust.NewDust(projectile.position, projectile.width, projectile.height, mod.DustType(""));
Main.dust[dust].velocity /= 1f;
}
}
}
}
}

PS: I don't know why the "curly brackets" are not in the perfect place but in my code, it has different alignment and as well as the codes.
You did everything right, its just that the projectile ai style automatically sets the projectile as hostile throughout its life. To counteract this, try "projectile.hostile = false" under the AI hook.
 
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;
}

How would I make this spawn a specific proectile at a target?
 
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace YourModName.Projectiles
{
public class Shattern : ModProjectile
{
public override void SetDefaults()
{
projectile.CloneDefaults(ProjectileID.CultistBossLightningOrb);
projectile.name = "Spirit Sphere";
projectile.friendly = true;
projectile.penetrate = 20;
aiType = ProjectileID.CultistBossLightningOrb;
projectile.hostile = false;
}

public override void AI()
{
if (Main.rand.Next(10) == 0)
{
for (int i = 0; i < 4; i++)
{
Projectile.NewProjectile(projectile.position.X, projectile.position.Y, (float)Main.rand.Next(-35, 36) * 0.2f, (float)Main.rand.Next(-35, 36) * 0.2f, ProjectileID.CultistBossLightningOrb/*307*/, (int)((double)projectile.damage * 0.7), (float)((int)((double)projectile.knockBack * 0.35)), Main.myPlayer, 0f, 0f);
}
}
}
}
}

okay so this is my code now, but still! It hurts me instead of the enemies. :(
 
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace YourModName.Projectiles
{
public class Shattern : ModProjectile
{
public override void SetDefaults()
{
projectile.CloneDefaults(ProjectileID.CultistBossLightningOrb);
projectile.name = "Spirit Sphere";
projectile.friendly = true;
projectile.penetrate = 20;
aiType = ProjectileID.CultistBossLightningOrb;
projectile.hostile = false;
}

public override void AI()
{
if (Main.rand.Next(10) == 0)
{
for (int i = 0; i < 4; i++)
{
Projectile.NewProjectile(projectile.position.X, projectile.position.Y, (float)Main.rand.Next(-35, 36) * 0.2f, (float)Main.rand.Next(-35, 36) * 0.2f, ProjectileID.CultistBossLightningOrb/*307*/, (int)((double)projectile.damage * 0.7), (float)((int)((double)projectile.knockBack * 0.35)), Main.myPlayer, 0f, 0f);
}
}
}
}
}

okay so this is my code now, but still! It hurts me instead of the enemies. :(
Haven't looked at the code, but the orb probably spawns the lightning, which is also hostile. Basically you'll need to copy the code from decompiled for this weapon and all of the sub-projectiles
 
How would I make this spawn a specific proectile at a target?
What do you mean by spawning a specific projectile on a target? If you mean changing what the projectile is firing, you just modify 5th parameter in Projectile.NewProjectile. Here's a layout of the parameters of the Projectile.NewProjectile.

Code:
Projectile.NewProjectile(
int positionX, 
int positionY,
float velocityX,
float velocityY,
int type,
int damage,
float knockback,
int ownerId,
float ai1,
float ai2
)

If this is not the case, could you give me an example of what you mean by your question?

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

namespace YourModName.Projectiles
{
public class Shattern : ModProjectile
{
public override void SetDefaults()
{
projectile.CloneDefaults(ProjectileID.CultistBossLightningOrb);
projectile.name = "Spirit Sphere";
projectile.friendly = true;
projectile.penetrate = 20;
aiType = ProjectileID.CultistBossLightningOrb;
projectile.hostile = false;
}

public override void AI()
{
if (Main.rand.Next(10) == 0)
{
for (int i = 0; i < 4; i++)
{
Projectile.NewProjectile(projectile.position.X, projectile.position.Y, (float)Main.rand.Next(-35, 36) * 0.2f, (float)Main.rand.Next(-35, 36) * 0.2f, ProjectileID.CultistBossLightningOrb/*307*/, (int)((double)projectile.damage * 0.7), (float)((int)((double)projectile.knockBack * 0.35)), Main.myPlayer, 0f, 0f);
}
}
}
}
}

okay so this is my code now, but still! It hurts me instead of the enemies. :(
I agree with Jopojelly, you'll have to look into the actual code for the projectile and modify it as you choose. Only thing I have to say about your code is one of your variable conversions. With your knockback, all you would really need to do is just multiply projectile.knockBack with 0.35 without any conversions, as floats are like doubles, just that it can store a bit more judging from my quick google search and prior knowledge.

You would need to try putting "projectile.hostile = false" in the AI hook like this:

Code:
public override void AI() {
   projectile.hostile = false;
   if (Main.rand.Next(10) == 0)
   {
      for (int i = 0; i < 4; i++)
      {
           Projectile.NewProjectile(projectile.position.X, projectile.position.Y, (float)Main.rand.Next(-35, 36) * 0.2f, (float)Main.rand.Next(-35, 36) * 0.2f, ProjectileID.CultistBossLightningOrb/*307*/, (int)((double)projectile.damage * 0.7), (float)((int)((double)projectile.knockBack * 0.35)), Main.myPlayer, 0f, 0f);
       }
    }
}

And if for the new Projectile that is spawned, you would need to either use the projectile you created or a fancier way of adding the "projectile.hostile = false" through the use of a global Projectile file. Here is an example of a global projectile file.
 
How would one make an enemy shoot a pre-existing friendly projectile? (e.g. a wooden arrow)
You can use the code "Having a projectile shoot at something" in the next post after the opening post and replace all the "projectile" to "npc" and the "npc" to "player". After that, change the projectile ID parameter in Projectile.NewProjectile to the projectile you want. The only thing that is a problem is that if you have it shoot a vanilla projectile, it will be considered friendly to the player, so it will damage the enemy npc instead, so it's best you use a custom projectile for this.
 
Back
Top Bottom