tModLoader [Tutorial] TModLoader: Projectile Help

Is there a way to make a worm-like projectile with multiple segments that follows the mouse like a yoyo?
 
Haven't been on in a while. Sorry! I have other projects I'm working on, so I'm not online often.
The rain code dont works
Can you elaborate? This is an old post, so my code may not work. Can you post your code?
Is there a way to make a worm-like projectile with multiple segments that follows the mouse like a yoyo?
Worm AI is incredibly complex. First you need the head, then you need the segments that follow it, then you need to upload the information to the server in case it's multiplayer, etc. Worm enemy AI can have a lot of code, however this may not apply to projectiles, especially if it follows the mouse. Making it follow the mouse is easy (copy the existing in-game code), but the multiple segments are tricky. I'm bad at AI, and this is mostly for more basic projectiles, like already-existing projectiles or more basic stuff, like spawning new projectiles. There is likely a way (look on the TModLoaderDiscord, they're way better than I am).
How do i make a projectile that splits into X more like the ichor dart?
Splitting projectiles on death is easy, (just put Projectile.NewProjectile in Kill(int timeLeft)) but that's a little more complex:
Since the projectile is similar to the ingame Ichor dart (id 479), I searched 479 in Projectile.cs. I found that a) it uses bullet ai (aiStyle = 1; ) so that's easy and 2: Redigit uses this code to make it work:
Code:
localAI[0] += 1f;
                        if (localAI[0] > 3f)
                        {
                            alpha = 0;
                        }
                        if (ai[0] >= 20f)
                        {
                            ai[0] = 20f;
                            if (type != 477)
                            {
                                base.velocity.Y += 0.075f;
                            }
                        }
                        if (type == 479 && Main.myPlayer == owner)
                        {
                            if (ai[1] >= 0f)
                            {
                                penetrate = -1;
                            }
                            else if (penetrate < 0)
                            {
                                penetrate = 1;
                            }
                            if (ai[1] >= 0f)
                            {
                                ai[1] += 1f;
                            }
                            if (ai[1] > (float)Main.rand.Next(5, 30))
                            {
                                ai[1] = -1000f;
                                float scaleFactor4 = base.velocity.Length();
                                Vector2 velocity = base.velocity;
                                velocity.Normalize();
                                int num161 = Main.rand.Next(2, 4);
                                if (Main.rand.Next(4) == 0)
                                {
                                    num161++;
                                }
                                for (int num162 = 0; num162 < num161; num162++)
                                {
                                    Vector2 vector12 = new Vector2((float)Main.rand.Next(-100, 101), (float)Main.rand.Next(-100, 101));
                                    vector12.Normalize();
                                    vector12 += velocity * 2f;
                                    vector12.Normalize();
                                    vector12 *= scaleFactor4;
                                    NewProjectile(base.Center.X, base.Center.Y, vector12.X, vector12.Y, type, damage, knockBack, owner, 0f, -1000f);
                                }
                            }
                        }
Basically, what it does is it picks a number between 2 & 4 at some point in its AI. It then has a 1/5 chance of adding 1 to that number, so it can get between 2 and 5. It then spawns a projectile in a random direction for each number it picks. There's also things like alpha thrown in for aesthetics.

This code won't work. Since it's in projectile.cs, instead of projectile.___, it uses base.___. This means that this code will only work in projectile.cs, since it doesn't need to reference projectile, it needs to reference itself (base).

The solution, of course, is surprisingly simple. Change all the base. to projectile. and add projectile. in front of projectile variables that don't have it (like localAI[0]).
The code is outside the spoiler.
And here's the AI hook! Works beautifully!
Code:
public override void AI()
        {
            projectile.localAI[0] += 1f;
            if (projectile.localAI[0] > 3f)
            {
                projectile.alpha = 0;
            }
            if (projectile.ai[0] >= 20f)
            {
                projectile.ai[0] = 20f;
                projectile.velocity.Y += 0.075f;
            }
            if (Main.myPlayer == projectile.owner)
            {
                if (projectile.ai[1] >= 0f)
                {
                    projectile.penetrate = -1;
                }
                else if (projectile.penetrate < 0)
                {
                    projectile.penetrate = 1;
                }
                if (projectile.ai[1] >= 0f)
                {
                    projectile.ai[1] += 1f;
                }
                if (projectile.ai[1] > (float)Main.rand.Next(5, 30))
                {
                    projectile.ai[1] = -1000f;
                    float scaleFactor4 = projectile.velocity.Length();
                    Vector2 velocity = projectile.velocity;
                    velocity.Normalize();
                    int num161 = Main.rand.Next(2, 4); // First one is the minimum number of projectiles, second is the maximum.
                    if (Main.rand.Next(4) == 0) //1 in 5 chance (remember, 0 counts as a number here, so 4+1 = 5
                    {
                        num161++; //adds a new projectile.
                    }
                    for (int num162 = 0; num162 < num161; num162++) //repeat num161 (remember, this is the variable used to represent # of projectiles)
                    {
                        Vector2 vector12 = new Vector2((float)Main.rand.Next(-100, 101), (float)Main.rand.Next(-100, 101)); //all of this randomizes rotation
                        vector12.Normalize();
                        vector12 += velocity * 2f;
                        vector12.Normalize();
                        vector12 *= scaleFactor4;
                        Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, vector12.X, vector12.Y, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0f, -1000f); //spawn a projectile
                    }
                }
            }
        }
 
Last edited:
Haven't been on in a while. Sorry! I have other projects I'm working on, so I'm not online often.

Can you elaborate? This is an old post, so my code may not work. Can you post your code?

Worm AI is incredibly complex. First you need the head, then you need the segments that follow it, then you need to upload the information to the server in case it's multiplayer, etc. Worm enemy AI can have a lot of code, however this may not apply to projectiles, especially if it follows the mouse. Making it follow the mouse is easy (copy the existing in-game code), but the multiple segments are tricky. I'm bad at AI, and this is mostly for more basic projectiles, like already-existing projectiles or more basic stuff, like spawning new projectiles. There is likely a way (look on the TModLoaderDiscord, they're way better than I am).

Splitting projectiles on death is easy, (just put Projectile.NewProjectile in Kill(int timeLeft)) but that's a little more complex:
Since the projectile is similar to the ingame Ichor dart (id 479), I searched 479 in Projectile.cs. I found that a) it uses bullet ai (aiStyle = 1; ) so that's easy and 2: Redigit uses this code to make it work:
Code:
localAI[0] += 1f;
                        if (localAI[0] > 3f)
                        {
                            alpha = 0;
                        }
                        if (ai[0] >= 20f)
                        {
                            ai[0] = 20f;
                            if (type != 477)
                            {
                                base.velocity.Y += 0.075f;
                            }
                        }
                        if (type == 479 && Main.myPlayer == owner)
                        {
                            if (ai[1] >= 0f)
                            {
                                penetrate = -1;
                            }
                            else if (penetrate < 0)
                            {
                                penetrate = 1;
                            }
                            if (ai[1] >= 0f)
                            {
                                ai[1] += 1f;
                            }
                            if (ai[1] > (float)Main.rand.Next(5, 30))
                            {
                                ai[1] = -1000f;
                                float scaleFactor4 = base.velocity.Length();
                                Vector2 velocity = base.velocity;
                                velocity.Normalize();
                                int num161 = Main.rand.Next(2, 4);
                                if (Main.rand.Next(4) == 0)
                                {
                                    num161++;
                                }
                                for (int num162 = 0; num162 < num161; num162++)
                                {
                                    Vector2 vector12 = new Vector2((float)Main.rand.Next(-100, 101), (float)Main.rand.Next(-100, 101));
                                    vector12.Normalize();
                                    vector12 += velocity * 2f;
                                    vector12.Normalize();
                                    vector12 *= scaleFactor4;
                                    NewProjectile(base.Center.X, base.Center.Y, vector12.X, vector12.Y, type, damage, knockBack, owner, 0f, -1000f);
                                }
                            }
                        }
Basically, what it does is it picks a number between 2 & 4 at some point in its AI. It then has a 1/5 chance of adding 1 to that number, so it can get between 2 and 5. It then spawns a projectile in a random direction for each number it picks. There's also things like alpha thrown in for aesthetics.

This code won't work. Since it's in projectile.cs, instead of projectile.___, it uses base.___. This means that this code will only work in projectile.cs, since it doesn't need to reference projectile, it needs to reference itself (base).

The solution, of course, is surprisingly simple. Change all the base. to projectile. and add projectile. in front of projectile variables that don't have it (like localAI[0]).
The code is outside the spoiler.
And here's the AI hook! Works beautifully!
Code:
public override void AI()
        {
            projectile.localAI[0] += 1f;
            if (projectile.localAI[0] > 3f)
            {
                projectile.alpha = 0;
            }
            if (projectile.ai[0] >= 20f)
            {
                projectile.ai[0] = 20f;
                projectile.velocity.Y += 0.075f;
            }
            if (Main.myPlayer == projectile.owner)
            {
                if (projectile.ai[1] >= 0f)
                {
                    projectile.penetrate = -1;
                }
                else if (projectile.penetrate < 0)
                {
                    projectile.penetrate = 1;
                }
                if (projectile.ai[1] >= 0f)
                {
                    projectile.ai[1] += 1f;
                }
                if (projectile.ai[1] > (float)Main.rand.Next(5, 30))
                {
                    projectile.ai[1] = -1000f;
                    float scaleFactor4 = projectile.velocity.Length();
                    Vector2 velocity = projectile.velocity;
                    velocity.Normalize();
                    int num161 = Main.rand.Next(2, 4); // First one is the minimum number of projectiles, second is the maximum.
                    if (Main.rand.Next(4) == 0) //1 in 5 chance (remember, 0 counts as a number here, so 4+1 = 5
                    {
                        num161++; //adds a new projectile.
                    }
                    for (int num162 = 0; num162 < num161; num162++) //repeat num161 (remember, this is the variable used to represent # of projectiles)
                    {
                        Vector2 vector12 = new Vector2((float)Main.rand.Next(-100, 101), (float)Main.rand.Next(-100, 101)); //all of this randomizes rotation
                        vector12.Normalize();
                        vector12 += velocity * 2f;
                        vector12.Normalize();
                        vector12 *= scaleFactor4;
                        Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, vector12.X, vector12.Y, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0f, -1000f); //spawn a projectile
                    }
                }
            }
        }
If not like a yoyo, is there a way to make it act like a stardust dragon?
 
If not like a yoyo, is there a way to make it act like a stardust dragon?
Again, probably but I'm not able to, and again, ask on the discord. What you're asking for now is (presumably) the worm AI but instead of following your cursor, homes in on enemies. However, you could probably make a summon that mimics dragon AI, but I'm bad at those and it would just be a minion.
 
When using the below code

Code:
Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //Creates a new projectile with our new vector for spread.

The compiler gives me an error saying Projectile does not contain a definition for new projectile. Here is the full document.

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

namespace DarkSouls.Items
{
    public class Crissaegrim : ModItem
    {
        public override void SetDefaults()
        {
            DisplayName.SetDefault("Crissaegrim");
            Tooltip.SetDefault(    "A powerful, throwable sword made of 30 lost souls of the night\n" +
                                "A dark aura endlessly manifests five blades in the wielder's hand, and will \n" +
                                "return if the wielder's throw misses the one whom it was intended for"    );

            item.width=20;
            item.height=20;
            //item.prefixType=519;
            item.useStyle=1;
            item.useAnimation=30;
            item.useTime=30;
            item.useTurn=true;
            item.maxStack=1;
            item.damage=50;
            item.autoReuse=true;
            item.scale=(float)1;
            item.UseSound = SoundID.Item1;
            item.noMelee=true;
            item.ranged=true;
            //item.maxUpdates=2;
            item.value=200000;
            item.shoot = mod.ProjectileType("Crissaegrim");
        }

        public override void AddRecipes()
        {
            ModRecipe recipe = new ModRecipe(mod);

            recipe.AddIngredient(ModLoader.GetMod("DarkSouls"), "DarkSoul", 80000);
            recipe.AddIngredient(ItemID.SoulofNight, 30);

            recipe.AddTile(TileID.DemonAltar);
            recipe.SetResult(this, 1);
            recipe.AddRecipe();
        }

        public override bool Shoot( Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack )
        {
            float numberProjectiles = 3; // 3 shots
            float rotation = MathHelper.ToRadians(0);//Shoots them in a 45 degree radius. (This is technically 90 degrees because it's 45 degrees up from your cursor and 45 degrees down)
            position += Vector2.Normalize(new Vector2(speedX, speedY)) * 45f; //45 should equal whatever number you had on the previous line
            for (int i = 0; i < numberProjectiles; i++)
            {
                Vector2 perturbedSpeed = new Vector2(speedX, speedY).RotatedBy(MathHelper.Lerp(-rotation, rotation, i / (numberProjectiles - 1))) * .2f; // Vector for spread. Watch out for dividing by 0 if there is only 1 projectile.
                Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //Creates a new projectile with our new vector for spread.
            }
            return false; //makes sure it doesn't shoot the projectile again after this
        }

    }
}

Any help would be greatly appreciated
 
How can you make an enemy fire projectiles? I've searched for it but couldn't find anything to explain how to do it.
 
When using the below code

Code:
Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //Creates a new projectile with our new vector for spread.

The compiler gives me an error saying Projectile does not contain a definition for new projectile. Here is the full document.

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

namespace DarkSouls.Items
{
    public class Crissaegrim : ModItem
    {
        public override void SetDefaults()
        {
            DisplayName.SetDefault("Crissaegrim");
            Tooltip.SetDefault(    "A powerful, throwable sword made of 30 lost souls of the night\n" +
                                "A dark aura endlessly manifests five blades in the wielder's hand, and will \n" +
                                "return if the wielder's throw misses the one whom it was intended for"    );

            item.width=20;
            item.height=20;
            //item.prefixType=519;
            item.useStyle=1;
            item.useAnimation=30;
            item.useTime=30;
            item.useTurn=true;
            item.maxStack=1;
            item.damage=50;
            item.autoReuse=true;
            item.scale=(float)1;
            item.UseSound = SoundID.Item1;
            item.noMelee=true;
            item.ranged=true;
            //item.maxUpdates=2;
            item.value=200000;
            item.shoot = mod.ProjectileType("Crissaegrim");
        }

        public override void AddRecipes()
        {
            ModRecipe recipe = new ModRecipe(mod);

            recipe.AddIngredient(ModLoader.GetMod("DarkSouls"), "DarkSoul", 80000);
            recipe.AddIngredient(ItemID.SoulofNight, 30);

            recipe.AddTile(TileID.DemonAltar);
            recipe.SetResult(this, 1);
            recipe.AddRecipe();
        }

        public override bool Shoot( Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack )
        {
            float numberProjectiles = 3; // 3 shots
            float rotation = MathHelper.ToRadians(0);//Shoots them in a 45 degree radius. (This is technically 90 degrees because it's 45 degrees up from your cursor and 45 degrees down)
            position += Vector2.Normalize(new Vector2(speedX, speedY)) * 45f; //45 should equal whatever number you had on the previous line
            for (int i = 0; i < numberProjectiles; i++)
            {
                Vector2 perturbedSpeed = new Vector2(speedX, speedY).RotatedBy(MathHelper.Lerp(-rotation, rotation, i / (numberProjectiles - 1))) * .2f; // Vector for spread. Watch out for dividing by 0 if there is only 1 projectile.
                Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //Creates a new projectile with our new vector for spread.
            }
            return false; //makes sure it doesn't shoot the projectile again after this
        }

    }
}

Any help would be greatly appreciated
No clue. That line is identical to the one I use in my working shotgun code:
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)
        {
            for (int i = 0; i < 3; i++)
            {
                Vector2 perturbedSpeed = new Vector2(speedX, speedY).RotatedByRandom(MathHelper.ToRadians(12));
                Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //the line in question. Yours is identical, so idk
            }
            return false;
        }
I think you're supposed to put the DisplayName and Tooltip.SetDefault into SetStaticDefaults, though.
How can you make an enemy fire projectiles? I've searched for it but couldn't find anything to explain how to do it.
I'm really bad at mobs. In theory, we could try to attempt to adapt it to a mob like so:
Code:
for(int i = 0; i < 200; i++)
            {
                Player target = Main.player[i];
                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(distance < 480f)
                {
                    if(npc.ai[0] > 10f)
                    {
                        distance = 3f / distance;
                        shootToX *= distance * 5;
                        shootToY *= distance * 5;
                        int proj = Projectile.NewProjectile(npc.Center.X, npc.Center.Y, shootToX, shootToY, mod.ProjectileType("Laser"), npc.damage, npc.knockBack, Main.myPlayer, 0f, 0f); //mod.ProjectileType("Laser") is the projectile it shoots, change it to what you like
                            Main.projectile[proj].timeLeft = 300;
                            Main.projectile[proj].netUpdate = true;
                            projectile.netUpdate = true;
                        Main.PlaySound(2, (int)projectile.position.X, (int)projectile.position.Y, 12);
                        npc.ai[0] = -50f;
                    }
                }
                }
            npc.ai[0] += 1f;
If you put that in an AI hook, there is a (very small) chance that, in fact, the NPC will shoot the specified projectile at the player! I haven't tested it, but if it doesn't work...
I'm bad at mobs. Go to the TModLoader Discord for mobs, because if that doesn't work I can't help you.
 
I figured it out. There is a namespace error when you attempt to make a projectile spawn from an item, due to the fact that the compiler assumes you're calling it from your mod's namespace. So you have to do "Terraria.Projectile.NewProjectile(enter arguements here)" and it will work
 
I've tried to create completely new ammo types and a weapon to fire them.
Weapon's code:
Code:
public override void SetDefaults()
        {

            item.damage = 50;
            item.ranged = true;
            item.width = 30;
            item.height = 20;
            item.useTime = 15;
            item.useAnimation = 15;
            item.useStyle = 5;
            item.noMelee = true;
            item.knockBack = 6;
            item.value = 50000;
            item.rare = 5;
            item.autoReuse = true;
            item.shoot = mod.ProjectileType("BolterBolt");
            item.shootSpeed = 40f;
            item.useAmmo = AmmoID.Bullet;
            item.UseSound = SoundID.Item36;
        }

BolterBolt's projectile code:
Code:
public override void SetStaticDefaults()
        {
            projectile.width = 2; //sprite is 2 pixels wide
            projectile.height = 20; //sprite is 20 pixels tall
            projectile.aiStyle = 0; //projectile moves in a straight line
            projectile.friendly = true; //player projectile
            projectile.ranged = true; //ranged projectile
            projectile.timeLeft = 600; //lasts for 600 frames/ticks. Terraria runs at 60FPS, so it lasts 10 seconds.
            aiType = ProjectileID.Bullet; //This clones the exact AI of the vanilla projectile Bullet.
        }

        public override void Kill(int timeLeft)
        {
            Collision.HitTiles(projectile.position, projectile.velocity, projectile.width, projectile.height); //makes dust based on tile
            Main.PlaySound(SoundID.Item10, projectile.position); //plays impact sound
        }

Lastly, one of many ammo types that a Bolter use:
Code:
public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Standart Bolter Ammo");
        }
        public override void SetDefaults()
        {
            item.damage = 13;
            item.ranged = true;
            item.width = 8;
            item.height = 8;
            item.maxStack = 999;
            item.consumable = true;
            item.knockBack = 4f;
            item.value = Item.sellPrice(0, 0, 1, 0);
            item.rare = 8;
            item.shoot = mod.ProjectileType("BolterBolt");
            item.ammo = AmmoID.Bullet;
        }

This code works but it doesn't do damage to anything, just passing through them. What is missing in this code to do damage, can you help?
 
I've tried to create completely new ammo types and a weapon to fire them.
Weapon's code:
Code:
public override void SetDefaults()
        {

            item.damage = 50;
            item.ranged = true;
            item.width = 30;
            item.height = 20;
            item.useTime = 15;
            item.useAnimation = 15;
            item.useStyle = 5;
            item.noMelee = true;
            item.knockBack = 6;
            item.value = 50000;
            item.rare = 5;
            item.autoReuse = true;
            item.shoot = mod.ProjectileType("BolterBolt");
            item.shootSpeed = 40f;
            item.useAmmo = AmmoID.Bullet;
            item.UseSound = SoundID.Item36;
        }

BolterBolt's projectile code:
Code:
public override void SetStaticDefaults()
        {
            projectile.width = 2; //sprite is 2 pixels wide
            projectile.height = 20; //sprite is 20 pixels tall
            projectile.aiStyle = 0; //projectile moves in a straight line
            projectile.friendly = true; //player projectile
            projectile.ranged = true; //ranged projectile
            projectile.timeLeft = 600; //lasts for 600 frames/ticks. Terraria runs at 60FPS, so it lasts 10 seconds.
            aiType = ProjectileID.Bullet; //This clones the exact AI of the vanilla projectile Bullet.
        }

        public override void Kill(int timeLeft)
        {
            Collision.HitTiles(projectile.position, projectile.velocity, projectile.width, projectile.height); //makes dust based on tile
            Main.PlaySound(SoundID.Item10, projectile.position); //plays impact sound
        }

Lastly, one of many ammo types that a Bolter use:
Code:
public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Standart Bolter Ammo");
        }
        public override void SetDefaults()
        {
            item.damage = 13;
            item.ranged = true;
            item.width = 8;
            item.height = 8;
            item.maxStack = 999;
            item.consumable = true;
            item.knockBack = 4f;
            item.value = Item.sellPrice(0, 0, 1, 0);
            item.rare = 8;
            item.shoot = mod.ProjectileType("BolterBolt");
            item.ammo = AmmoID.Bullet;
        }
To answer your question:
This code works but it doesn't do damage to anything, just passing through them. What is missing in this code to do damage, can you help?
You put the projectile code in SetStaticDefaults() instead of SetDefaults(). This is wrong. The main issue with this is projectile.width and projectile.height, which are the width and height of the hitbox of the projectile and default to 0. Since you have not SetDefaults(), it probably reads the default values, and creates a 0x0 hitbox for the projectile, which of course can't hit anything because it has 0 pixels.

TL;DR: Change your projectile code to SetDefaults instead of SetStaticDefaults.

However, there is another issue with this code, if I interpret this correctly:
I've tried to create completely new ammo types and a weapon to fire them.
Because of item.ammo = AmmoID.Bullet and item.useAmmo = AmmoID.Bullet, you made a bullet and a gun, respectively. I will add something on making custom ammo types soon.
 
You put the projectile code in SetStaticDefaults() instead of SetDefaults(). This is wrong. The main issue with this is projectile.width and projectile.height, which are the width and height of the hitbox of the projectile and default to 0. Since you have not SetDefaults(), it probably reads the default values, and creates a 0x0 hitbox for the projectile, which of course can't hit anything because it has 0 pixels.

TL;DR: Change your projectile code to SetDefaults instead of SetStaticDefaults.

However, there is another issue with this code, if I interpret this correctly:

Because of item.ammo = AmmoID.Bullet and item.useAmmo = AmmoID.Bullet, you made a bullet and a gun, respectively. I will add something on making custom ammo types soon.

Thanks very much. That change fixed the issue.
Another problem is my weapon looks like firing two bullets merged together.
Looking forward to new tutorial.
 
Last edited:
Hey, in the forum post above there is a code indicating how to make a sound when the projectile hits a tile.

My question is: Is there a way to make the projectile make a sound when it is being summoned? I already know how to make the impact sound, but what about when it summoned? I want this to be able to co-exist with my sword swing sound.

-Thx,
Spectr3
 
Sorry, haven't been on in a while.
Hey, in the forum post above there is a code indicating how to make a sound when the projectile hits a tile.

My question is: Is there a way to make the projectile make a sound when it is being summoned? I already know how to make the impact sound, but what about when it summoned? I want this to be able to co-exist with my sword swing sound.

-Thx,
Spectr3
Play the sound in the Shoot method and return true to fire the projectile. Can't make the code rn but it should work.
 
Pls can someone help? I need to do projectile that i can spawn under cursor at any place for a few seconds and it will deal damage on contact
I tried to summon projectile under cursor but nothing works!(
I tried to add something that i found but it's useless and this item cannot even spawn projectile

Code:
public class ExampleMagicMissile : ModItem
    {
        public Vector2 usePos = default(Vector2);

        public bool PreShoot(Player player, Vector2 position, Vector2 velocity, int projType, int damage, float knockback)
        {
            
            usePos = Main.MouseWorld - player.position;
            UseStyle(player);
            position.X = Main.MouseWorld.X;
            position.X += MathHelper.Lerp(-120f, 120f, (float)Main.rand.NextDouble());
            position.Y -= 500;
            velocity.Y = (float)(item.shootSpeed);
            velocity.X = 0;
    
            
            
            return false;
        }
        public override void SetStaticDefaults() {
            DisplayName.SetDefault("Starfury V2");
            Tooltip.SetDefault("This weapon does something special with <right>.");
        }
        public override void SetDefaults() {
            item.shootSpeed = 10;
            item.damage = 10;
            item.shoot = ProjectileType<Projectiles.MagicMissile>();
        }
 
Hello, if you could answer this soon, that would be lovely. How would I make my projectile emit particles after it hitting the ground and stopping?
 
So i have this code for my sword, everything is fine except for two errors on 55 and one on 69 (nice).
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.Localization;

namespace ArkasiaMod.Items.Weapons.Melee
{
    public class ExtinctionSaber : ModItem
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Extinction Saber")
            ; Tooltip.SetDefault("'Forged from the depths of the abyssal grounds'");

        }

        public override void SetDefaults()
        {
            item.damage = 50;
            item.melee = true;
            item.width = 40;
            item.height = 40;
            item.useTime = 10;
            item.useAnimation = 10;
            item.useStyle = 1;
            item.knockBack = 3;
            item.value = 10000;
            item.rare = 2;
            item.UseSound = SoundID.Item1;
            item.autoReuse = true;
            item.crit = 50;
            item.shoot = mod.ProjectileType("ExtinctionBeam");
            item.shootSpeed = 10f;
        }


        public override void AddRecipes()
        {

            ModRecipe recipe = new ModRecipe(mod);

            recipe.SetResult(this);
            recipe.AddRecipeGroup("IronBar", 8);
            recipe.AddRecipeGroup("Wood", 10);
            recipe.AddIngredient(ItemID.HellstoneBar, 25);
            recipe.AddIngredient(ItemID.MeteoriteBar, 10);
            recipe.AddTile(TileID.Anvils);
            recipe.AddRecipe();

        }
    }
    public override bool Shoot(Player player, ref Microsoft.Xna.Framework.Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack)

    {
        int numberProjectiles = 6; // shoots 6 projectiles
        for (int index = 0; index < numberProjectiles; ++index)
        {
            Vector2 vector2_1 = new Vector2((float)((double)player.position.X + (double)player.width * 0.5 + (double)(Main.rand.Next(201) * -player.direction) + ((double)Main.mouseX + (double)Main.screenPosition.X - (double)player.position.X)), (float)((double)player.position.Y + (double)player.height * 0.5 - 600.0));   //this defines the projectile width, direction and position
            vector2_1.X = (float)(((double)vector2_1.X + (double)player.Center.X) / 2.0) + (float)Main.rand.Next(-200, 201);
            vector2_1.Y -= (float)(100 * index);
            float num12 = (float)Main.mouseX + Main.screenPosition.X - vector2_1.X;
            float num13 = (float)Main.mouseY + Main.screenPosition.Y - vector2_1.Y;
            if ((double)num13 < 0.0) num13 *= -1f;
            if ((double)num13 < 20.0) num13 = 20f;
            float num14 = (float)Math.Sqrt((double)num12 * (double)num12 + (double)num13 * (double)num13);
            float num15 = item.shootSpeed / num14;
            float num16 = num12 * num15;
            float num17 = num13 * num15;
            float SpeedX = num16 + (float)Main.rand.Next(-40, 41) * 0.02f; //change the Main.rand.Next here to, for example, (-10, 11) to reduce the spread. Change this to 0 to remove it altogether
            float SpeedY = num17 + (float)Main.rand.Next(-40, 41) * 0.02f;
            Projectile.NewProjectile(vector2_1.X, vector2_1.Y, SpeedX, SpeedY, type, damage, knockBack, Main.myPlayer, 0.0f, (float)Main.rand.Next(5));
        }
        return false;
    }
}

I don't know how to fix this, please help ;(
What do i need to change or add?

Edit: Errors are CS0103, CS0116, CS0115 if that helps.
 
have you tried validating integrity files?
(right-click terraria, click on properties, click on local files, click on verify integrity of game files.
 
Back
Top Bottom