So, recently I've been trying to spice up my mod with more unique projectile weapons, and I found some nice tricks with existing tutorials, which I will compile here. I also decompiled Terraria because my homing AI wasn't cutting it and I needed Chloro bullet AI as a base, so I'll share the AI I derived from vanilla projectiles too. Read ahead for some tips on how to make a decent projectile in Terraria.
1. Basic Projectiles and Useful Vanilla ThingsFirstly, you may be wondering how to actually make a projectile. Firstly, here's a skeleton for a projectile. (Each Code section is 1 .cs file).
Adding code in, here's what a basic bullet would look like.
So now we have a projectile that, when spawned, moves straight forward until it hits something or has been active for 600 frames. However, you may notice that when it hits a tile, it simply despawns with no noise or particle effects. This is because AI does not do this; the hook Kill does this. We can fix that by adding the following code:
Making our new projectile code look like this:
You can also make it trail particles behind it like so, by spawning them every tick in the AI() hook:
And, to top off what I would consider basic, adding a debuff to the bullet. This is done with the hook OnHitNPC.
(In case you're wondering, to make a weapon shoot a projectile, add the code item.shoot = ___. This can be a number for a vanilla projectile, ProjectileID.___ for a vanilla projectile, or mod.ProjectileType("") for a modded. For the latter, put the ID in the quotation marks. For a gun, you must use 10 as your shoot; for a bow, use 3.)
Speaking of shooting vanilla projectiles, here are some useful vanilla projectiles.
Finally, here's a basic magic weapon that shoots a single projectile.
Section 2: Advanced Projectile AIsAdd these to your AI hook in your projectile to make them do what it says on the label.
Section 3: Weapons that Shoot ProjectilesSo now you need your item to shoot a projectile. As demonstrated in Section 1, you can easily make a magic weapon like a Gem Staff that shoots a single projectile. What about a ranged weapon? To make a weapon ranged, do the following:
- A magic weapon that rains projectiles from the sky
- A magic weapon that fires projectiles in a spread
- A magic weapon that fires more than one projectile
- A magic weapon that shoots a double, triple, quadruple, etc. burst of projectiles in a straight line while only consuming 1 burst of mana
- Any ranged weapon with the above qualities
then I can help!
Firstly, add following the hook to your weapon:
All of the following blocks of code will be put in this hook, between the {} (unless it is stated otherwise).
Section 4: Custom AmmoMaking custom ammo is surprisingly easy, and you can even make your own ammo types!
There are 3 sub-sections:
Using a Modded Item as a Vanilla Ammo Type
To make an ammo, all you really need is item.ammo. However, to make it actually function, you need this code in SetDefaults:
Using a Modded Item as a Modded Ammo Type
First, set your weapon to use the ammo ModdedAmmo or CrossbowBolt or whatever your ammo type is called (i.e. set item.useAmmo to the ID). Next, set item.ammo in your ammo to the same thing. That's it!
Using a Vanilla Item as a Modded Ammo Type
This is a little bit trickier: how do we mod an existing item? The answer is simple: GlobalItem! GlobalItem is a class that overrides every item in the game. You may be confused as to how overriding every item in the game helps, but if you use if(item.type == id), you can make it only apply to items with that ID! Here's GlobalItem, put this in a new cs file in your items folder:
Now you can do whatever you want to vanilla items! If you want to make the Reaver Shark have less pickaxe power, you can put this in SetDefaults:
Replace the id with the item you want to modify, and item.pick to whatever value you want to modify. This can do everything from making copper shortswords one-shot bosses to making musketballs shoot explosive fireballs instead of bullets!
With this, we can make vanilla items do whatever we want, including making them ammo with item.ammo!
If you need anything else that relates to a vanilla projectile's AI, ask me about it. I have the decompiled source code for Terraria, so I can access the exact AI for you. I can also help with most issues of any kind that don't relate to bosses.
Here's a .cs file about creative ways to make a gun shoot things: blushiemagic/tModLoader
Scroll down to see how to get a clockwork assault rifle-type effect, shotgun effect, reduced ammo consumption effect, set spread effect, and chain gun effect.
1. Basic Projectiles and Useful Vanilla Things
Code:
using System; //what sources the code uses, these sources allow for calling of terraria functions, existing system functions and microsoft vector functions (probably more)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Mod.Projectiles //where it's stored, replace Mod with the name of your mod. This file is stored in the folder \Mod Sources\(mod name, folder can't have spaces)\Projectiles.
{
public class ProjectileSkeleton : ModProjectile //the class of the projectile. Change ProjectileSkeleton to whatever you want the projectile name to be.
{
public override void SetDefaults()
{
}
}
}
Code:
using System; //what sources the code uses, these sources allow for calling of terraria functions, existing system functions and microsoft vector functions (probably more)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Mod.Projectiles //where it's stored, replace Mod with the name of your mod. This file is stored in the folder \Mod Sources\(mod name, folder can't have spaces)\Projectiles.
{
public class Bullet : ModProjectile //the class of the projectile
{
public override void SetDefaults()
{
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.
}
}
}
Code:
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
}
Code:
using System; //what sources the code uses, these sources allow for calling of terraria functions, existing system functions and microsoft vector functions (probably more)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Mod.Projectiles //where it's stored. Replace Mod with the name of your mod. This file is stored in the folder \Mod Sources\(mod name, folder can't have spaces)\Projectiles.
{
public class Bullet : ModProjectile //the class of the projectile
{
public override void SetDefaults()
{
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);
Main.PlaySound(SoundID.Item10, projectile.position);
}
}
}
Code:
using System; //what sources the code uses, these sources allow for calling of terraria functions, existing system functions and microsoft vector functions (probably more)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Mod.Projectiles //where it's stored. Replace Mod with the name of your mod. This file is stored in the folder \Mod Sources\(mod name, folder can't have spaces)\Projectiles.
{
public class Bullet : ModProjectile //the class of the projectile
{
public override void SetDefaults()
{
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 AI()
{
Dust.NewDust(projectile.position + projectile.velocity, projectile.width, projectile.height, 15, projectile.velocity.X * -0.5f, projectile.velocity.Y * -0.5f); //spawns dust behind it, this is a spectral light blue dust
}
public override void Kill(int timeLeft)
{
Collision.HitTiles(projectile.position, projectile.velocity, projectile.width, projectile.height);
Main.PlaySound(SoundID.Item10, projectile.position);
}
}
}
Code:
using System; //what sources the code uses, these sources allow for calling of terraria functions, existing system functions and microsoft vector functions (probably more)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Mod.Projectiles //where it's stored. Replace Mod with the name of your mod. This file is stored in the folder \Mod Sources\(mod name, folder can't have spaces)\Projectiles.
{
public class EtherealBullet : ModProjectile //the class of the projectile. Change EtherealBullet to the ID of your projectile. The ID has to match the name of the sprite for that item in your folder and can have no spaces.
{
public override void SetDefaults()
{
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 AI()
{
Dust.NewDust(projectile.position + projectile.velocity, projectile.width, projectile.height, 15, projectile.velocity.X * -0.5f, projectile.velocity.Y * -0.5f); //spawns dust behind it, this is a spectral light blue dust. 15 is the dust, change that to what you want.
}
public override void Kill(int timeLeft)
{
Collision.HitTiles(projectile.position, projectile.velocity, projectile.width, projectile.height);
Main.PlaySound(SoundID.Item10, projectile.position);
}
public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
{
target.AddBuff(mod.BuffType("EtherealFlames"), 180, false); //The debuff inflicted is the modded debuff Ethereal Flames. 180 is the duration in frames: Terraria runs at 60 FPS, so that's 3 seconds (180/60=3). To change the modded debuff, change EtherealFlames to whatever the buff is called; to add a vanilla debuff, change mod.BuffType("EtherealFlames") to a number based on the terraria buff IDs. Some useful ones are 20 for poison, 24 for On Fire!, 39 for Cursed Flames, 69 for Ichor, and 70 for Venom.
}
}
}
Speaking of shooting vanilla projectiles, here are some useful vanilla projectiles.
668: Flameburst Fireball
This is an exploding fireball that inflicts On Fire! and is very useful for a fire weapon.
521: Crystal Serpent
A pink projectile great for magic weapons that explodes into more for massive damage. May be a tad hard to balance.
This is an exploding fireball that inflicts On Fire! and is very useful for a fire weapon.
521: Crystal Serpent
A pink projectile great for magic weapons that explodes into more for massive damage. May be a tad hard to balance.
Finally, here's a basic magic weapon that shoots a single projectile.
Code:
using System;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace Terrxplosion.Items.Weapons.Magic // under Mod Sources\Terrxplosion\Items\Weapons\Magic
{
public class StarryWand : ModItem
{
public override void SetStaticDefaults() //used to set the name (defaults to the ID but with spaces before every capital letter except the first letter of the ID), tooltip and more.
{
Tooltip.SetDefault(""); //tooltip
Item.staff[item.type] = true; //this code makes a gun-style item into a staff-style item
}
public override void SetDefaults()
{
item.damage = 5; //deals 5 damage
item.magic = true; //deals magic damage
item.noMelee = true; //the item sprite itself does no damage
item.width = 26; //26 px wide
item.height = 26; //26 px tall
item.useTime = 18; //shoots a projectile every 18 frames
item.useAnimation = 18; //the item itself is visible for 18 frames (no frame where it's invisible if you use auto-fire) and has a displayed use time of 18
item.useStyle = 5; //animates like a gun (staff because of what we did in SetStaticDefaults)
item.knockBack = 5f; //deals 5 units of knockback
item.value = Item.buyPrice(0, 0, 5, 0); //if you buy it in a shop, it would cost 5 silver, but it would be 1/5 if you sold it, so it has a sell price of 1 silver
item.rare = 0; //white rarity
item.autoReuse = true; //auto-fires
item.shoot = mod.ProjectileType ("Star"); //shoots a modded projectile, in this case Star
item.shootSpeed = 12; //projectile has a velocity of 12
item.mana = 2; //2 mana to use
}
public override void AddRecipes()
{
ModRecipe recipe = new ModRecipe(mod);
recipe.AddIngredient(ItemID.Wood, 10); //crafted with 10 wood
recipe.AddIngredient(75); //crafted with Item 75, Fallen Star
recipe.AddTile(18); //crafted at Tile 18, Workbench
recipe.SetResult(this);
recipe.AddRecipe();
}
}
}
Section 2: Advanced Projectile AIs
Code:
float num132 = (float)Math.Sqrt((double)(projectile.velocity.X * projectile.velocity.X + projectile.velocity.Y * projectile.velocity.Y));
float num133 = projectile.localAI[0];
if (num133 == 0f)
{
projectile.localAI[0] = num132;
num133 = num132;
}
float num134 = projectile.position.X;
float num135 = projectile.position.Y;
float num136 = 300f;
bool flag3 = false;
int num137 = 0;
if (projectile.ai[1] == 0f)
{
for (int num138 = 0; num138 < 200; num138++)
{
if (Main.npc[num138].CanBeChasedBy(this, false) && (projectile.ai[1] == 0f || projectile.ai[1] == (float)(num138 + 1)))
{
float num139 = Main.npc[num138].position.X + (float)(Main.npc[num138].width / 2);
float num140 = Main.npc[num138].position.Y + (float)(Main.npc[num138].height / 2);
float num141 = Math.Abs(projectile.position.X + (float)(projectile.width / 2) - num139) + Math.Abs(projectile.position.Y + (float)(projectile.height / 2) - num140);
if (num141 < num136 && Collision.CanHit(new Vector2(projectile.position.X + (float)(projectile.width / 2), projectile.position.Y + (float)(projectile.height / 2)), 1, 1, Main.npc[num138].position, Main.npc[num138].width, Main.npc[num138].height))
{
num136 = num141;
num134 = num139;
num135 = num140;
flag3 = true;
num137 = num138;
}
}
}
if (flag3)
{
projectile.ai[1] = (float)(num137 + 1);
}
flag3 = false;
}
if (projectile.ai[1] > 0f)
{
int num142 = (int)(projectile.ai[1] - 1f);
if (Main.npc[num142].active && Main.npc[num142].CanBeChasedBy(this, true) && !Main.npc[num142].dontTakeDamage)
{
float num143 = Main.npc[num142].position.X + (float)(Main.npc[num142].width / 2);
float num144 = Main.npc[num142].position.Y + (float)(Main.npc[num142].height / 2);
if (Math.Abs(projectile.position.X + (float)(projectile.width / 2) - num143) + Math.Abs(projectile.position.Y + (float)(projectile.height / 2) - num144) < 1000f)
{
flag3 = true;
num134 = Main.npc[num142].position.X + (float)(Main.npc[num142].width / 2);
num135 = Main.npc[num142].position.Y + (float)(Main.npc[num142].height / 2);
}
}
else
{
projectile.ai[1] = 0f;
}
}
if (!projectile.friendly)
{
flag3 = false;
}
if (flag3)
{
float num145 = num133;
Vector2 vector10 = new Vector2(projectile.position.X + (float)projectile.width * 0.5f, projectile.position.Y + (float)projectile.height * 0.5f);
float num146 = num134 - vector10.X;
float num147 = num135 - vector10.Y;
float num148 = (float)Math.Sqrt((double)(num146 * num146 + num147 * num147));
num148 = num145 / num148;
num146 *= num148;
num147 *= num148;
int num149 = 8;
projectile.velocity.X = (projectile.velocity.X * (float)(num149 - 1) + num146) / (float)num149;
projectile.velocity.Y = (projectile.velocity.Y * (float)(num149 - 1) + num147) / (float)num149;
}
}
Credit to @Sin Costan for this AI.
Code:
for(int i = 0; i < 200; i++)
{
NPC target = Main.npc[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 && !target.friendly && target.active)
{
if(projectile.ai[0] > 10f)
{
distance = 3f / distance;
shootToX *= distance * 5;
shootToY *= distance * 5;
int proj = Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, shootToX, shootToY, mod.ProjectileType("Laser"), projectile.damage, projectile.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);
projectile.ai[0] = -50f;
}
}
}
projectile.ai[0] += 1f;
Code:
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);
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;
Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, vector12.X, vector12.Y, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0f, -1000f);
}
}
}
Section 3: Weapons that Shoot Projectiles
- Change item.magic = true; to item.ranged = true; //so it will do ranged damage
- Remove item.mana = x;
- Add item.useAmmo = x; //replace x with AmmoID.whatever you want from here. If you want it to not consume ammo like the Toxikarp, ignore this. Common ammo types include AmmoID.Arrow, AmmoID.Bullet, and AmmoID.Rocket
- Set item.shoot to:
- 3 for arrow
- 10 for bullet
- 134 for rocket
- Projectile ID of the projectile you want for anything else
- A magic weapon that rains projectiles from the sky
- A magic weapon that fires projectiles in a spread
- A magic weapon that fires more than one projectile
- A magic weapon that shoots a double, triple, quadruple, etc. burst of projectiles in a straight line while only consuming 1 burst of mana
- Any ranged weapon with the above qualities
then I can help!
Firstly, add following the hook to your weapon:
Code:
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)
{
}
Code:
float numberProjectiles = 3; // 3 shots
float rotation = MathHelper.ToRadians(45);//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
Code:
for (int i = 0; i < 3; i++) //replace 3 with however many projectiles you like
{
Vector2 perturbedSpeed = new Vector2(speedX, speedY).RotatedByRandom(MathHelper.ToRadians(12)); //12 is the spread in degrees, although like with Set Spread it's technically a 24 degree spread due to the fact that it's randomly between 12 degrees above and 12 degrees below your cursor.
Projectile.NewProjectile(position.X, position.Y, perturbedSpeed.X, perturbedSpeed.Y, type, damage, knockBack, player.whoAmI); //create the projectile
}
return false;
Code:
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;
Section 4: Custom Ammo
There are 3 sub-sections:
Using a Modded Item as a Vanilla Ammo Type
To make an ammo, all you really need is item.ammo. However, to make it actually function, you need this code in SetDefaults:
Code:
public override void SetDefaults()
{
item.damage = 1; //how much additional damage your ammo does
item.width = 12;
item.height = 12;
item.maxStack = 999; //how much fit in one inventory slot
item.consumable = true; //makes it so the bullet is used on shooting. Delete this if you want an endless ammo pouch
item.knockBack = 1.5f; //how much additional knockback your bullet does.
item.value = 10; //if value is just a number, it's the sell price in copper coins. This is worth 10 copper. Every 100 means it sells for a silver, every 10000 means gold, and every 1000000 means platinum
item.rare = 0;
item.shoot = mod.ProjectileType("WoodenBullet"); //IMPORTANT! Make sure you have a projectile for your ammo and this shoots it
item.shootSpeed = 10f; //how much additional velocity it applies to the projectile
item.ammo = AmmoID.Bullet; //IMPORTANT! This makes the item ammo of the according type. Common ammo types include AmmoID.Arrow, AmmoID.Bullet, and AmmoID.Rocket
}
Using a Modded Item as a Modded Ammo Type
First, set your weapon to use the ammo ModdedAmmo or CrossbowBolt or whatever your ammo type is called (i.e. set item.useAmmo to the ID). Next, set item.ammo in your ammo to the same thing. That's it!
Using a Vanilla Item as a Modded Ammo Type
This is a little bit trickier: how do we mod an existing item? The answer is simple: GlobalItem! GlobalItem is a class that overrides every item in the game. You may be confused as to how overriding every item in the game helps, but if you use if(item.type == id), you can make it only apply to items with that ID! Here's GlobalItem, put this in a new cs file in your items folder:
Code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria.ModLoader.IO;
using Terraria.Utilities;
namespace Terraria.ModLoader
{
public class ModGlobalItem : GlobalItem
{
public override bool InstancePerEntity
{
get
{
return true;
}
}
public override void SetDefaults(Item item)
{
}
}
}
Code:
if (item.type == 2341) //reaver sharks item ID, a list is here: https://terraria.wiki.gg/Item_IDs
{
item.pick = 58;
}
Here's a .cs file about creative ways to make a gun shoot things: blushiemagic/tModLoader
Scroll down to see how to get a clockwork assault rifle-type effect, shotgun effect, reduced ammo consumption effect, set spread effect, and chain gun effect.
Code:
public override void OnHitNPC(NPC target, int damage, float knockback, bool crit)
{
Player p = Main.player[projectile.owner];
int healingAmount = damage/30; //decrease the value 30 to increase heal, increase value to decrease. Or you can just replace damage/x with a set value to heal, instead of making it based on damage.
p.statLife +=healingAmount;
p.HealEffect(healingAmount, true);
}
Last edited: