tModLoader [Tutorial] Projectile Guide and Implementation: tModLoader Edition

No, it should be in SetStaticDefaults: that is for modifying static properties, and projFrames is static.

projFrames is a static array in the Main class that keeps track of which projectile has how many frames. Passing the type as the index will return you your projectile, and you can set the amount of frames there. So all you need to do is Main.projFrames[projectile.type] = amount of frames.

If the [ ] operator is new to you, you should look up arrays. You're going to need them if you're working with C#.
Thanks. Btw, the [ ] Operator isn't new to me, I'm just making sure. :)
 
I got it working, but now the weapon is flickering on and off quickly, is there a way to prevent it? Here's the codes I have:
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Items.Weapons.Nirvana
{
    public class Nirvana : ModItem
    {
        public override void SetDefaults()
        {
            item.useStyle = 1;
            item.UseSound = SoundID.Item71;
            item.scale = 0.55f;
            item.damage = 1000;
            item.width = 64;
            item.height = 68;
            item.useTime = 10;
            item.useAnimation = 10;
            item.autoReuse = true;
            item.melee = false;
            item.expert = true;
            item.useTurn = true;
            }

        public override void OnHitNPC(Player player, NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 300);        //Add CursedInferno buff to the NPC for 5 seconds.

            int healingAmount = damage/50;
            player.statLife +=healingAmount;
            player.HealEffect(healingAmount, true);
        }
       
        public override bool AltFunctionUse(Player player)
        {
            return true;
        }

        public override bool CanUseItem(Player player)
        {
            if (player.altFunctionUse == 2)
            {
                item.CloneDefaults(ItemID.Arkhalis);
                item.useStyle = 5;
                item.UseSound = SoundID.Item1;
                item.damage = 1000;
                item.useTime = 24;
                item.useAnimation = 24;
                item.shootSpeed = 18f;
                item.shoot = mod.ProjectileType("NirvanaSlash");
                item.useTurn = false;
                item.noUseGraphic = true;
                item.channel = true;
            }
            else
            {
                item.useStyle = 1;
                item.UseSound = SoundID.Item71;
                item.scale = 0.55f;
                item.damage = 1000;
                item.width = 64;
                item.height = 68;
                item.useTime = 10;
                item.useAnimation = 10;
                item.autoReuse = true;
                item.melee = false;
                item.expert = true;
                item.useTurn = true;
            }
            return base.CanUseItem(player);
        }
       
        public override void AddRecipes() //Cannot add more than 14 items in the recipe, including modded items.
        {
        ModRecipe recipe = new ModRecipe(mod);
        //Vanilla items in the recipe.
        recipe.AddIngredient(ItemID.Arkhalis, 1);
        recipe.AddIngredient(ItemID.Muramasa, 1);
        recipe.AddIngredient(ItemID.LunarBar, 20);
        recipe.AddIngredient(ItemID.HallowedBar, 20);
        recipe.AddIngredient(ItemID.ChlorophyteBar, 20);
        recipe.AddIngredient(ItemID.BrokenHeroSword, 1);
        //Workbench the item is crafted at.
        recipe.AddTile(TileID.LunarCraftingStation);
        recipe.SetResult(this, 1);
        recipe.AddRecipe();
        }
    }
}
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.Nirvana
{
    public class NirvanaSlash : ModProjectile
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Nirvana");
            Main.RegisterItemAnimation(projectile.type, new DrawAnimationVertical(10, 5));
            Main.projFrames[mod.ProjectileType("NirvanaSlash")] = 5;
        }
       
        public override void SetDefaults()
        {
            projectile.width = 80;
            projectile.height = 70;
            projectile.aiStyle = 75;
            projectile.penetrate = -1;
            projectile.friendly = true;
            projectile.melee = true;
            projectile.ownerHitCheck = true;
            projectile.ignoreWater = true;
            projectile.tileCollide = false;
        }

        public override void AI()
        {
            Player player = Main.player[projectile.owner];
            float num = 1.57079637f;
            Vector2 vector = player.RotatedRelativePoint(player.MountedCenter, true);
           
            num = 0f;
            if (projectile.spriteDirection == -1)
            {
                num = 3.14159265274f;
            }
           
            if (++projectile.frame >= Main.projFrames[projectile.type])
            {
                projectile.frame = 1;
            }

            projectile.soundDelay--;
            if (projectile.soundDelay <=0)
            {
                Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 1);
                projectile.soundDelay = 12;
            }
           
            if (Main.myPlayer == projectile.owner)
            {
                if (player.channel && !player.noItems && !player.CCed)
                {
                    float scaleFactor6 = 1f;
                    if (player.inventory[player.selectedItem].shoot == projectile.type)
                    {
                        scaleFactor6 = player.inventory[player.selectedItem].shootSpeed * projectile.scale;
                    }
                   
                    Vector2 vector13 = Main.MouseWorld - vector;
                    vector13.Normalize();
                    if (vector13.HasNaNs())
                    {
                        vector13 = Vector2.UnitX * (float)player.direction;
                    }
                   
                    vector13 *= scaleFactor6;
                    if (vector13.X != projectile.velocity.X || vector13.Y != projectile.velocity.Y)
                    {
                        projectile.netUpdate = true;
                    }
                    projectile.velocity = vector13;
                }
                else
                {
                    projectile.Kill();
               
                }
            }
            Vector2 vector14 = projectile.Center + projectile.velocity * 3f;
            Lighting.AddLight(vector14, 0.1f, 1f, 0.1f);
            projectile.position = player.RotatedRelativePoint(player.MountedCenter, true) - projectile.Size / 2f;
            projectile.rotation = projectile.velocity.ToRotation() + num;
            projectile.spriteDirection = projectile.direction;
            projectile.timeLeft = 2;
            player.ChangeDir(projectile.direction);
            player.heldProj = projectile.whoAmI;
            player.itemTime = 2;
            player.itemAnimation = 2;
            player.itemRotation = (float)Math.Atan2((double)(projectile.velocity.Y * (float)projectile.direction), (double)(projectile.velocity.X * (float)projectile.direction));
        }
       
        public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60);
            target.immune[projectile.owner] = 2;
        }
    }  
}
Also, after I use the Alternate attack (Right Click), it doesn't go back to it's normal left click. Why's that?
 
