This is Many
Retinazer
Introduction
Hi everyone! It's been 9 months since the last tutorial because I was too lazy and busy with my projects.
In this tutorial, we'll make weapons for ranger and mage that will be way harder than a sword we did in previous tutorial, so get ready!
Plan is big, so let's begin.
What are we going to study in this tutorial:
- How to create a gun that has some interesting abilities
- How to create a staff with custom projectile
How to create a gun that has some interesting abilities
Gun is a weapon that consumes ammo and fires projectiles. This would be boring, so we'll add a few more effects:
1. Gun will fire 3 shots in a row, just like the Clockwork Assault Rifle does.
2. Each bullet has a 1/5 chance of being replaced with Silver Bullet.
3. Gun fires 1-3 projectiles at a time.
4. Have a 33% chance to not consume ammo.
For the basic gun we need this code:
A bit harder than a sword, but still boring.
For first, let's fix gun position in hands, cuz now it looks weird.
Now it looks way better!
Also we want to add a chance to not consume ammo, just like Minishark!
But all we did above is just a default generic common bloat suck gun.
That's why I decided to add some shoot modifications.
They are made in Shoot() or in ModifyShootStats(). We'll use Shoot() cuz there you can do some more things, such as the bullet quantity or replacement.
For first let's add Shoot() to our code:
Creating some shoot inaccuracy:
Our gun will be able to shoot 1-3 projectiles a shot. Here we enter the spread in which number of projectiles will vary:
Note: Main.rand.Next does not return the last number, so, for eg Main.rand.Next(1, 4) can return 1, 2 or 3!!!
Finally, creating a loop in which we are going to replace proj type with other with 20% chance and create new projectile(s)
Woah, that works perfectly!
I almost forgot, we also want to make our gun shoot 3 times a row, consuming only one ammo.
To do that, make
Also, you need two more lines of code.
That's all, we made a gun with some interesting effects!
Full code:
How to create a staff with custom projectile
Vanilla has tons of projectiles. But sometimes they are not enough.
So we'll create our own projectile and make custom behaviour for it!
It will be fired from a staff, which is held differently than a gun and uses mana instead of ammo.
For the basic magic weapon we need this code:
To staff be held not like a gun we need this code:
Firstly, let's create one more folder where all our projectiles will be stored:
Then, create .cs and .png files there. I will not create .png file because I will use no texture for projectile (it will be made out of dust).
This is the basic projectile code:
Also I'll use no texture:
As we are using no texture, let's add dust to visualise the projectile.
This must happen every tick, and the projectile has a hook for this called AI():
Don't forget to add
Looks sick!
Also I want to add a little dust explosion on projectile death.
Things that happen when projectile is destroyed have to be in OnKill() hook:
That's all, we made a staff with custom projectile!
Full projectile code:
Ending
Thanks to everyone who read this tutorial! I hope your brain didn't burst from so much new information.
Also, sorry for being slow lazy snail and making no tutorials for 9 months. Hope I will not make next one for 9 months, like this one!
Any questions are allowed! See you on the next tutorial!
Previous Tutorial / Next Tutorial (coming soon!)
Hi everyone! It's been 9 months since the last tutorial because I was too lazy and busy with my projects.
In this tutorial, we'll make weapons for ranger and mage that will be way harder than a sword we did in previous tutorial, so get ready!
Plan is big, so let's begin.
What are we going to study in this tutorial:
- How to create a gun that has some interesting abilities
- How to create a staff with custom projectile
How to create a gun that has some interesting abilities
Gun is a weapon that consumes ammo and fires projectiles. This would be boring, so we'll add a few more effects:
1. Gun will fire 3 shots in a row, just like the Clockwork Assault Rifle does.
2. Each bullet has a 1/5 chance of being replaced with Silver Bullet.
3. Gun fires 1-3 projectiles at a time.
4. Have a 33% chance to not consume ammo.
For the basic gun we need this code:
C#:
using Microsoft.Xna.Framework;
using SteelMod.Content.Items.Materials;
using Terraria;
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.ModLoader;
namespace SteelMod.Content.Items.Weapons.Ranged
{
public class SteelRifle : ModItem
{
public override void SetDefaults()
{
// Visual properties
Item.width = 60;
Item.height = 20;
Item.scale = 1.05f;
Item.useStyle = ItemUseStyleID.Shoot; // Use style for guns
Item.rare = ItemRarityID.Blue;
// Combat properties
Item.damage = 50; // Gun damage + bullet damage = final damage
Item.DamageType = DamageClass.Ranged;
Item.useTime = 15; // Delay between shots.
Item.useAnimation = 15; // How long shoot animation lasts in ticks.
Item.knockBack = 4.5f; // Gun knockback + bullet knockback = final knockback
Item.autoReuse = false;
// Other properties
Item.value = 10000;
Item.UseSound = SoundID.Item11; // Gun use sound
// Gun properties
Item.noMelee = true; // Item not dealing damage while held, we don’t hit mobs in the head with a gun
Item.shoot = ProjectileID.PurificationPowder; // What kind of projectile the gun fires, does not mean anything here because it is replaced by ammo
Item.shootSpeed = 16f; // Speed of a projectile. Mainly measured by eye
Item.useAmmo = AmmoID.Bullet; // What ammo gun uses
}
public override void AddRecipes()
{
CreateRecipe()
.AddIngredient<SteelShard>(9)
.AddTile(TileID.Anvils)
.Register();
}
}
}
For first, let's fix gun position in hands, cuz now it looks weird.
C#:
public override Vector2? HoldoutOffset() => new Vector2(-8f, 0f); // Offset in pixels at which the player will hold the gun. -Y is up
Also we want to add a chance to not consume ammo, just like Minishark!
C#:
public override bool CanConsumeAmmo(Item ammo, Player player) => Main.rand.Next(101) <= 33; // Chance in % to not consume ammo
But all we did above is just a default generic common bloat suck gun.
That's why I decided to add some shoot modifications.
They are made in Shoot() or in ModifyShootStats(). We'll use Shoot() cuz there you can do some more things, such as the bullet quantity or replacement.
For first let's add Shoot() to our code:
C#:
public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, Vector2 position, Vector2 velocity, int type, int damage, float knockback)
{
return true; // return true to allow gun to shoot
}
C#:
velocity = velocity.RotatedByRandom(MathHelper.ToRadians(10));
C#:
int NumProjectiles = Main.rand.Next(1, 4);
Finally, creating a loop in which we are going to replace proj type with other with 20% chance and create new projectile(s)
C#:
for (int i = 0; i < NumProjectiles; i++)
{
// New velocity for new bullets
Vector2 NewVelocity = velocity.RotatedByRandom(MathHelper.ToRadians(10));
// Some random to bullet speed
NewVelocity *= 1f - Main.rand.NextFloat(0.2f);
// Our gun has a 1/5 chance to replace default bullets with silver ones
if (Main.rand.NextBool(5))
{
type = ProjectileID.SilverBullet;
}
// Creating new projectile
Projectile.NewProjectileDirect(
source,
position,
NewVelocity,
type,
damage,
knockback,
player.whoAmI
);
}
I almost forgot, we also want to make our gun shoot 3 times a row, consuming only one ammo.
To do that, make
Item.useTime
3 times lesser than Item.useAnimation
:
C#:
Item.useTime = 10; // Delay between shots.
Item.useAnimation = 30; // How long shoot animation lasts in ticks. We made it 3 times larger than useTime to make gun fire thrice
Also, you need two more lines of code.
C#:
Item.reuseDelay = 25; // How long the gun will be unable to shoot after useAnimation ends
Item.consumeAmmoOnLastShotOnly = true; // Gun will consume only one ammo per a burst of shots
That's all, we made a gun with some interesting effects!
Full code:
C#:
using Microsoft.Xna.Framework;
using SteelMod.Content.Items.Materials;
using Terraria;
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.ModLoader;
namespace SteelMod.Content.Items.Weapons.Ranged
{
public class SteelRifle : ModItem
{
public override void SetDefaults()
{
// Visual properties
Item.width = 60;
Item.height = 20;
Item.scale = 1.05f;
Item.useStyle = ItemUseStyleID.Shoot; // Use style for guns
Item.rare = ItemRarityID.Blue;
// Combat properties
Item.damage = 50; // Gun damage + bullet damage = final damage
Item.DamageType = DamageClass.Ranged;
Item.useTime = 10; // Delay between shots.
Item.useAnimation = 30; // How long shoot animation lasts in ticks. We made it 3 times larger than useTime to make gun fire thrice
Item.reuseDelay = 25; // How long the gun will be unable to shoot after useAnimation ends
Item.consumeAmmoOnLastShotOnly = true; // Gun will consume only one ammo per 3 shots
Item.knockBack = 4.5f; // Gun knockback + bullet knockback = final knockback
Item.autoReuse = false;
// Other properties
Item.value = 10000;
Item.UseSound = SoundID.Item11; // Gun use sound
// Gun properties
Item.noMelee = true; // Item not dealing damage while held, we don’t hit mobs in the head with a gun
Item.shoot = ProjectileID.PurificationPowder; // What kind of projectile the gun fires, does not mean anything here because it is replaced by ammo
Item.shootSpeed = 16f; // Speed of a projectile. Mainly measured by eye
Item.useAmmo = AmmoID.Bullet; // What ammo gun uses
}
public override void AddRecipes()
{
CreateRecipe()
.AddIngredient<SteelShard>(9)
.AddTile(TileID.Anvils)
.Register();
}
public override bool CanConsumeAmmo(Item ammo, Player player) => Main.rand.Next(101) <= 33; // Chance in % to not consume ammo
public override Vector2? HoldoutOffset() => new Vector2(-8f, 0f); // Offset in pixels at which the player will hold the gun. -Y is up
public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, Vector2 position, Vector2 velocity, int type, int damage, float knockback)
{
// Creating some shoot inaccuracy
velocity = velocity.RotatedByRandom(MathHelper.ToRadians(10));
// Our gun will be able to shoot 1-3 projectiles a shot. Here we enter the spread in which number of projectiles will vary
// Remember that Main.rand.Next does not return the last number, so Main.rand.Next(1, 4) can return 1, 2 or 3
int NumProjectiles = Main.rand.Next(1, 4);
for (int i = 0; i < NumProjectiles; i++)
{
// New velocity for new bullets
Vector2 NewVelocity = velocity.RotatedByRandom(MathHelper.ToRadians(10));
// Some random to bullet speed
NewVelocity *= 1f - Main.rand.NextFloat(0.2f);
// Our gun has a 1/5 chance to replace default bullets with silver ones
if (Main.rand.NextBool(5))
{
type = ProjectileID.SilverBullet;
}
// Creating new projectile
Projectile.NewProjectileDirect(
source,
position,
NewVelocity,
type,
damage,
knockback,
player.whoAmI
);
}
return false; // return false to prevent the gun from shooting original projectile as we created them manually above
}
}
}
How to create a staff with custom projectile
Vanilla has tons of projectiles. But sometimes they are not enough.
So we'll create our own projectile and make custom behaviour for it!
It will be fired from a staff, which is held differently than a gun and uses mana instead of ammo.
For the basic magic weapon we need this code:
C#:
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Microsoft.Xna.Framework;
using SteelMod.Content.Items.Materials;
using SteelMod.Content.Projectiles;
namespace SteelMod.Content.Items.Weapons.Magic
{
public class ElectromagneticRod : ModItem
{
public override void SetDefaults()
{
// Helper method to quickly set basic magic weapon properties
Item.DefaultToMagicWeapon(
projType: ModContent.ProjectileType<ElectromagneticBolt>(), // Our own projectile
singleShotTime: 35, // useTime & useAnimation
shotVelocity: 9f,
hasAutoReuse: true
);
Item.damage = 45;
Item.knockBack = 5f;
Item.value = 10000;
Item.rare = ItemRarityID.Blue;
Item.UseSound = SoundID.Item94; // Some electric sound
Item.mana = 10; // This item uses 10 mana
Item.width = Item.height = 40;
}
public override void AddRecipes()
{
CreateRecipe()
.AddIngredient<SteelShard>(8)
.AddTile(TileID.Anvils)
.Register();
}
}
}
To staff be held not like a gun we need this code:
C#:
public override void SetStaticDefaults()
{
Item.staff[Item.type] = true;
}
ModContent.ProjectileType<ElectromagneticBolt>()
gives an error because we don't have any ElectromagneticBolt
in our mod. Let's create one!Firstly, let's create one more folder where all our projectiles will be stored:
Then, create .cs and .png files there. I will not create .png file because I will use no texture for projectile (it will be made out of dust).
This is the basic projectile code:
C#:
using Terraria;
using Terraria.ModLoader;
namespace SteelMod.Content.Projectiles
{
public class ElectromagneticBolt : ModProjectile
{
public override void SetDefaults()
{
Projectile.DamageType = DamageClass.Magic; // Damage class projectile uses
Projectile.scale = 1f; // Projectile scale multiplier
Projectile.penetrate = 3; // How many hits projectile have to make before it dies. 3 means projectile will die on 3rd enemy. Setting this to 0 will make projectile die instantly
Projectile.aiStyle = 0; // AI style of a projectile. 0 is default bullet AI
Projectile.width = Projectile.height = 10; // Hitbox of projectile in pixels
Projectile.friendly = true; // Can hit enemies?
Projectile.hostile = false; // Can hit player?
Projectile.timeLeft = 90; // Time in ticks before projectile dies
Projectile.light = 0.3f; // How much light projectile provides
Projectile.ignoreWater = true; // Does the projectile ignore water (doesn't slow down in it)
Projectile.tileCollide = true; // Does the projectile collide with tiles, like blocks?
Projectile.alpha = 255; // Completely transparent
}
}
}
Also I'll use no texture:
C#:
public override string Texture => "Terraria/Images/Projectile_0"; // We will use no texture
As we are using no texture, let's add dust to visualise the projectile.
This must happen every tick, and the projectile has a hook for this called AI():
C#:
public override void AI() // This hook updates every tick
{
if (Main.netMode != NetmodeID.Server) // Do not spawn dust on server!
{
Dust dust = Dust.NewDustPerfect(
Position: Projectile.Center,
Type: DustID.Electric,
Velocity: Vector2.Zero,
Alpha: 100,
newColor: Color.White,
Scale: 0.9f
);
dust.noGravity = true; // Dust don't have gravity
dust.fadeIn = -1f; // Dust will fade out
}
}
Don't forget to add
using Terraria.ID;
and using Microsoft.Xna.Framework;
Looks sick!
Also I want to add a little dust explosion on projectile death.
Things that happen when projectile is destroyed have to be in OnKill() hook:
C#:
public override void OnKill(int timeLeft) // What happens on projectile death
{
int numDust = 20;
for (int i = 0; i < numDust; i++) // Loop through code below numDust times
{
Vector2 velocity = Vector2.One.RotatedBy(MathHelper.ToRadians(360 / numDust * i)); // Circular velocity
Dust.NewDustPerfect(Projectile.Center, DustID.Electric, velocity).noGravity = true; // Creating dust
}
}
That's all, we made a staff with custom projectile!
Full projectile code:
C#:
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Microsoft.Xna.Framework;
namespace SteelMod.Content.Projectiles
{
public class ElectromagneticBolt : ModProjectile
{
public override string Texture => "Terraria/Images/Projectile_0"; // We will use no texture
public override void SetDefaults()
{
Projectile.DamageType = DamageClass.Magic; // Damage class projectile uses
Projectile.scale = 1f; // Projectile scale multiplier
Projectile.penetrate = 3; // How many hits projectile have to make before it dies. 3 means projectile will die on 3rd enemy. Setting this to 0 will make projectile die instantly
Projectile.aiStyle = 0; // AI style of a projectile. 0 is default bullet AI
Projectile.width = Projectile.height = 10; // Hitbox of projectile in pixels
Projectile.friendly = true; // Can hit enemies?
Projectile.hostile = false; // Can hit player?
Projectile.timeLeft = 90; // Time in ticks before projectile dies
Projectile.light = 0.3f; // How much light projectile provides
Projectile.ignoreWater = true; // Does the projectile ignore water (doesn't slow down in it)
Projectile.tileCollide = true; // Does the projectile collide with tiles, like blocks?
Projectile.alpha = 255; // Completely transparent
}
public override void AI() // This hook updates every tick
{
if (Main.netMode != NetmodeID.Server) // Do not spawn dust on server!
{
Dust dust = Dust.NewDustPerfect(
Position: Projectile.Center,
Type: DustID.Electric,
Velocity: Vector2.Zero,
Alpha: 100,
newColor: Color.White,
Scale: 0.9f
);
dust.noGravity = true; // Dust don't have gravity
dust.fadeIn = -1f;
}
}
public override void OnKill(int timeLeft) // What happens on projectile death
{
int numDust = 20;
for (int i = 0; i < numDust; i++) // Loop through code below numDust times
{
Vector2 velocity = Vector2.One.RotatedBy(MathHelper.ToRadians(360 / numDust * i)); // Circular velocity
Dust.NewDustPerfect(Projectile.Center, DustID.Electric, velocity).noGravity = true; // Creating dust
}
}
}
}
Ending
Thanks to everyone who read this tutorial! I hope your brain didn't burst from so much new information.
Also, sorry for being slow lazy snail and making no tutorials for 9 months. Hope I will not make next one for 9 months, like this one!
Any questions are allowed! See you on the next tutorial!
Previous Tutorial / Next Tutorial (coming soon!)
Last edited: