What are Terraria mods?
The most common Terraria mods are initiated by a program called "Tconfig" which comes with it's own modded client for both Normal and Online game play for modded games. The most basic files you need are a ".ini" file for scripting, a ".cs" file for the detailes of your modded object, and a ".png" file for the sprites.
An example of an npc from the Omnir's npc mod would be the Bomb from final fantasy.
Here is what the typical .ini format should look like.
[SPOILER="Spoiler"]
[Stats][/SPOILER]
npcSlots=1
frameCount=4
animationType=-1
width=38
height=40
type=-1
aiStyle=10
damage=60
defense=50
soundHit=1
soundKilled=6
lifeMax=30
scale=1
knockBackResist=0.8
noGravity=True
value=6000
[Buff Immunities]
Poisoned=True
On Fire!=True
[Drops]
1 Edgar Top=3
1 Edgar Hair Style=3
1 Edgar Bottoms=3
1 Sabin Top=3
1 Sabin Hair Style=3
1 Sabin Bottoms=3
1 Cyan Top=3
1 Cyan Hair Style=3
1 Cyan Bottoms=3
The statistics for the mob are listed in the quote above, as well as the drop table and the chance to obtain the items (which is 3% per item.)
the script for the Bomb in the .cs file should look like this:
[code]float customAi1;
#region Spawn
public static bool SpawnNPC(int x, int y, int playerID)
{
if (Main.player[playerID].townNPCs <= 0f && !Main.player[playerID].zoneDungeon && !Main.player[playerID].zoneJungle && !Main.player[playerID].zoneMeteor)
{
if (Main.player[playerID].position.X > ((Main.worldSurface * 45.0)) && Main.player[playerID].position.X < ((Main.worldSurface * 65.0)) && Main.rand.Next(90)==1) return true;
else if (Main.player[playerID].position.X > ((Main.worldSurface * 135.0)) && Main.player[playerID].position.X < ((Main.worldSurface * 160.0)) && Main.rand.Next(90)==1) return true;
else if (Main.player[playerID].position.Y > ((Main.rockLayer * 16.0)) && Main.player[playerID].position.X > ((Main.rockLayer * 30.0)) && Main.player[playerID].position.X < ((Main.rockLayer * 160.0)) && Main.rand.Next(120)==1) return true;
return false;
}
return false;
}
#endregion
#region Frames
public void FindFrame(int currentFrame)
{
int num = 1;
if (!Main.dedServ)
{
num = Main.npcTexture[npc.type].Height / Main.npcFrameCount[npc.type];
}
if (npc.velocity.X < 0)
{
npc.spriteDirection = -1;
}
else
{
npc.spriteDirection = 1;
}
npc.rotation = npc.velocity.X * 0.08f;
npc.frameCounter += 1.0;
if (npc.frameCounter >= 6.0)
{
npc.frame.Y = npc.frame.Y + num;
npc.frameCounter = 0.0;
}
if (npc.frame.Y >= num * Main.npcFrameCount[npc.type])
{
npc.frame.Y = 0;
}
if (npc.ai[3] == 0)
{
npc.alpha = 0;
}
else
{
npc.alpha = 200;
}
}
#endregion
#region AI
public void AI()
{
bool flag25 = false;
customAi1 += (Main.rand.Next(2, 5) * 0.1f) * npc.scale;
if (customAi1 >= 10f)
{
npc.TargetClosest(true);
if (Collision.CanHit(npc.position, npc.width, npc.height, Main.player[npc.target].position, Main.player[npc.target].width, Main.player[npc.target].height))
{
if ((npc.life <= 25) && (npc.life >= 18))
{
npc.scale = 1.2f;
npc.netUpdate=true;
}
if ((npc.life <= 17) && (npc.life >= 11))
{
npc.scale = 1.5f;
npc.netUpdate=true;
}
if (npc.life <= 10)
{
float num48 = 8f;
Vector2 vector8 = new Vector2(npc.position.X + (npc.width * 0.5f), npc.position.Y + (npc.height / 2));
float speedX = ((Main.player[npc.target].position.X + (Main.player[npc.target].width * 0.5f)) - vector8.X) + Main.rand.Next(-20, 0x15);
float speedY = ((Main.player[npc.target].position.Y + (Main.player[npc.target].height * 0.5f)) - vector8.Y) + Main.rand.Next(-20, 0x15);
float num51 = (float) Math.Sqrt((double) ((speedX * speedX) + (speedY * speedY)));
num51 = num48 / num51;
speedX *= num51;
speedY *= num51;
int damage = 10;
int type = Config.projectileID["Enemy Spell Great Fireball Ball"];//44;//0x37; //14;
int num54 = Projectile.NewProjectile(vector8.X, vector8.Y, speedX, speedY, type, damage, 0f, Main.myPlayer);
Main.projectile[num54].timeLeft = 0;
Main.projectile[num54].aiStyle=9;
Main.PlaySound(2, (int) npc.position.X, (int) npc.position.Y, 14);
customAi1 = 1f;
npc.life = 0;
npc.netUpdate=true;
}
}
}
if (npc.justHit)
{
npc.ai[2] = 0f;
customAi1 = 1f;
}
if (npc.ai[2] >= 0f)
{
int num258 = 16;
bool flag26 = false;
bool flag27 = false;
if (npc.position.X > npc.ai[0] - (float)num258 && npc.position.X < npc.ai[0] + (float)num258)
{
flag26 = true;
}
else
{
if ((npc.velocity.X < 0f && npc.direction > 0) || (npc.velocity.X > 0f && npc.direction < 0))
{
flag26 = true;
}
}
num258 += 24;
if (npc.position.Y > npc.ai[1] - (float)num258 && npc.position.Y < npc.ai[1] + (float)num258)
{
flag27 = true;
}
if (flag26 && flag27)
{
npc.ai[2] += 1f;
if (npc.ai[2] >= 30f && num258 == 16)
{
flag25 = true;
}
if (npc.ai[2] >= 60f)
{
npc.ai[2] = -200f;
npc.direction *= -1;
npc.velocity.X = npc.velocity.X * -1f;
npc.collideX = false;
}
}
else
{
npc.ai[0] = npc.position.X;
npc.ai[1] = npc.position.Y;
npc.ai[2] = 0f;
}
npc.TargetClosest(true);
}
else
{
npc.ai[2] += 1f;
if (Main.player[npc.target].position.X + (float)(Main.player[npc.target].width / 2) > npc.position.X + (float)(npc.width / 2))
{
npc.direction = -1;
}
else
{
npc.direction = 1;
}
}
int num259 = (int)((npc.position.X + (float)(npc.width / 2)) / 16f) + npc.direction * 2;
int num260 = (int)((npc.position.Y + (float)npc.height) / 16f);
bool flag28 = true;
bool flag29 = false;
int num261 = 3;
for (int num269 = num260; num269 < num260 + num261; num269++)
{
if (Main.tile[num259, num269] == null)
{
Main.tile[num259, num269] = new Tile();
}
if ((Main.tile[num259, num269].active && Main.tileSolid[(int)Main.tile[num259, num269].type]) || Main.tile[num259, num269].liquid > 0)
{
if (num269 <= num260 + 1)
{
flag29 = true;
}
flag28 = false;
break;
}
}
if (flag25)
{
flag29 = false;
flag28 = true;
}
if (flag28)
{
npc.velocity.Y = npc.velocity.Y + 0.1f;
if (npc.velocity.Y > 3f)
{
npc.velocity.Y = 3f;
}
}
else
{
if (npc.directionY < 0 && npc.velocity.Y > 0f)
{
npc.velocity.Y = npc.velocity.Y - 0.1f;
}
if (npc.velocity.Y < -4f)
{
npc.velocity.Y = -4f;
}
}
if (npc.collideX)
{
npc.velocity.X = npc.oldVelocity.X * -0.4f;
if (npc.direction == -1 && npc.velocity.X > 0f && npc.velocity.X < 1f)
{
npc.velocity.X = 1f;
}
if (npc.direction == 1 && npc.velocity.X < 0f && npc.velocity.X > -1f)
{
npc.velocity.X = -1f;
}
}
if (npc.collideY)
{
npc.velocity.Y = npc.oldVelocity.Y * -0.25f;
if (npc.velocity.Y > 0f && npc.velocity.Y < 1f)
{
npc.velocity.Y = 1f;
}
if (npc.velocity.Y < 0f && npc.velocity.Y > -1f)
{
npc.velocity.Y = -1f;
}
}
float num270 = 2f;
if (npc.direction == -1 && npc.velocity.X > -num270)
{
npc.velocity.X = npc.velocity.X - 0.1f;
if (npc.velocity.X > num270)
{
npc.velocity.X = npc.velocity.X - 0.1f;
}
else
{
if (npc.velocity.X > 0f)
{
npc.velocity.X = npc.velocity.X + 0.05f;
}
}
if (npc.velocity.X < -num270)
{
npc.velocity.X = -num270;
}
}
else
{
if (npc.direction == 1 && npc.velocity.X < num270)
{
npc.velocity.X = npc.velocity.X + 0.1f;
if (npc.velocity.X < -num270)
{
npc.velocity.X = npc.velocity.X + 0.1f;
}
else
{
if (npc.velocity.X < 0f)
{
npc.velocity.X = npc.velocity.X - 0.05f;
}
}
if (npc.velocity.X > num270)
{
npc.velocity.X = num270;
}
}
}
if (npc.directionY == -1 && (double)npc.velocity.Y > -1.5)
{
npc.velocity.Y = npc.velocity.Y - 0.04f;
if ((double)npc.velocity.Y > 1.5)
{
npc.velocity.Y = npc.velocity.Y - 0.05f;
}
else
{
if (npc.velocity.Y > 0f)
{
npc.velocity.Y = npc.velocity.Y + 0.03f;
}
}
if ((double)npc.velocity.Y < -1.5)
{
npc.velocity.Y = -1.5f;
}
}
else
{
if (npc.directionY == 1 && (double)npc.velocity.Y < 1.5)
{
npc.velocity.Y = npc.velocity.Y + 0.04f;
if ((double)npc.velocity.Y < -1.5)
{
npc.velocity.Y = npc.velocity.Y + 0.05f;
}
else
{
if (npc.velocity.Y < 0f)
{
npc.velocity.Y = npc.velocity.Y - 0.03f;
}
}
if ((double)npc.velocity.Y > 1.5)
{
npc.velocity.Y = 1.5f;
}
}
}
Lighting.addLight((int)npc.position.X / 16, (int)npc.position.Y / 16, 0.4f, 0f, 0.25f);
return;
}
#endregion[/code]
It may look complex, however I find it makes great practice to tinker with the script of these mods if you're just starting to get into coding. This script enables the bomb to behave as it's own ai, and will explode if you lower it's Hp low enough or get too close to it. The bomb will even grow in size as it's hp drops and become faster to! Also don't feel too intimidated, you don't need to learn coding to make mobs, you just have to copy/paste the spawning script from other mobs in the mods you download (if you decide to create any). The Tconfig-wiki tuitorial pages also have a list of pre-made vanilla Ai's which you can use as well in whatever you make (such as the snowman ai or the skeleton ai)
and here are the sprites in png format:
[Image: http://i.imgur.com/VewhWUV.png]
It's advised to use paint.net to edit Terraria sprites, as a clear canvas is needed.
Some things you need to know before downloading Terraria mods:
1) Anti-virus scans don't like tconfig mods very much, the mod installers which insert the mods into the game provided via comand promt will always read as a pieces of malware, which they are not since they just insert whatever is in the mod folders into the game's modded client.
2) You need the T-config client to run anything, if you want to play the vanilla game, use the vanilla launcher that's on the T-config UI before launching.
3) it adds a shit ton of content to the previous vanilla game, some mods such as Omnir's creatures, obsidian's mod, and Zoogle's necro and binding of Isaac mods make the game brutal in difficulty. Some mobs are even capable of blowing stuff up, and on red moons demons will spawn and destroy your stuff. (you've been warned! >w<)
http://www.terrariaonline.com/forums/client-server-mods-tools.51/ - link to the modding page on the terraria forums.