How do I make an Item/Projectile shoot another (different) Projectile when the Player stops channeling?
Channeled projectiles are killed when the player stops channeling. So one thing you can do is fire projectile in the Kill method.
 
Channeled projectiles are killed when the player stops channeling. So one thing you can do is fire projectile in the Kill method.
Like this?
Code:
public override void Kill(int channel)
        {
            Projectile.NewProjectile(position.X, position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), damage, knockBack, player.whoAmI, 0f, 0f);
        }
It's in the Projectile Code.
 
Like this?
Code:
public override void Kill(int channel)
        {
            Projectile.NewProjectile(position.X, position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), damage, knockBack, player.whoAmI, 0f, 0f);
        }
It's in the Projectile Code.
You can always check the documentation (Kill documentation here).
So yeah, you're using the right principle. Have you tested it to see if this is what you want?
 
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,38) : error CS0103: The name 'position' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,50) : error CS0103: The name 'position' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,62) : error CS0103: The name 'speedX' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,70) : error CS0103: The name 'speedY' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,114) : error CS0103: The name 'damage' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,122) : error CS0103: The name 'knockBack' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,133) : error CS0103: The name 'player' does not exist in the current context
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.Nirvana
{
public class NirvanaSlash : ModProjectile
{
public override void SetStaticDefaults()
{
DisplayName.SetDefault("Nirvana");
Main.RegisterItemAnimation(projectile.type, new DrawAnimationVertical(20, 10));
Main.projFrames[mod.ProjectileType("NirvanaSlash")] = 10;
}

public override void SetDefaults()
{
projectile.width = 86;
projectile.height = 76;
projectile.aiStyle = 75;
projectile.penetrate = -1;
projectile.friendly = true;
projectile.melee = true;
projectile.ownerHitCheck = true;
projectile.ignoreWater = true;
projectile.tileCollide = false;
}

public override void AI()
{
Player player = Main.player[projectile.owner];
float num = 1.57079637f;
Vector2 vector = player.RotatedRelativePoint(player.MountedCenter, true);

num = 0f;
if (projectile.spriteDirection == -1)
{
num = 3.14159265274f;
}

if (++projectile.frame >= Main.projFrames[projectile.type])
{
projectile.frame = 1;
}

projectile.soundDelay--;
if (projectile.soundDelay <=0)
{
Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 1);
projectile.soundDelay = 16;
}

if (Main.myPlayer == projectile.owner)
{
if (player.channel && !player.noItems && !player.CCed)
{
float scaleFactor6 = 1f;
if (player.inventory[player.selectedItem].shoot == projectile.type)
{
scaleFactor6 = player.inventory[player.selectedItem].shootSpeed * projectile.scale;
}

Vector2 vector13 = Main.MouseWorld - vector;
vector13.Normalize();
if (vector13.HasNaNs())
{
vector13 = Vector2.UnitX * (float)player.direction;
}

vector13 *= scaleFactor6;
if (vector13.X != projectile.velocity.X || vector13.Y != projectile.velocity.Y)
{
projectile.netUpdate = true;
}
projectile.velocity = vector13;
}
else
{
projectile.Kill();
}
}
Vector2 vector14 = projectile.Center + projectile.velocity * 3f;
Lighting.AddLight(vector14, 0.1f, 1f, 0.1f);
projectile.position = player.RotatedRelativePoint(player.MountedCenter, true) - projectile.Size / 2f;
projectile.rotation = projectile.velocity.ToRotation() + num;
projectile.spriteDirection = projectile.direction;
projectile.timeLeft = 2;
player.ChangeDir(projectile.direction);
player.heldProj = projectile.whoAmI;
player.itemTime = 2;
player.itemAnimation = 2;
player.itemRotation = (float)Math.Atan2((double)(projectile.velocity.Y * (float)projectile.direction), (double)(projectile.velocity.X * (float)projectile.direction));

Lighting.AddLight(projectile.Center, 0f, 1f, 0f); //This is the projectile light color R, G, B (Red, Green, Blue).
}

public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
{
target.AddBuff(BuffID.CursedInferno, 5 * 60);
target.immune[projectile.owner] = 2;
}

public override void Kill(int channel)
{
Projectile.NewProjectile(position.X, position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), damage, knockBack, player.whoAmI, 0f, 0f);
}

}
}
 
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,38) : error CS0103: The name 'position' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,50) : error CS0103: The name 'position' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,62) : error CS0103: The name 'speedX' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,70) : error CS0103: The name 'speedY' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,114) : error CS0103: The name 'damage' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,122) : error CS0103: The name 'knockBack' does not exist in the current context

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\Nirvana\NirvanaSlash.cs(109,133) : error CS0103: The name 'player' does not exist in the current context
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.Nirvana
{
public class NirvanaSlash : ModProjectile
{
public override void SetStaticDefaults()
{
DisplayName.SetDefault("Nirvana");
Main.RegisterItemAnimation(projectile.type, new DrawAnimationVertical(20, 10));
Main.projFrames[mod.ProjectileType("NirvanaSlash")] = 10;
}

public override void SetDefaults()
{
projectile.width = 86;
projectile.height = 76;
projectile.aiStyle = 75;
projectile.penetrate = -1;
projectile.friendly = true;
projectile.melee = true;
projectile.ownerHitCheck = true;
projectile.ignoreWater = true;
projectile.tileCollide = false;
}

public override void AI()
{
Player player = Main.player[projectile.owner];
float num = 1.57079637f;
Vector2 vector = player.RotatedRelativePoint(player.MountedCenter, true);

num = 0f;
if (projectile.spriteDirection == -1)
{
num = 3.14159265274f;
}

if (++projectile.frame >= Main.projFrames[projectile.type])
{
projectile.frame = 1;
}

projectile.soundDelay--;
if (projectile.soundDelay <=0)
{
Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 1);
projectile.soundDelay = 16;
}

if (Main.myPlayer == projectile.owner)
{
if (player.channel && !player.noItems && !player.CCed)
{
float scaleFactor6 = 1f;
if (player.inventory[player.selectedItem].shoot == projectile.type)
{
scaleFactor6 = player.inventory[player.selectedItem].shootSpeed * projectile.scale;
}

Vector2 vector13 = Main.MouseWorld - vector;
vector13.Normalize();
if (vector13.HasNaNs())
{
vector13 = Vector2.UnitX * (float)player.direction;
}

vector13 *= scaleFactor6;
if (vector13.X != projectile.velocity.X || vector13.Y != projectile.velocity.Y)
{
projectile.netUpdate = true;
}
projectile.velocity = vector13;
}
else
{
projectile.Kill();
}
}
Vector2 vector14 = projectile.Center + projectile.velocity * 3f;
Lighting.AddLight(vector14, 0.1f, 1f, 0.1f);
projectile.position = player.RotatedRelativePoint(player.MountedCenter, true) - projectile.Size / 2f;
projectile.rotation = projectile.velocity.ToRotation() + num;
projectile.spriteDirection = projectile.direction;
projectile.timeLeft = 2;
player.ChangeDir(projectile.direction);
player.heldProj = projectile.whoAmI;
player.itemTime = 2;
player.itemAnimation = 2;
player.itemRotation = (float)Math.Atan2((double)(projectile.velocity.Y * (float)projectile.direction), (double)(projectile.velocity.X * (float)projectile.direction));

Lighting.AddLight(projectile.Center, 0f, 1f, 0f); //This is the projectile light color R, G, B (Red, Green, Blue).
}

public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
{
target.AddBuff(BuffID.CursedInferno, 5 * 60);
target.immune[projectile.owner] = 2;
}

public override void Kill(int channel)
{
Projectile.NewProjectile(position.X, position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), damage, knockBack, player.whoAmI, 0f, 0f);
}

}
}
Again: you're using the right principle. Not the right code :p
I think you're trying to use the same Projectile.NewProjectile code commonly used in Shoot methods of items. That's not really possible here.
position is not a variable that you have access to from a ModProjectile object. You'll want to reference the projectile.position instead.
You also have to calculate your own velocity values, since speedX and speedY don't exist in this context.
The same rule for the position is valid for the damage, knockBack and index parameters. All in all, it should look more like this:
Code:
float speedX = 5, speedY = 5;
Projectile.NewProjectile(projectile.position.X, projectile.position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), projectile.damage, projectile.knockBack, projectile.owner);
 
Again: you're using the right principle. Not the right code :p
I think you're trying to use the same Projectile.NewProjectile code commonly used in Shoot methods of items. That's not really possible here.
position is not a variable that you have access to from a ModProjectile object. You'll want to reference the projectile.position instead.
You also have to calculate your own velocity values, since speedX and speedY don't exist in this context.
The same rule for the position is valid for the damage, knockBack and index parameters. All in all, it should look more like this:
Code:
float speedX = 5, speedY = 5;
Projectile.NewProjectile(projectile.position.X, projectile.position.Y, speedX, speedY, mod.ProjectileType("AronditeWind"), projectile.damage, projectile.knockBack, projectile.owner);
Thanks. :)
Now I need help on a "Spinning Weapon", and the code I'm using is outdated, I think. I dunno. The error looks like this:
Code:
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(29,24) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.AI()': no suitable method found to override

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(59,30) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.PreDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch, Microsoft.Xna.Framework.Color)': no suitable method found to override

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(66,24) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.OnHitNPC(Terraria.NPC, int, float, bool)': no suitable method found to override
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.MourningArc
{
    public class MourningArc : ModItem
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Mourning Arc");    //The weapon's name when shown in-game.
        }
       
        public override void SetDefaults()
        {
            projectile.width = 220;
            projectile.height = 220;
            projectile.penetrate = -1;
            projectile.ignoreWater = true;
            projectile.melee = true;
            projectile.friendly = true;
            projectile.tileCollide = false;
        }
       
        public override void AI()
        {
            //The sound of the projectile.
            projectile.soundDelay--;
            if (projectile.soundDelay <= 0)
            {
                Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 15); //Cant tell if "2" or "15" is the SoundID. Either way I want SoundID of "71" (Death Sickle's Swing Sound).
                projectile.soundDelay = 45;
            }
           
            //How the projectile works.
            Player player = Main.player[projectile.owner];
            if (Main.myPlayer == projectile.owner)
            {
                if (!player.channel || player.noItems || player.CCed)
                {
                    projectile.Kill();
                }
            }
            Lighting.AddLight(projectile.Center, 1f, 0.6f, 0f); //This is the Projectile's light color (RGB)
            projectile.Center = player.MountedCenter;
            projectile.position.X += player.width / 2 * player.direction;
            projectile.spriteDirection = player.direction;
            projectile.rotation += 0.3f * player.direction; //This is the Projectile's Spinnig/Rotation Speed
            if (projectile.rotation > MathHelper.TwoPi)
            {
                projectile.rotation -= MathHelper.TwoPi;
            }
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color lightColor)
        {
            Texture2D texture = Main.projectileTexture[projectile.type];
            spriteBatch.Draw(texture, projectile.Center - Main.screenPosition, null, Color.White, projectile.rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1f, projectile.spriteDirection == 1 ? SpriteEffects.None : SpriteEffects.FlipHorizontally, 0f);
            return false;
        }
       
        public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60); //Add CursedInferno Buff to the NPC for 5 seconds.
        }
    }
}
[/CODE[/SPOILER]
 
Thanks. :)
Now I need help on a "Spinning Weapon", and the code I'm using is outdated, I think. I dunno. The error looks like this:
Code:
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(29,24) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.AI()': no suitable method found to override

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(59,30) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.PreDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch, Microsoft.Xna.Framework.Color)': no suitable method found to override

c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Projectiles\MourningArc\MourningArc.cs(66,24) : error CS0115: 'JoshuasMod.Projectiles.MourningArc.MourningArc.OnHitNPC(Terraria.NPC, int, float, bool)': no suitable method found to override
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.MourningArc
{
    public class MourningArc : ModItem
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Mourning Arc");    //The weapon's name when shown in-game.
        }
      
        public override void SetDefaults()
        {
            projectile.width = 220;
            projectile.height = 220;
            projectile.penetrate = -1;
            projectile.ignoreWater = true;
            projectile.melee = true;
            projectile.friendly = true;
            projectile.tileCollide = false;
        }
      
        public override void AI()
        {
            //The sound of the projectile.
            projectile.soundDelay--;
            if (projectile.soundDelay <= 0)
            {
                Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 15); //Cant tell if "2" or "15" is the SoundID. Either way I want SoundID of "71" (Death Sickle's Swing Sound).
                projectile.soundDelay = 45;
            }
          
            //How the projectile works.
            Player player = Main.player[projectile.owner];
            if (Main.myPlayer == projectile.owner)
            {
                if (!player.channel || player.noItems || player.CCed)
                {
                    projectile.Kill();
                }
            }
            Lighting.AddLight(projectile.Center, 1f, 0.6f, 0f); //This is the Projectile's light color (RGB)
            projectile.Center = player.MountedCenter;
            projectile.position.X += player.width / 2 * player.direction;
            projectile.spriteDirection = player.direction;
            projectile.rotation += 0.3f * player.direction; //This is the Projectile's Spinnig/Rotation Speed
            if (projectile.rotation > MathHelper.TwoPi)
            {
                projectile.rotation -= MathHelper.TwoPi;
            }
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color lightColor)
        {
            Texture2D texture = Main.projectileTexture[projectile.type];
            spriteBatch.Draw(texture, projectile.Center - Main.screenPosition, null, Color.White, projectile.rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1f, projectile.spriteDirection == 1 ? SpriteEffects.None : SpriteEffects.FlipHorizontally, 0f);
            return false;
        }
      
        public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60); //Add CursedInferno Buff to the NPC for 5 seconds.
        }
    }
}
[/CODE[/SPOILER]
You're trying to put projectile code into a ModItem.
 
Yup, projectiles have the exact same variable.
"projectile.scale = #f;" seems to only work on the Hitbox Sizes, not the actual sprite itself. :(
Also where do I import this code? I know it goes in "public override bool CanUseItem(Player player)" line, but I'm not exactly sure where. It's the same place where the Alt. Function (Right Click) happens.
Code:
public override bool CanUseItem(Player player) //This piece of Code makes it so that the Item shoots only 1 Boomerang at a time.
        {
            for (int i = 0; i < 1000; ++i)
            {
                if (Main.projectile[i].active && Main.projectile[i].owner == Main.myPlayer && Main.projectile[i].type == item.shoot)
                {
                    return false;
                }
            }
            return true;
        }
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Items.Weapons.Arondite
{
    public class Arondite : ModItem
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Arondite");    //The weapon's name when shown in-game.
        }
      
        public override void SetDefaults()
        {
            item.useStyle = 1;
            item.UseSound = SoundID.Item71;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 10;
            item.useAnimation = 10;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = false;
            item.useTurn = true;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = 0;
            item.scale = 0.7f;
        }
      
        public override bool AltFunctionUse(Player player)
        {
            return true;
        }

        public override bool CanUseItem(Player player)
        {
            if (player.altFunctionUse == 2)
            {
            item.useStyle = 1;
            item.UseSound = SoundID.Item1;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 12;
            item.useAnimation = 12;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = true;
            item.useTurn = false;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = mod.ProjectileType("Arondite");
            item.shootSpeed = 12f;
            item.scale = 0.7f;
            }
            else
            {
            item.useStyle = 1;
            item.UseSound = SoundID.Item71;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 10;
            item.useAnimation = 10;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = false;
            item.useTurn = true;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = 0;
            item.scale = 0.7f;
            }
            return base.CanUseItem(player);
        }

        public override void OnHitNPC(Player player, NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60);        //Add CursedInferno buff to the NPC for 5 seconds.

            int healingAmount = damage/40;
            player.statLife +=healingAmount;
            player.HealEffect(healingAmount, true);
        }
    }
}
 
