Item & Projectile Tutorial
Comments227this wiki
|
Under Construction
|
Projectile AI Functionality:
Edit
I'm still working with some of the code to figure out how it applies additonal functions to projectiles. Here I will state the things I have not figured out how to modify yet, or effects that still need to rely on stock item values until an alternative is figured out.
Projectile issues still existing for now
Boomerangs: - Throw limit is enforced through the CanUse() Item method. - Chakram style bouncing still requires a pretendType field in the projectile ini Flails: - Chain color defaults to blue - Unless the flail hits a block it always seems to kill itself upon returning to the player instead of being swung around when the mouse button is held down if it does hit a block it will act properly though... Spears: - Nothing known as of yet. - If anyone finds any issues let me know and show me the source so I can try and figure it out
Making a Bow and Arrow
Edit
- Go to your "Item" folder
- Create a new ini file called "whatever you want"
- Put inside the ini file:
[Stats] autoReuse=True damage=30 height=28 knockBack=8 maxStack=1 noMelee=True ;sets the bow itself to not do damage ranged=True rare=4 scale=1 shootSpeed=15 ;how fast the projectile must travel. type=-1 useAnimation=30 ;how long 1 animation (in click) is. useTime=30 ;how many times it shoots (in this case), /useAnimation value. useSound=1 shoot=1 ;the arrow projectile type. ;;Projectile='custom projectile name' useStyle=5 ;the style for the bow, for it to 'shoot' value=200000 width=14 [Recipe] Items=1 Wood needWater=False Amount=1
- Create a png file for the bow named the same.
Making a Custom Arrow for Bows/Same for Guns
Edit
- Go into your Projectile folder in modpack folder.
- Create an ini file called 'whatever you want'.
- Put this ini code inside of your .ini file:
[Stats] aiStyle=1 ;the ai style of an arrow and for bullets aiPretendType=20 ;for bullets ONLY, will make the projectile fly straight. width=6 height=6 scale=1 type=-1 friendly=True ;so it will act as a friendly weapon and not kill your NPC's ;;set as Hostile=True if you actually want it to kill your NPC's damage=50 hide=false ranged=True timeLeft=600 light=1 tileCollide=True
- Create a .png file with the same name.
- Make sure the item that uses this projectile has its 'projectile' string set to whatever you named this projectile.
Making a Gun
Edit
- 1. Go to your "Item" folder
- 2. Create an ini file named whatever you feel like.
- 3. Put the following code into the .ini file:
- It works pretty much the same like bows
[Stats] width=44 height=14 type=-1 //Stil has to be -1 useStyle=5 // the general gun useStyle useAnimation=43 //how long the full shot cycle takes useTime=43 //how many shots fired during the cycle useTime/useAnimation=how many maxStack=1 damage=23 knockBack=4 autoReuse=True scale=1 useSound=11 rare=1 shoot=10 //change to the projectile you want it to shoot, ONLY FOR NON-CUSTOM PROJECTILES //projectile=POTATO BULLET //use this if your using a custom projectile, and make sure to remove shoot=# shootSpeed=8 //the speed the projectile will travel useAmmo=14 //the non-custom ammo it will use //useAmmoName=POTATO //the custom ammo the gun will use, remove useAmmo noMelee=True //so the gun itself wont do damage value=100000 ranged=True className=Item
Making the Item for the Projectile
Edit
Place this in the Item's .ini and put it into ~ModPack/[Name of Mod]/Item~ Folder
[Stats] width=10 height=14 type=-1 maxStack=250 scale=1.0 value=2500 ammoName=Potato ;wich projectile it will shoot, also needed in the gun/bow's .ini [Recipe] Items=1 Wood needWater=False Amount=25 ;set everything to what you want
- 4. Create a .png file for your gun, name it the same thing.
Adding Dust to a Projectile
Edit
This Example deals with adding a dust to a spear projectile, note that we spawn the dust in the AI() method, although it can be done anywhere else, too.
The primary means of this is to explain how dust spawning a dust work and using it in the projectile we have.
Dust.NewDust(params here), is the a method that will spawn a dust , in a certain box , at a certain variation of velocity , at a certain color , and at a certain size.
Dust.NewDust also returns a number , which is the index of the dust in our array of dusts in the game , so we can tamper with that dust later.
The method itself is:
Dust.NewDust(Vector2 ARG1, int ARG2, int ARG3, int ARG4, float ARG5, float ARG6, int ARG7, Color ARG8, float ARG9);
- ARG1 is a Vector2 ,which is the top left corner of the box in which your dust spawns
- ARG2 is an int, which is the width of your box , the width goes towards the right corner of the box, so the right corner's X is at ARG1.X + ARG2, in terms of values.
- ARG3 is an int, which is the height of your box , the height goes towards the bottom of of the box , so the bottom corner's Y is at ARG1.Y + ARG3, in terms of values.
- ARG4 is an int, which is the Dust's Type, see the List of Dusts.
- ARG5 is a float, which is the the dust's X speed, negative values go left, positive values go right.
- ARG6 is a float, which is the dust's Y speed, negative values go up, positive values go down.
- ARG7 is an int, which is the dust's alpha, the higher it is the more visible a dust is(or is it less visible.....) , at 0 its transparent, its usually best to set it to 150. (this value ranges from 0 to 255).
- ARG8 is a color, you will usually want to leave it as 'default(Color)', but if you have the understanding of tampering with it, it can be of great fun.
- ARG9 is a float, which is the dust's size, for example 5f would mean the dust is 5 times the size of its usual self.
Now the example, the first part regards the spear ai, the second part regards the dusts we make.
Gae Bolg Infernal.cs
public void AI()
{
projectile.direction = Main.player[projectile.owner].direction;
Main.player[projectile.owner].heldProj = projectile.whoAmI;
Main.player[projectile.owner].itemTime = Main.player[projectile.owner].itemAnimation;
projectile.position.X = Main.player[projectile.owner].position.X + (float)(Main.player[projectile.owner].width / 2) - (float)(projectile.width / 2);
projectile.position.Y = Main.player[projectile.owner].position.Y + (float)(Main.player[projectile.owner].height / 2) - (float)(projectile.height / 2);
if (projectile.ai[0] == 0f)
{
projectile.ai[0] = 3f;
projectile.netUpdate = true;
}
if (Main.player[projectile.owner].itemAnimation < Main.player[projectile.owner].itemAnimationMax / 3)
{
projectile.ai[0] -= 2.4f;
}
else
{
projectile.ai[0] += 2.1f;
}
projectile.position += projectile.velocity * projectile.ai[0];
if (Main.player[projectile.owner].itemAnimation == 0) // Has the projectile run its animation and returned to the player? If so kill it then...
{
projectile.Kill();
}
projectile.rotation = (float)Math.Atan2((double)projectile.velocity.Y, (double)projectile.velocity.X) + 2.355f;
if (projectile.spriteDirection == -1)
{
projectile.rotation -= 1.57f;
}
//until this point , all we did was writing a spear's ai.
Vector2 DustPos = projectile.position;
int DustWidth = projectile.width;
int DustHeight = projectile.height;
int DustType = 74; // this controls a dust type
float DustSpeedX = 0f;
float DustSpeedY = 0f;
int DustAlpha = 150;
float DustSize = 1.4f;
int DustIndex = 0; //we will be using it for our second dust
//this is where we spawn our first dust , on a random chance
if (Main.rand.Next(5) == 0) //20% chance to spawn the dust
{
Dust.NewDust(DustPos, DustWidth, DustHeight, DustType, DustSpeedX, DustSpeedY, DustAlpha, default(Color), DustSize);
}
//our second dust
DustIndex = Dust.NewDust(DustPos, DustWidth, DustHeight, DustType, DustSpeedX, DustSpeedY, DustAlpha, default(Color), DustSize);
//we're pointing to our dust , and changing it as we see fit.
Dust DustRef = Main.dust[DustIndex];
DustRef.noGravity = true;
DustRef.velocity /= 5f; //divide its velocity by 5
//now for the third dust we change our dust a bit , so it gets a little of its spawner projectile's speed.
DustSpeedX = projectile.velocity.X * 0.2f + (float)(projectile.direction * 3);
DustSpeedY = projectile.velocity.Y * 0.2f;
DustAlpha = 100;
DustSize = 1.2f;
DustIndex = Dust.NewDust(DustPos, DustWidth, DustHeight, DustType, DustSpeedX, DustSpeedY, DustAlpha, default(Color), DustSize);
Dust DustRef = Main.dust[DustIndex];
DustRef.noGravity = true;
DustRef.velocity /= 2f; //divide its velocity by a half
}
For a Screenshot of this particular spear in action from me click here.
Making a Boomerang
Edit
For this example, I'll use a boomerang called Hellfire Chakram I created in my modpack. I will show ini and pictures to help with understanding how they should look. I will also show how to have the boomerang inflict poison and fire debuffs to an NPC upon contact.
You'll need an Inventory & Projectile picture. Unless you're doing some sort of special sprite, there is no need for rotation or resizing.

After you're done with the pictures and have them placed in both the Item and Projectile folders, it's time for the ini files.
For the Item Folder in your modpack
Hellfire Chakram.ini
[Stats] autoReuse=True damage=30 height=28 knockBack=8 maxStack=1 noMelee=True ;the projectile is what has a hitbox and not the item noUseGraphic=True ;the inventory item should not show while throwing melee=True ;boomerangs now do melee damage as of latest update but you can set it to ranged if you prefer that. rare=4 scale=1 shootSpeed=15 type=-1 useAnimation=15 ;the animation for the boomerang useSound=1 projectile=Hellfire Chakram useStyle=1 ;the style for the boomerang makes a throw animation useTime=15 value=200000 width=14 [Recipe] Items=1 Thorn Chakram,1 Flamarang Tiles=Demon Altar needWater=False Amount=1
For the Projectile folder in your modpack:
Hellfire Chakram.ini
[Stats] aiStyle=3 ;A boomerang projectile's AI as found on the projectile AI page friendly=True pretendType=33 ;makes the boomerang bounce off things like the Thorn Chakram, also gives it the same particle effects and the poison effect too killPretendType=33 ;refer to the aiPretendType Article for more information on this ;(means that it blows up tiles) height=34 light=1 melee=True ;this should match what is in the Hellfire Chakram's item folder ini scale=1 tileCollide=True penetrate=-1 ;I believe this stopped the boomerang from disappearing on contact with npcs so now it will bounce off like one does normally type=-1 width=34
Now comes the C# code for those of you who are a little more advanced. My code is updated to be used with the latest version of tConfig and to be used via a code.dll as Surfpup states with the newest handling of .cs files. Putting this in a .cs file and into your modpack just as is will probably give an error of some sort when you run the modpack builder. I have removed the outdated method as it is obsolete. You will need to make your modpack's c# files into a code.dll following Surf's instructions in the 0.16.9 version of the changelog.
Hellfire Chakram.cs (Visual Studio Code.dll style)
public void DamageNPC(NPC npc, ref int damage, ref float knockback)
{
if (Main.rand.Next(2) == 1)//33% chance to occur
{
npc.AddBuff(24, 360, false); //Light 'em on fire!
npc.AddBuff(20, 360, false); //Poison 'em too!
//24 is for onFire buff, 20 is for poisoned buff, look at the list of buffs for more information. to add your own buff, add npc.addBuff("your buff here", 360, false);
}
}
public void DealtPVP(Player enemyPlayer, ref int damage, ref float knockback) {
if (Main.rand.Next(2) == 1)
{
npc.AddBuff(24, 360, false);
npc.AddBuff(20, 360, false);
}
}
//same as for the DealtNPC, only for in a PvP battle.
Method for limiting the number of projectiles you can throw:
public bool CanUse(Player player, int pID) {
bool use=true;
//This code is used by boomerangs to limit the amount of boomerang projectiles that can be thrown.
for (int m = 0; m < 1000; m++)
{
if (Main.projectile[m].active && Main.projectile[m].owner == Main.myPlayer && Main.projectile[m].type == item.shoot)
{
use = false;
break;
}
}
return use;
}
Making a Flail
Edit
For this example, I'll use a flail I created in my own modpack along with the ini files and pictures of it.
You'll need an Inventory & Projectile picture as usual.


Example 2: Projectile Version of the Meteor Masher
Note: This will always be what is on the end of your flail, so find or make a picture of ONLY what will be at the end of the chain and not anything else with it.
After you're satisfied with the icon and projectile pictures and put them in their proper places; it's time to make the ini files.
For the Item Folder in your modpack
Meteor Masher.ini
[Stats] width=30 height=10 type=-1 pretendType=163 ;Just to make sure it'll pretend to be a flail for any inventory purposes. May not be needed though. useStyle=5 ;A flail's useStyle channel=True ;this is used for keeping the flail active while you hold down the mouse button like you would with any flail useAnimation=45 prefixType=368 useTime=45 maxStack=1 damage=75 knockBack=100 scale=1.5 useSound=1 rare=4 shootSpeed=15 projectile=Meteor Masher Ball noUseGraphic=True ;Once again we don't want the inventory item's graphic displaying while we swing noMelee=True ;The inventory item's sprite should not be doing the damage as it's done via a projectile just like a lance or boomerang value=27000 melee=True [Recipe] Items=99 Demonite Bar,99 Meteorite Bar,99 Shadow Scale,50 Diamond,250 Spike Tiles=Anvil needWater=False Amount=1
For the Projectile Folder in your modpack
Meteor Masher Ball.ini
[Stats] aiStyle=15 ;the AI style of a flail aiPretendType=63 width=42 height=42 scale=1 type=-1 prefixType=368 penetrate=-1 ;Once again we want it to bounce around and off things not just disappear upon hitting anything. timeLeft=3600 ;the time left that the flail's projectile will be held till it disappears until fired again friendly=True tileCollide=True melee=True
To make the flail have a custom chain, add this in the Player.cs file inside your mod's Global folder, replacing "Meteor Masher" with whatever your file's names are(and make sure you have a .png file in the Gore folder for both the Blue Moon Chain and the custom flail chain):
This is the file for the Blue Moon Chain.
Player.cs
public void UpdatePlayer(Player P)
{
if (P.inventory[P.selectedItem].type == Config.itemDefs.byName["Meteor Masher"].type)
{
Main.chain3Texture = Main.goreTexture[Config.goreID["Meteor Masher Chain"]];
}
if (P.inventory[P.selectedItem].type != Config.itemDefs.byName["Meteor Masher"].type)
{
Main.chain3Texture = Main.goreTexture[Config.goreID["Blue Moon Chain"]];
}
}
Making a Spear
Edit
For this example, I'll use a spear that I created in my own modpack along with the ini files and pictures of it.
As with the boomerang and flail items you'll need an Inventory & Projectile picture.


