Standalone [1.3] tModLoader - A Modding API

I made a little code that makes the armor piece log all the texture names in Main.playerDrawData. What I've noticed is that my custom armor's texture is not showing up; instead, the texture name is null. In contrast, vanilla armor and accessories have an associated texture name in Main.playerDrawData.texture.Name.
Piece of the log which shows what I mean:
Code:
Hey man! Texture name of this object is: Images/Acc_HandsOn_12
Hey man! Texture name of this object is: Images/Wings_26
Hey man! Texture name of this object is: Images/Player_4_3
Hey man! Texture name of this object is: Images/Player_4_10
Hey man! Texture name of this object is: Images/Armor_Legs_6
Hey man! Texture name of this object is: Images/Acc_Shoes_9
Hey man! Texture name of this object is:
Hey man! Texture name of this object is: Images/Acc_HandsOff_7
Hey man! Texture name of this object is: Images/Acc_Neck_3
Hey man! Texture name of this object is: Images/Player_0_0
Hey man! Texture name of this object is: Images/Player_0_1
Hey man! Texture name of this object is: Images/Player_0_2
Hey man! Texture name of this object is: Images/Armor_Head_4
Hey man! Texture name of this object is: Images/Acc_Shield_4
Hey man! Texture name of this object is:
See those two blank spots? That's where my armor piece is likely *supposed* to be (arms texture and body texture), but it isn't. Somehow, it's still being rendered on the player, though.
The big issue with this is that because the texture name isn't where it's supposed to be, you're effectively unable to do any complicated screwing around with how that layer is drawn.

This same issue occurs when equipping armor and accessories from other mods as well.
 
Last edited:
I made a little code that makes the armor piece log all the texture names in Main.playerDrawData. What I've noticed is that my custom armor's texture is not showing up; instead, the texture name is null. In contrast, vanilla armor and accessories have an associated texture name in Main.playerDrawData.texture.Name.
Piece of the log which shows what I mean:
Code:
Hey man! Texture name of this object is: Images/Acc_HandsOn_12
Hey man! Texture name of this object is: Images/Wings_26
Hey man! Texture name of this object is: Images/Player_4_3
Hey man! Texture name of this object is: Images/Player_4_10
Hey man! Texture name of this object is: Images/Armor_Legs_6
Hey man! Texture name of this object is: Images/Acc_Shoes_9
Hey man! Texture name of this object is:
Hey man! Texture name of this object is: Images/Acc_HandsOff_7
Hey man! Texture name of this object is: Images/Acc_Neck_3
Hey man! Texture name of this object is: Images/Player_0_0
Hey man! Texture name of this object is: Images/Player_0_1
Hey man! Texture name of this object is: Images/Player_0_2
Hey man! Texture name of this object is: Images/Armor_Head_4
Hey man! Texture name of this object is: Images/Acc_Shield_4
Hey man! Texture name of this object is:
See those two blank spots? That's where my armor piece is likely *supposed* to be (arms texture and body texture), but it isn't. Somehow, it's still being rendered on the player, though.
The big issue with this is that because the texture name isn't where it's supposed to be, you're effectively unable to do any complicated screwing around with how that layer is drawn.

This same issue occurs when equipping armor and accessories from other mods as well.
Hmm, that's strange, since I can see how modded texture names should show up.
Could you try taking a different route? Try debugging:
Code:
Main.itemTexture[player.head].Name
Or something like that. I'm not entirely sure if the playerDrawData is to blame, but it can't hurt to try... Right?
 
I made a little code that makes the armor piece log all the texture names in Main.playerDrawData. What I've noticed is that my custom armor's texture is not showing up; instead, the texture name is null. In contrast, vanilla armor and accessories have an associated texture name in Main.playerDrawData.texture.Name.
Piece of the log which shows what I mean:
Code:
Hey man! Texture name of this object is: Images/Acc_HandsOn_12
Hey man! Texture name of this object is: Images/Wings_26
Hey man! Texture name of this object is: Images/Player_4_3
Hey man! Texture name of this object is: Images/Player_4_10
Hey man! Texture name of this object is: Images/Armor_Legs_6
Hey man! Texture name of this object is: Images/Acc_Shoes_9
Hey man! Texture name of this object is:
Hey man! Texture name of this object is: Images/Acc_HandsOff_7
Hey man! Texture name of this object is: Images/Acc_Neck_3
Hey man! Texture name of this object is: Images/Player_0_0
Hey man! Texture name of this object is: Images/Player_0_1
Hey man! Texture name of this object is: Images/Player_0_2
Hey man! Texture name of this object is: Images/Armor_Head_4
Hey man! Texture name of this object is: Images/Acc_Shield_4
Hey man! Texture name of this object is:
See those two blank spots? That's where my armor piece is likely *supposed* to be (arms texture and body texture), but it isn't. Somehow, it's still being rendered on the player, though.
The big issue with this is that because the texture name isn't where it's supposed to be, you're effectively unable to do any complicated screwing around with how that layer is drawn.

This same issue occurs when equipping armor and accessories from other mods as well.
Hm, that's probably because textures from mods are created from streams, since they can't be loaded in by the content manager. I suppose in the next update I could try to manually assign their Name property. In the meantime you could check for reference equality with mod.GetTexture.
 
Hm, that's probably because textures from mods are created from streams, since they can't be loaded in by the content manager. I suppose in the next update I could try to manually assign their Name property. In the meantime you could check for reference equality with mod.GetTexture.
I'm getting confused here. How am I supposed to compare a Terraria.DataStructures.DrawData.texture object with a mod.GetTexture object? I'm trying to find armor textures, so would I be using mod.GetEquipTexture instead? How would this account for multiple textures e.g. arms?

EDIT: According to the documentation, I'm supposed to do mod.GetTexture("MyMod/items/armor/MyArmorTexture") to get the texture object, then I can compare it with the Terraria.DataStructures.DrawData.texture with .Equals? Or can I just use the normal operator (==)?
 
Last edited:
Allright, so I've got the following problem:
I've got a tile of which I'm getting the top-left coordinates, to access the some data belonging to that tile (kind of how chests are accessed).
Now my problem is that I want to animate the tile based on some of the values of the data. Problem is that in the AnimateTile function of the ModTile, there are no coordinate parameters, so I'm kind of at a loss.
 
Allright, so I've got the following problem:
I've got a tile of which I'm getting the top-left coordinates, to access the some data belonging to that tile (kind of how chests are accessed).
Now my problem is that I want to animate the tile based on some of the values of the data. Problem is that in the AnimateTile function of the ModTile, there are no coordinate parameters, so I'm kind of at a loss.
You can't animate other tiles with AnimateTile. Have the tile animate itself when it is accessed.
 
You can't animate other tiles with AnimateTile. Have the tile animate itself when it is accessed.
I'm sorry, that was not what I was getting at, but thanks for the quick reply.
I'm trying to animate the tile the method is called on, I just want it to animate using external data, which I need to access using the coordinates of the tile.
 
I'm sorry, that was not what I was getting at, but thanks for the quick reply.
I'm trying to animate the tile the method is called on, I just want it to animate using external data, which I need to access using the coordinates of the tile.
You can set the coordinates to be whatever C#'s equivalent of instance locals are, then access them from within AnimateTile.
Probably looks something like this:
Code:
private int targetX;
private int targetY;

(method where you set targetX and targetY)

(AnimateTile method)
{
    //you can access targetX and targetY from here
}
 
You can set the coordinates to be whatever C#'s equivalent of instance locals are, then access them from within AnimateTile.
Probably looks something like this:
Code:
private int targetX;
private int targetY;

(method where you set targetX and targetY)

(AnimateTile method)
{
    //you can access targetX and targetY from here
}
Yeah, I've been there and encountered a small problem... AnimateTile is called before any of the other methods in which I can get the coordinates (which are MouseOver and HitWire). I was hoping I could get some of these values via the SetDefaults method of my ModTile, but so far no luck.
I have been trying to utilize TileObjectData.newTile.HookPostPlaceMyPlayer in the SetDefaults function, but to no avail (so far that is).
 
Yeah, I've been there and encountered a small problem... AnimateTile is called before any of the other methods in which I can get the coordinates (which are MouseOver and HitWire). I was hoping I could get some of these values via the SetDefaults method of my ModTile, but so far no luck.
I have been trying to utilize TileObjectData.newTile.HookPostPlaceMyPlayer in the SetDefaults function, but to no avail (so far that is).
Try calling MouseOver/HitWire from within AnimateTile?
 
so, im trying to make a boss summon wallcreepers as minions but i get this error
error CS1061: 'Terraria.NPC' does not contain a definition for 'NPCType' and no extension method 'NPCType' accepting a first argument of type 'Terraria.NPC' could be found (are you missing a using directive or an assembly reference?)
this is my code
Code:
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace LordBozo.NPCs.Boss
{
    public class Spider : ModNPC
    {
        public override void SetDefaults()
        {
            npc.name = "SpiderBoss";
            npc.displayName = "Shelob";
            npc.aiStyle = 3;  
            npc.lifeMax = 5000;   
            npc.damage = 200;  
            npc.defense = 10;    
            npc.knockBackResist = 100f;
            npc.width = 47;
            npc.height = 97;
            animationType = NPCID.WallCreeper;   
            Main.npcFrameCount[npc.type] = 3;    
            npc.value = Item.buyPrice(0, 40, 75, 45);
            npc.npcSlots = 1f;
            npc.boss = true;
            npc.lavaImmune = true;
            npc.noGravity = false;
            npc.noTileCollide = false;
            npc.soundHit = 8;
            npc.soundKilled = 14;
            npc.buffImmune[24] = true;
            music = MusicID.Boss2;
            npc.netAlways = true;
        }
        public override void AutoloadHead(ref string headTexture, ref string bossHeadTexture)
        {
            bossHeadTexture = "LordBozo/NPCs/Boss/Ian_Head_Boss"; 
        }
        public override void BossLoot(ref string name, ref int potionType)
        {
            potionType = ItemID.LesserHealingPotion;   
            Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, mod.ItemType("Chloroform"));
        }
        public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
        {
            npc.lifeMax = (int)(npc.lifeMax * 0.579f * bossLifeScale);  
            npc.damage = (int)(npc.damage * 0.6f); 
        }
        public override void AI()
        {
            npc.ai[0]++;
            Player P = Main.player[npc.target];
            if (npc.target < 0 || npc.target == 255 || Main.player[npc.target].dead || !Main.player[npc.target].active)
            {
                npc.TargetClosest(true);
            }
            npc.netUpdate = true;

            npc.ai[1]++;
            if (npc.ai[1] >= 230)  
            {
                float Speed = 20f;  
                Vector2 vector8 = new Vector2(npc.position.X + (npc.width / 2), npc.position.Y + (npc.height / 2));
                int damage = 10;  
                int type = mod.ProjectileType("ProBoss");  
                Main.PlaySound(23, (int)npc.position.X, (int)npc.position.Y, 17);
                float rotation = (float)Math.Atan2(vector8.Y - (P.position.Y + (P.height * 0.5f)), vector8.X - (P.position.X + (P.width * 0.5f)));
                int num54 = Projectile.NewProjectile(vector8.X, vector8.Y, (float)((Math.Cos(rotation) * Speed) * -1), (float)((Math.Sin(rotation) * Speed) * -1), type, damage, 0f, 0);
                npc.ai[1] = 0;
            }
            if (npc.ai[0] % 600 == 3)  

            {
                NPC.NewNPC((int)npc.position.X, (int)npc.position.Y, npc.NPCType("WallCreeper") );  
            }
            npc.ai[1] += 0;
        }
    }
}
 
so, im trying to make a boss summon wallcreepers as minions but i get this error
error CS1061: 'Terraria.NPC' does not contain a definition for 'NPCType' and no extension method 'NPCType' accepting a first argument of type 'Terraria.NPC' could be found (are you missing a using directive or an assembly reference?)
this is my code
Code:
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace LordBozo.NPCs.Boss
{
    public class Spider : ModNPC
    {
        public override void SetDefaults()
        {
            npc.name = "SpiderBoss";
            npc.displayName = "Shelob";
            npc.aiStyle = 3; 
            npc.lifeMax = 5000;  
            npc.damage = 200; 
            npc.defense = 10;   
            npc.knockBackResist = 100f;
            npc.width = 47;
            npc.height = 97;
            animationType = NPCID.WallCreeper;  
            Main.npcFrameCount[npc.type] = 3;   
            npc.value = Item.buyPrice(0, 40, 75, 45);
            npc.npcSlots = 1f;
            npc.boss = true;
            npc.lavaImmune = true;
            npc.noGravity = false;
            npc.noTileCollide = false;
            npc.soundHit = 8;
            npc.soundKilled = 14;
            npc.buffImmune[24] = true;
            music = MusicID.Boss2;
            npc.netAlways = true;
        }
        public override void AutoloadHead(ref string headTexture, ref string bossHeadTexture)
        {
            bossHeadTexture = "LordBozo/NPCs/Boss/Ian_Head_Boss";
        }
        public override void BossLoot(ref string name, ref int potionType)
        {
            potionType = ItemID.LesserHealingPotion;  
            Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, mod.ItemType("Chloroform"));
        }
        public override void ScaleExpertStats(int numPlayers, float bossLifeScale)
        {
            npc.lifeMax = (int)(npc.lifeMax * 0.579f * bossLifeScale); 
            npc.damage = (int)(npc.damage * 0.6f);
        }
        public override void AI()
        {
            npc.ai[0]++;
            Player P = Main.player[npc.target];
            if (npc.target < 0 || npc.target == 255 || Main.player[npc.target].dead || !Main.player[npc.target].active)
            {
                npc.TargetClosest(true);
            }
            npc.netUpdate = true;

            npc.ai[1]++;
            if (npc.ai[1] >= 230) 
            {
                float Speed = 20f; 
                Vector2 vector8 = new Vector2(npc.position.X + (npc.width / 2), npc.position.Y + (npc.height / 2));
                int damage = 10; 
                int type = mod.ProjectileType("ProBoss"); 
                Main.PlaySound(23, (int)npc.position.X, (int)npc.position.Y, 17);
                float rotation = (float)Math.Atan2(vector8.Y - (P.position.Y + (P.height * 0.5f)), vector8.X - (P.position.X + (P.width * 0.5f)));
                int num54 = Projectile.NewProjectile(vector8.X, vector8.Y, (float)((Math.Cos(rotation) * Speed) * -1), (float)((Math.Sin(rotation) * Speed) * -1), type, damage, 0f, 0);
                npc.ai[1] = 0;
            }
            if (npc.ai[0] % 600 == 3) 

            {
                NPC.NewNPC((int)npc.position.X, (int)npc.position.Y, npc.NPCType("WallCreeper") ); 
            }
            npc.ai[1] += 0;
        }
    }
}
The following line:
Code:
NPC.NewNPC((int)npc.position.X, (int)npc.position.Y, npc.NPCType("WallCreeper") ); //NPC name
See how you're calling npc.NPCType? That should be mod.NPCType.
 
The following line:
Code:
NPC.NewNPC((int)npc.position.X, (int)npc.position.Y, npc.NPCType("WallCreeper") ); //NPC name
See how you're calling npc.NPCType? That should be mod.NPCType.
wall creeper is a vanilla npc not a modded one, its vanilla npc number 164 if that helps, would i still write mod.npctype
 
No, then it's even easier!
Code:
NPC.NewNPC((int)npc.position.X, (int)npc.position.Y, 164); //NPC name
Just like that.
hate to do this, but next question, so in the code i posted, it drops chloroform, how do i make it drop between 5-10 chloroform(modded item) and 5-10 Poison(modded item)
 
I'm getting confused here. How am I supposed to compare a Terraria.DataStructures.DrawData.texture object with a mod.GetTexture object? I'm trying to find armor textures, so would I be using mod.GetEquipTexture instead? How would this account for multiple textures e.g. arms?

EDIT: According to the documentation, I'm supposed to do mod.GetTexture("MyMod/items/armor/MyArmorTexture") to get the texture object, then I can compare it with the Terraria.DataStructures.DrawData.texture with .Equals? Or can I just use the normal operator (==)?
If I remember correctly, Equals and == do the same thing. They're more relaxed than a reference equality, so that should be good.
Also, if you're using mod.GetTexture instead of ModLoader.GetTexture, the MyMod/ part shouldn't be necessary.

Allright, so I've got the following problem:
I've got a tile of which I'm getting the top-left coordinates, to access the some data belonging to that tile (kind of how chests are accessed).
Now my problem is that I want to animate the tile based on some of the values of the data. Problem is that in the AnimateTile function of the ModTile, there are no coordinate parameters, so I'm kind of at a loss.
Hm, you'll probably have to wait until there's tile entity support. In the meantime, you can try keeping track of where all the tiles are, store animation information in the world's PostUpdate, then do the actual animation using PreDraw and/or PostDraw.
 
hate to do this, but next question, so in the code i posted, it drops chloroform, how do i make it drop between 5-10 chloroform(modded item) and 5-10 Poison(modded item)
You can do something like:
Code:
Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, mod.ItemType("Chloroform"), Main.rand.Next(5, 11)); // Will drop between 5 and 10.
If I remember correctly, Equals and == do the same thing. They're more relaxed than a reference equality, so that should be good.
Also, if you're using mod.GetTexture instead of ModLoader.GetTexture, the MyMod/ part shouldn't be necessary.


Hm, you'll probably have to wait until there's tile entity support. In the meantime, you can try keeping track of where all the tiles are, store animation information in the world's PostUpdate, then do the actual animation using PreDraw and/or PostDraw.
Yup, that's totally gonna work. I was too tunnel-visioned I guess. Thanks!
 
Back
Top Bottom