"projectile.scale = #f;" seems to only work on the Hitbox Sizes, not the actual sprite itself. :(
Also where do I import this code? I know it goes in "public override bool CanUseItem(Player player)" line, but I'm not exactly sure where. It's the same place where the Alt. Function (Right Click) happens.
Code:
public override bool CanUseItem(Player player) //This piece of Code makes it so that the Item shoots only 1 Boomerang at a time.
        {
            for (int i = 0; i < 1000; ++i)
            {
                if (Main.projectile[i].active && Main.projectile[i].owner == Main.myPlayer && Main.projectile[i].type == item.shoot)
                {
                    return false;
                }
            }
            return true;
        }
Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Items.Weapons.Arondite
{
    public class Arondite : ModItem
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Arondite");    //The weapon's name when shown in-game.
        }
     
        public override void SetDefaults()
        {
            item.useStyle = 1;
            item.UseSound = SoundID.Item71;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 10;
            item.useAnimation = 10;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = false;
            item.useTurn = true;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = 0;
            item.scale = 0.7f;
        }
     
        public override bool AltFunctionUse(Player player)
        {
            return true;
        }

        public override bool CanUseItem(Player player)
        {
            if (player.altFunctionUse == 2)
            {
            item.useStyle = 1;
            item.UseSound = SoundID.Item1;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 12;
            item.useAnimation = 12;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = true;
            item.useTurn = false;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = mod.ProjectileType("Arondite");
            item.shootSpeed = 12f;
            item.scale = 0.7f;
            }
            else
            {
            item.useStyle = 1;
            item.UseSound = SoundID.Item71;
            item.damage = 1000;
            item.width = 48;
            item.height = 50;
            item.useTime = 10;
            item.useAnimation = 10;
            item.melee = true;
            item.expert = true;
            item.autoReuse = true;
            item.noUseGraphic = false;
            item.useTurn = true;
            item.noMelee = false;
            item.value = Item.sellPrice(1, 50, 0, 0);
            item.shoot = 0;
            item.scale = 0.7f;
            }
            return base.CanUseItem(player);
        }

        public override void OnHitNPC(Player player, NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60);        //Add CursedInferno buff to the NPC for 5 seconds.

            int healingAmount = damage/40;
            player.statLife +=healingAmount;
            player.HealEffect(healingAmount, true);
        }
    }
}
That's strange. In the vanilla drawing code, projectile.scale is clearly used as the size/scale parameter. I'll have to loop into that, then.
As for your question: I'm guessing you want to check that little piece of code when player.altFunctionUse == 2?
If so, just implement the contents of your other method near the bottom of that if statement. Note that I replaced the for loop you showed with an (imo) much cleaner lambda expression:
Code:
public override bool CanUseItem(Player player)
{
    if (player.altFunctionUse == 2)
    {
        item.useStyle = 1;
        item.UseSound = SoundID.Item1;
        item.damage = 1000;
        item.width = 48;
        item.height = 50;
        item.useTime = 12;
        item.useAnimation = 12;
        item.melee = true;
        item.expert = true;
        item.autoReuse = true;
        item.noUseGraphic = true;
        item.useTurn = false;
        item.noMelee = false;
        item.value = Item.sellPrice(1, 50, 0, 0);
        item.shoot = mod.ProjectileType("Arondite");
        item.shootSpeed = 12f;
        item.scale = 0.7f;
       
        // An (imo) much cleaner lambda expression, which basically does the same as the for loop.
        return !Main.projectile.Select(proj => proj.active && proj.owner == Main.myPlayer && proj.type == item.shoot);
    }
    else
    {
        item.useStyle = 1;
        item.UseSound = SoundID.Item71;
        item.damage = 1000;
        item.width = 48;
        item.height = 50;
        item.useTime = 10;
        item.useAnimation = 10;
        item.melee = true;
        item.expert = true;
        item.autoReuse = true;
        item.noUseGraphic = false;
        item.useTurn = true;
        item.noMelee = false;
        item.value = Item.sellPrice(1, 50, 0, 0);
        item.shoot = 0;
        item.scale = 0.7f;
    }
    return true;
}
For this code to work you do have to have using System.Linq; at the top of your file.
 
That's strange. In the vanilla drawing code, projectile.scale is clearly used as the size/scale parameter. I'll have to loop into that, then.
As for your question: I'm guessing you want to check that little piece of code when player.altFunctionUse == 2?
If so, just implement the contents of your other method near the bottom of that if statement. Note that I replaced the for loop you showed with an (imo) much cleaner lambda expression:
Code:
public override bool CanUseItem(Player player)
{
    if (player.altFunctionUse == 2)
    {
        item.useStyle = 1;
        item.UseSound = SoundID.Item1;
        item.damage = 1000;
        item.width = 48;
        item.height = 50;
        item.useTime = 12;
        item.useAnimation = 12;
        item.melee = true;
        item.expert = true;
        item.autoReuse = true;
        item.noUseGraphic = true;
        item.useTurn = false;
        item.noMelee = false;
        item.value = Item.sellPrice(1, 50, 0, 0);
        item.shoot = mod.ProjectileType("Arondite");
        item.shootSpeed = 12f;
        item.scale = 0.7f;
      
        // An (imo) much cleaner lambda expression, which basically does the same as the for loop.
        return !Main.projectile.Select(proj => proj.active && proj.owner == Main.myPlayer && proj.type == item.shoot);
    }
    else
    {
        item.useStyle = 1;
        item.UseSound = SoundID.Item71;
        item.damage = 1000;
        item.width = 48;
        item.height = 50;
        item.useTime = 10;
        item.useAnimation = 10;
        item.melee = true;
        item.expert = true;
        item.autoReuse = true;
        item.noUseGraphic = false;
        item.useTurn = true;
        item.noMelee = false;
        item.value = Item.sellPrice(1, 50, 0, 0);
        item.shoot = 0;
        item.scale = 0.7f;
    }
    return true;
}
For this code to work you do have to have using System.Linq; at the top of your file.
Thanks. :) I used my own method to shoot the 1 Boomerang, because when I tried yours, it came up with this error:
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Items\Weapons\Arondite\Arondite.cs(69,24) : error CS0023: Operator '!' cannot be applied to operand of type 'System.Collections.Generic.IEnumerable<bool>'
Also, please tell me when you figured out the "projectile.scale" problem. :)
 
Thanks. :) I used my own method to shoot the 1 Boomerang, because when I tried yours, it came up with this error:
c:\Users\Joshua\Documents\My Games\Terraria\ModLoader\Mod Sources\JoshuasMod\Items\Weapons\Arondite\Arondite.cs(69,24) : error CS0023: Operator '!' cannot be applied to operand of type 'System.Collections.Generic.IEnumerable<bool>'
Also, please tell me when you figured out the "projectile.scale" problem. :)
Oh lol, that's my bad. I don't know why my compiler would allow that xD
If you want to fix that oneliner:
Code:
return !Array.Exists(Main.projectile, proj => proj.active && proj.owner == Main.myPlayer && proj.type == item.shoot);
But you can always use your own code as you please ofc :)
I'll let you know what I find out about the projectile.scale part. I'll probably look into it sometime today.

Edit:
The only thing that comes to mind now is that you're manually drawing your projectile?
 
Edit:
The only thing that comes to mind now is that you're manually drawing your projectile?
Yeah, shouldn't be too hard, just resizing the sprite to half the size. :)
Looks like this:
MourningArc.png
 
How to make vanilla projectiles fall from sky like Star Wrath or Blizzard Staff? I wanted to create sword that makes Vampire Knives fall like that.
 
How to make vanilla projectiles fall from sky like Star Wrath or Blizzard Staff? I wanted to create sword that makes Vampire Knives fall like that.
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)
        {
            int numberProjectiles = 2 + Main.rand.Next(1);
            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(100) * -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(-100, 100);
                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(-12, 10) * 0.160f;  //This defines the projectile X position speed and randomness.
                float SpeedY = num17 + (float)Main.rand.Next(-12, 10) * 0.160f;  //This defines the projectile Y position speed and randomness.
                Projectile.NewProjectile(vector2_1.X, vector2_1.Y, SpeedX, SpeedY, type, damage, knockBack, Main.myPlayer, 0.0f, (float)Main.rand.Next(5));              
            }
            return false;
        }
Try that, and experiment with different randomness and speeds until you're satisfied with what you got. :)
For shooting different projectiles (As well as the first Projectile) from the top of the screen, use this (It goes at the bottom of the piece of code):
Code:
Projectile.NewProjectile(vector2_1.X, vector2_1.Y, SpeedX * 1.50f, SpeedY * 1.50f, mod.ProjectileType("CataclysmicLife"), damage * 1, knockBack, Main.myPlayer, 0.0f, (float)Main.rand.Next(5)); //Whatever new projectile you want to spawn will be 50% faster than the first projectile, because the Speed is 1.50 times faster.
Hope this helps. :)
 
Oh lol, that's my bad. I don't know why my compiler would allow that xD
If you want to fix that oneliner:
Code:
return !Array.Exists(Main.projectile, proj => proj.active && proj.owner == Main.myPlayer && proj.type == item.shoot);
But you can always use your own code as you please ofc :)
I'll let you know what I find out about the projectile.scale part. I'll probably look into it sometime today.

Edit:
The only thing that comes to mind now is that you're manually drawing your projectile?
Before I forget, here's the Projectile Code:
Code:
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.DataStructures;

namespace JoshuasMod.Projectiles.MourningArc
{
    public class MourningArc : ModProjectile
    {
        public override void SetStaticDefaults()
        {
            DisplayName.SetDefault("Mourning Arc");    //The weapon's name when shown in-game.
        }
       
        public override void SetDefaults()
        {
            projectile.width = 120;
            projectile.height = 120;
            projectile.timeLeft = 15;
            projectile.penetrate = -1;
            projectile.scale = 0.6f;
            projectile.ignoreWater = true;
            projectile.melee = true;
            projectile.friendly = true;
            projectile.tileCollide = false;
        }
       
        public override void AI()
        {
            //The sound code for the projectile.
            projectile.soundDelay--;
            if (projectile.soundDelay <= 0)
            {
                Main.PlaySound(2, (int)projectile.Center.X, (int)projectile.Center.Y, 15);
                projectile.soundDelay = 45;
            }
           
            //How the projectile works.
            Player player = Main.player[projectile.owner];
            if (Main.myPlayer == projectile.owner)
            {
                if (!player.channel || player.noItems || player.CCed)
                {
                    projectile.Kill();
                }
            }
            Lighting.AddLight(projectile.Center, 0f, 1f, 0f); //This is the Projectile's light color (RGB)
           
            projectile.Center = player.MountedCenter;
            projectile.position.X += player.width / 2 * player.direction;
            projectile.spriteDirection = player.direction;
            projectile.rotation += 0.36f * player.direction; //This is the Projectile's Spinning/Rotation Speed
            if (projectile.rotation > MathHelper.TwoPi)
            {
                projectile.rotation -= MathHelper.TwoPi;
            }
        }

        public override bool PreDraw(SpriteBatch spriteBatch, Color lightColor)
        {
            Texture2D texture = Main.projectileTexture[projectile.type];
            spriteBatch.Draw(texture, projectile.Center - Main.screenPosition, null, Color.White, projectile.rotation, new Vector2(texture.Width / 2, texture.Height / 2), 1f, projectile.spriteDirection == 1 ? SpriteEffects.None : SpriteEffects.FlipHorizontally, 0f);
            return false;
        }
       
        public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
        {
            target.AddBuff(BuffID.CursedInferno, 5 * 60); //Add CursedInferno Buff to the NPC for 5 seconds.
            target.immune[projectile.owner] = 2;
        }
    }
}
I used the "projectile.scale" line in a different Projectile, and that seemed to work for that Projectile. I'm guessing there's a code preventing "projectile.scale" from changing the sprite, because this Projectile is a spinning weapon (Like the Sky Dragon's Fury).
 
Back
Top Bottom