Note: An easy way to make a spear projectile is by extending the handle on your spear for the inventory picture and then rotating the icon to look like Example 2 or if you prefer, rotate it first and then extend the handle.
Note: Make sure you put an Example 2 style picture in the projectile folder and not an Example 1 style picture.
After you're satisfied with the icon and projectile pictures, it's time to make the ini files.
For the Item Folder in your modpack:
Sacrificial Spear.ini
[Stats] damage=50 height=40 knockBack=4 maxStack=1 melee=True noMelee=True ;A spear handles its hitbox from a projectile and not the item itself. noUseGraphic=True ;Hides the inventory item from being displayed instead of the spear's projectile. If false you'll end up with a weird looking spear attack. rare=3 scale=1.3 shoot=46 ;I still oddly had to add this line to get any projectile custom or not to show up for me it may have been fixed now though so you might be able to omit this line shootSpeed=7 ;How far and fast the spear will extend from the player. Really high values can cause the spear to end up leaving your hands when you attack. projectile=Sacrificial Spear ;the spear's projectile type=-1 prefixType=368 toolTip=Demands sacrifices useAnimation=25 useSound=1 useStyle=5 useTime=15 value=2518000 width=40 [Recipe] Items=50 Demonite Bar,50 Shadow Scale,50 Bone Tiles=Anvil Amount=1 needWater=False
For the Projectile folder in your modpack:
Sacrificial Spear.ini:
[Stats] aiStyle=19 ;Found on the projectile page on the wiki this is the value for a spear style AI friendly=True height=22 hide=True ;Was not entirely sure what this was used for but I've made 3+ spears so far, all of which work perfectly so I keep this in there. Figure hide would hide the projectile but maybe it refers to the item which it originates from... melee=True ;Spears do melee damage, so let's assign this projectile melee type damage here scale=1.0 ;this is where you'd edit the size of the spear for the attack. timeLeft=3600 type=-1 width=22 pretendType=47 ;one of the spear projectile AI's in the stock game useTime=12 tileCollide=false ;Spears obviously don't stop upon hitting walls so they shouldn't collide with tiles penetrate=6 ;This causes wall penetration for a spear allowing it to hit any mobs through walls (change it to whatever you want though not sure what every value will do however, so mess around a little and see what happens).
Making Objects Retrievable
Edit
(credit goes to Yoraiz0r for this) (and now actually editted by Yoraiz0r)
To make an arrow or throwing weapon retrievable after use, simply add the following code to the projectile.
Example shown for "Steel Arrow.cs":
public void Kill()
{
if (!projectile.active)
{
return;
}
projectile.timeLeft = 0;
projectile.active = false;
//those were not important
Main.PlaySound(0, (int)projectile.position.X, (int)projectile.position.Y, 1); //adding sounds
for (int i = 0; i < 10; i++) //adding visuals
{
Dust.NewDust(projectile.position, projectile.width, projectile.height, 7, 0, 0, 0, default(Color), 1f);
}
//up to now we were adding visuals , sound and making sure the projectile is dead
//here , we check that the projectile is indeed ours (important for multiplayer only) and giving it a random chance , of 1 out of 3 , to drop its item.
if (projectile.owner == Main.myPlayer && Main.rand.Next(3) == 0)
{
Item.NewItem(
(int)projectile.position.X,
(int)projectile.position.Y,
projectile.width,
projectile.height,
Config.itemDefs.byName["Steel Arrow"].type,
1,
false,
0);
}
}
This code , does the following.
1 - make sure the projectile is indeed 'dead' and not just off the screen 'dead'.
2 - add a sound for when it dies , for realism
3 - adding dust , so that the death will look proper.
4 - actually trying to spawn an item , with a chance of 1 in 3.
.
You could replace "Steel Arrow" with whatever you named your item for projectile listed , and feel free to cut out the other parts.
Adding Effects on Projectile Death
Edit
So you want your projectile to explode when it dies? Maybe you want it to spew dust, or make another projectile? Well, here's how.
Simply open your projectile's class file (.cs) and add the following:
public void PreKill() {
//Stuff you want to happen when your projectile dies.
}
Now I'll go through an example; I wanted to make a bullet that exploded on impact, it proved way harder to figure out than I thought, but here's my method:
public void PreKill() {
Projectile.NewProjectile(projectile.position.X,projectile.position.Y,0,0,112,100,0,projectile.whoAmI); //this creates a new projectile at the position of the dead one. It's also a stupidly fun method in general.
}
Before you can run off and starting making bullets that shit Dynamite, here's what you need to know about Projectile.NewProjectile.
Projectile.NewProjectile(float[X coordinate], //Where on the X axis to spawn float[Y coordinate], // Where on the Y axis to spawn float[X velocity], // How fast to move on X axis float[Y velocity], // How fast to move on Y axis int[Projectile ID], // The projectile you're spawning (this is the tricky part) int[Damage], // Damage dealt (Completely ignores any damage defined elsewhere) float[Knockback], // How far to knockback those hit int[owner ID]) // This number messes with shit in ways I don't properly understand, so just leave it as projectile.whoAmI
So about the projectile ID, it will spawn the projectile whose number corresponds with this list. You'll notice that the number I used was 112, which isn't on that list. This is because in order for your explosion to work the way you want it to, you need to make a new projectile, here's mine, with the important stuff commented:
[Stats] width=60 //Width of explosion height=60 //Height of explosion damage=1 //Irrelevant unless you're using this projectile elsewhere type=-1 alpha=0 hide=True //don't draw the sprite on screen aiStyle=-1 timeLeft=20 //How long the explosion lasts in frames (60 frames = 1 second) friendly=True penetrate=999 ignoreWater=True tileCollide=False ranged=True
As for making an explosion animation happen:
killPretendType=30 //Add this to your exploding projectile's .ini, it makes it run the grenade's Kill() method.
If you change that ID to the bomb's or dynamite's it will also destroy tiles, I don't know how to change the destruction radius though.
You can make your projectile spawn anything you want, even itself (this messes up the game pretty fast though.), you could also add dust, or make it spawn NPCs, literally anything you want from the game.
Other Methods available Pertaining to Items/Projectiles
Edit
Several methods have already been mentioned in this section for extending the capabilities of what can be done with items and projectiles, such as Kill, UpdatePlayer, and DealtNPC. A full list of these methods is at TConfig Classes, with Item-specific methods at Item Methods.
I wanted to call attention to the PreShoot method which is called before the projectile is shot, and can be used for things such as making multiple shots come out.