Standalone [1.3] tModLoader - A Modding API

yaaay now he wont lose bodyparts! but, next problem: after the player is ded he still follows him, how can i make him run away after the target is dead??
Use `npc.TargetClosest(true);` to get a target player. Check if that player is dead or inactive using `!Main.player[npc.target].active || Main.player[npc.target].dead`.
If neither is true, check for a target again and repeat. If the target player is still inactive | dead, have the NPC despawn using your own despawn logic.
It would look something like this:
Code:
npc.TargetClosest(true);
if(!Main.player[npc.target].active || Main.player[npc.target].dead)
{
    npc.TargetClosest(true);
    if(!Main.player[npc.target].active || Main.player[npc.target].dead)
    {
        // Set the NPC to a state where he 'runs away' or 'disappears'.
    }
}
 
i want him to travel into the ground really fast (like the pumpking does)
and do i put that into AI() or PreAI() ??
 
i want him to travel into the ground really fast (like the pumpking does)
and do i put that into AI() or PreAI() ??
Is see you're using PreAI for the head, so... PreAI.
Just use the AI method you're using (may it be PreAI, AI or PostAI), unless stated otherwise OR if you're positive that another AI method is the better way to go.

As for the 'travel into the ground really fast' part. If you've not written the AI yourself (which I think is the case here), try to understand what each part of the AI does.
If you're unable to do this, you might want to refrain from using said AI and continue with something more simple.
If you do understand how the AI works, make sure you create a new AI state for the head (not for the body | tail) and increment npc.velocity.Y by a certain amount (the higher the amount, the faster it will go down). You'll (probably) also want to create a timer to determine after how much time the NPC should despawn. If you want your NPC to despawn, just set `npc.active = false;`.
 
I'm having a problem with resolution, every time I boot it up it changes my resolution back to an unwanted value, whether I change it in settings or directly in the config file, does anyone know how to fix this?
 
I'm having a problem with resolution, every time I boot it up it changes my resolution back to an unwanted value, whether I change it in settings or directly in the config file, does anyone know how to fix this?
Are you changing the value in the correct config file? Not the vanilla one.
 
Are you changing the value in the correct config file? Not the vanilla one.
hey jopojelly, is it possible to create custom grass yet???
and how do i make my worm boss drop the items like the destroyer (part nearest to player or part which was last hit)
 
hey jopojelly, is it possible to create custom grass yet???
and how do i make my worm boss drop the items like the destroyer (part nearest to player or part which was last hit)
if you check out other mods like tremor (its recent spoilers), gabehaswon's and a few others, you'll see custom grass can be added in.
 
Trying to make it so I can add a buff to the player upon dealing magic damage to an enemy using an accessory. Not entirely sure how to do so, sadly. Is it something I have to put into ModPlayer? Or can I do it in the ModItem class?

Also, I was trying to make a buff that has an effectiveness relevant to the remaining buffTime, but it seems there is no extension method for it in ModBuff. I'm guessing I need to do stuff for that in ModPlayer as well?
 
Last edited:
After installing tmodloader my fps dropped from 60 to 30, i have none mods installed. Any ideas?
does it happen all the time, or under certain conditions, because i suffer the same problem, only it happens after i open and close my inventory while in-game sometimes.
 
Are you changing the value in the correct config file? Not the vanilla one.
It's the config file in the ModLoader file, I change it, save it and then the game changes it back itself.
[edit:]
I've even tried completely removing the config file and changing it again to no avail
[edit2:]
I just completely wiped it off and then reinstalled it and that sorted it, I guess that's the slightly more long-winded version of turn it off and turn it back on again XD
 
Last edited:
Hey @jopojelly, I think I have hit another point where I can't continue working on my mod without your help :p
I have used the code you have provided for the slots and the rendering is working perfectly (all though I still need to make some major changes before publishing it),
you can insert items into it and I can loop through all the slots and check if certain item is in there. But the key functionality is still not working...
Now I'm looping through the slots and detecting items in the Modded Player class. But I can't change items stats (pickaxe power for example) from there.

Here's my code in case you need it:
Code:
namespace MEquipment
{
    class MItem : GlobalItem
    {
        private Item[] singleSlotArray;
        double time;

        public MItem()
        {
            singleSlotArray = new Item[1];
        }

        public override void PostDrawInInventory(Item item, SpriteBatch spriteBatch, Vector2 position, Rectangle frame, Color drawColor, Color itemColor, Vector2 origin, float scale)
        {
            if (time != Main.time)
            {
                time = Main.time;

                // These 2 lines might not be needed, not sure why there are here.
                spriteBatch.End();
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

                DrawUpdateAugments(spriteBatch);
            }
            base.PostDrawInInventory(item, spriteBatch, position, frame, drawColor, itemColor, origin, scale);
        }

        private void DrawUpdateAugments(SpriteBatch spriteBatch)
        {
            if (Main.playerInventory && Main.EquipPage == 0 && MEquipment.augmentsUIEnabled)
            {
                Point value = new Point(Main.mouseX, Main.mouseY);
                Rectangle r = new Rectangle(0, 0, (int)((float)Main.inventoryBackTexture.Width * Main.inventoryScale), (int)((float)Main.inventoryBackTexture.Height * Main.inventoryScale));

                MPlayer csp = Main.player[Main.myPlayer].GetModPlayer<MPlayer>(mod);
                for (int i = 0; i < 18; i++)
                {
                    Main.inventoryScale = 0.85f;
                    Item augment = csp.Augments[i];
                    int num17 = (Main.screenWidth / 2) - 200;
                    int num18 = 25;
                    if (Main.netMode == 1) num17 -= 47;
                    if (i >= 3)
                    {
                        r.X = (num17 + (0 + i) * 47) - (i / 3) * 141;
                        r.Y = num18 + (i / 3) * 47;
                    }
                    else
                    {
                        r.X = num17 + (0 + i) * 47;
                        r.Y = num18;
                    }

                    if (r.Contains(value))
                    {
                        Main.player[Main.myPlayer].mouseInterface = true;
                        Main.armorHide = true;
                        singleSlotArray[0] = augment;
                        ItemSlot.Handle(singleSlotArray, ItemSlot.Context.InventoryItem, 0);
                        augment = singleSlotArray[0];
                    }

                    singleSlotArray[0] = augment;

                    ItemSlot.Draw(spriteBatch, singleSlotArray, ItemSlot.Context.ChestItem, 0, new Vector2(r.X, r.Y));
                    //Utils.DrawInvBG(spriteBatch, r1);
                    //player.inventory[player.selectedItem]

                    augment = singleSlotArray[0];
                    csp.Augments[i] = augment;
                }
            }
            #region DrawAugmentInfo
            if (Main.playerInventory && Main.EquipPage == 0 && MEquipment.augmentsUIEnabled) // checks if inventory is opened and augments UI is enabled
            {
                Color color = new Color(.9f, .9f, .9f, .9f);

                int num1 = (Main.screenWidth / 2) - 241;
                int num2 = 4;
                int pickIconPos = 32;
                int swordIconPos = 79;
                int yoyoIconPos = 126;
                int bowIconPos = 173;
                int gunIconPos = 220;
                int staffIconPos = 267;

                Main.spriteBatch.DrawString(Main.fontItemStack, "Augments", new Vector2(num1, num2), color, 0.0f, new Vector2(), 1f, SpriteEffects.None, 0.0f);
                Main.spriteBatch.Draw(mod.GetTexture("UI/pickIcon"), new Vector2(num1, pickIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/swordIcon"), new Vector2(num1, swordIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/yoyoIcon"), new Vector2(num1, yoyoIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/bowIcon"), new Vector2(num1, bowIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/gunIcon"), new Vector2(num1, gunIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/staffIcon"), new Vector2(num1, staffIconPos), color);
            }
            #endregion
        }
    }
}

--------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using MEquipment.Tools;

namespace MEquipment
{
    public class MPlayer : ModPlayer
    {
        public static int SaveVersion = 0; // for saving items in slots
        public int maxAugments = 18; // max number of accessory slots, remove
        public static int maxAugmentsA = 18;
        public Item[] Augments = new Item[maxAugmentsA];
        protected double pressedKeyTime;

        public override void Initialize()
        {
            Augments = new Item[maxAugments];
            for (int i = 0; i < maxAugments; i++)
            {
                Augments[i] = new Item();
                Augments[i].SetDefaults();
            }
        }

        public override void PreUpdate()
        {
            BasicMPickaxe pickaxe = new BasicMPickaxe();
            for (int i = 0; i < maxAugments; i++)
            {
                if (Augments[i].type == mod.ItemType("IronHead"))
                {
                    pickaxe.ironHeadInstalled = true;
                    pickaxe.item.pick += 200;
                    pickaxe.item.useTime += 20;
                    pickaxe.item.useAnimation += 25;
                    if (Math.Abs(Main.time - pressedKeyTime) > 60 && MEquipment.debugMode)
                    {
                        pressedKeyTime = Main.time;
                        Main.NewText("[DEBUG] Iron Head Installed", 0, 150, 150);
                        Main.NewText(pickaxe.item.pick.ToString());
                        Main.NewText(pickaxe.ironHeadInstalled.ToString());
                    }
                }
                else
                {
                    pickaxe.ironHeadInstalled = false;
                }
            }
        }

        public override void LoadCustomData(BinaryReader reader)
        {
            for (int i = 0; i < maxAugments; i++)
            {
                Augments[i] = new Item();
                Augments[i].SetDefaults();
            }

            int loadVersion = reader.ReadInt32();

            if (loadVersion == 0)
            {
                maxAugmentsA = reader.ReadInt32();
                ReadInventory(Augments, reader, false, false);
            }
        }

        public override void SaveCustomData(BinaryWriter writer)
        {
            writer.Write(SaveVersion);
            writer.Write(maxAugments);

            WriteInventory(Augments, writer, false, false);
        }

        internal static bool WriteInventory(Item[] inv, BinaryWriter writer, bool writeStack = false, bool writeFavorite = false)
        {
            ushort count = 0;
            byte[] data;
            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter invWriter = new BinaryWriter(stream))
                {
                    for (int k = 0; k < inv.Length; k++)
                    {
                        if (IsModItem(inv[k]))
                        {
                            invWriter.Write((ushort)k);
                            Terraria.ModLoader.IO.ItemIO.WriteItem(inv[k], invWriter, writeStack, writeFavorite);
                            count++;
                        }
                    }
                }

                data = stream.ToArray();
            }
            if (count > 0)
            {
                writer.Write(count);
                writer.Write(data);

                return true;
            }
            return false;
        }

        internal static void ReadInventory(Item[] inv, BinaryReader reader, bool readStack = false, bool readFavorite = false)
        {
            int count = reader.ReadUInt16();
            for (int k = 0; k < count; k++)
            {
                ushort index = reader.ReadUInt16();
                Terraria.ModLoader.IO.ItemIO.ReadItem(inv[index], reader, readStack, readFavorite);
            }

        }

        internal static bool IsModItem(Item item)
        {
            return item.type >= ItemID.Count;
        }
    }
}

-------------------------------------------------------------------------------------------
using System;
using System.IO;
using Terraria;
using Terraria.ModLoader;

namespace MEquipment.Tools
{
    public class BasicMPickaxe : ModItem
    {
        private const int saveVersion = 0;
        protected double pressedKeyTime;

        public bool ironHeadInstalled = false;

        public override void SetDefaults()
        {
            item.name = "Basic Modular Pickaxe";
            item.toolTip = "A basic pickaxe, nothing special here...";
            item.value = Item.sellPrice(0, 5, 0, 0);
            item.width = 38;
            item.height = 38;
            item.melee = true;
            item.autoReuse = true;
            item.useTurn = true;
            item.rare = 9;
            item.useStyle = 1;
            item.useSound = 1;
            item.knockBack = 6;
            item.pick = 0;
            item.damage = 0;
            item.useTime = 0;
            item.useAnimation = 0;
        }

        public override void PostUpdate()
        {
            if (ironHeadInstalled)
            {
                item.pick += 200;
                item.useTime += 20;
                item.useAnimation += 25;
            }
        }

        public override void AddRecipes()
        {
          /* To-Do */
        }

        public override void SaveCustomData(BinaryWriter writer)
        {
            writer.Write(saveVersion);
            writer.Write(item.pick);
            writer.Write(item.useTime);
            writer.Write(item.damage);
        }

        public override void LoadCustomData(BinaryReader reader)
        {
            int loadVersion = reader.ReadInt32();
            item.useTime = reader.ReadInt32();
            item.pick = reader.ReadInt32();
            item.damage = reader.ReadInt32();
        }
    }
}
Do you have any advice for me?
Thanks in advance :)
 
Hey @jopojelly, I think I have hit another point where I can't continue working on my mod without your help :p
I have used the code you have provided for the slots and the rendering is working perfectly (all though I still need to make some major changes before publishing it),
you can insert items into it and I can loop through all the slots and check if certain item is in there. But the key functionality is still not working...
Now I'm looping through the slots and detecting items in the Modded Player class. But I can't change items stats (pickaxe power for example) from there.

Here's my code in case you need it:
Code:
namespace MEquipment
{
    class MItem : GlobalItem
    {
        private Item[] singleSlotArray;
        double time;

        public MItem()
        {
            singleSlotArray = new Item[1];
        }

        public override void PostDrawInInventory(Item item, SpriteBatch spriteBatch, Vector2 position, Rectangle frame, Color drawColor, Color itemColor, Vector2 origin, float scale)
        {
            if (time != Main.time)
            {
                time = Main.time;

                // These 2 lines might not be needed, not sure why there are here.
                spriteBatch.End();
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

                DrawUpdateAugments(spriteBatch);
            }
            base.PostDrawInInventory(item, spriteBatch, position, frame, drawColor, itemColor, origin, scale);
        }

        private void DrawUpdateAugments(SpriteBatch spriteBatch)
        {
            if (Main.playerInventory && Main.EquipPage == 0 && MEquipment.augmentsUIEnabled)
            {
                Point value = new Point(Main.mouseX, Main.mouseY);
                Rectangle r = new Rectangle(0, 0, (int)((float)Main.inventoryBackTexture.Width * Main.inventoryScale), (int)((float)Main.inventoryBackTexture.Height * Main.inventoryScale));

                MPlayer csp = Main.player[Main.myPlayer].GetModPlayer<MPlayer>(mod);
                for (int i = 0; i < 18; i++)
                {
                    Main.inventoryScale = 0.85f;
                    Item augment = csp.Augments[i];
                    int num17 = (Main.screenWidth / 2) - 200;
                    int num18 = 25;
                    if (Main.netMode == 1) num17 -= 47;
                    if (i >= 3)
                    {
                        r.X = (num17 + (0 + i) * 47) - (i / 3) * 141;
                        r.Y = num18 + (i / 3) * 47;
                    }
                    else
                    {
                        r.X = num17 + (0 + i) * 47;
                        r.Y = num18;
                    }

                    if (r.Contains(value))
                    {
                        Main.player[Main.myPlayer].mouseInterface = true;
                        Main.armorHide = true;
                        singleSlotArray[0] = augment;
                        ItemSlot.Handle(singleSlotArray, ItemSlot.Context.InventoryItem, 0);
                        augment = singleSlotArray[0];
                    }

                    singleSlotArray[0] = augment;

                    ItemSlot.Draw(spriteBatch, singleSlotArray, ItemSlot.Context.ChestItem, 0, new Vector2(r.X, r.Y));
                    //Utils.DrawInvBG(spriteBatch, r1);
                    //player.inventory[player.selectedItem]

                    augment = singleSlotArray[0];
                    csp.Augments[i] = augment;
                }
            }
            #region DrawAugmentInfo
            if (Main.playerInventory && Main.EquipPage == 0 && MEquipment.augmentsUIEnabled) // checks if inventory is opened and augments UI is enabled
            {
                Color color = new Color(.9f, .9f, .9f, .9f);

                int num1 = (Main.screenWidth / 2) - 241;
                int num2 = 4;
                int pickIconPos = 32;
                int swordIconPos = 79;
                int yoyoIconPos = 126;
                int bowIconPos = 173;
                int gunIconPos = 220;
                int staffIconPos = 267;

                Main.spriteBatch.DrawString(Main.fontItemStack, "Augments", new Vector2(num1, num2), color, 0.0f, new Vector2(), 1f, SpriteEffects.None, 0.0f);
                Main.spriteBatch.Draw(mod.GetTexture("UI/pickIcon"), new Vector2(num1, pickIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/swordIcon"), new Vector2(num1, swordIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/yoyoIcon"), new Vector2(num1, yoyoIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/bowIcon"), new Vector2(num1, bowIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/gunIcon"), new Vector2(num1, gunIconPos), color);
                Main.spriteBatch.Draw(mod.GetTexture("UI/staffIcon"), new Vector2(num1, staffIconPos), color);
            }
            #endregion
        }
    }
}

--------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using MEquipment.Tools;

namespace MEquipment
{
    public class MPlayer : ModPlayer
    {
        public static int SaveVersion = 0; // for saving items in slots
        public int maxAugments = 18; // max number of accessory slots, remove
        public static int maxAugmentsA = 18;
        public Item[] Augments = new Item[maxAugmentsA];
        protected double pressedKeyTime;

        public override void Initialize()
        {
            Augments = new Item[maxAugments];
            for (int i = 0; i < maxAugments; i++)
            {
                Augments[i] = new Item();
                Augments[i].SetDefaults();
            }
        }

        public override void PreUpdate()
        {
            BasicMPickaxe pickaxe = new BasicMPickaxe();
            for (int i = 0; i < maxAugments; i++)
            {
                if (Augments[i].type == mod.ItemType("IronHead"))
                {
                    pickaxe.ironHeadInstalled = true;
                    pickaxe.item.pick += 200;
                    pickaxe.item.useTime += 20;
                    pickaxe.item.useAnimation += 25;
                    if (Math.Abs(Main.time - pressedKeyTime) > 60 && MEquipment.debugMode)
                    {
                        pressedKeyTime = Main.time;
                        Main.NewText("[DEBUG] Iron Head Installed", 0, 150, 150);
                        Main.NewText(pickaxe.item.pick.ToString());
                        Main.NewText(pickaxe.ironHeadInstalled.ToString());
                    }
                }
                else
                {
                    pickaxe.ironHeadInstalled = false;
                }
            }
        }

        public override void LoadCustomData(BinaryReader reader)
        {
            for (int i = 0; i < maxAugments; i++)
            {
                Augments[i] = new Item();
                Augments[i].SetDefaults();
            }

            int loadVersion = reader.ReadInt32();

            if (loadVersion == 0)
            {
                maxAugmentsA = reader.ReadInt32();
                ReadInventory(Augments, reader, false, false);
            }
        }

        public override void SaveCustomData(BinaryWriter writer)
        {
            writer.Write(SaveVersion);
            writer.Write(maxAugments);

            WriteInventory(Augments, writer, false, false);
        }

        internal static bool WriteInventory(Item[] inv, BinaryWriter writer, bool writeStack = false, bool writeFavorite = false)
        {
            ushort count = 0;
            byte[] data;
            using (MemoryStream stream = new MemoryStream())
            {
                using (BinaryWriter invWriter = new BinaryWriter(stream))
                {
                    for (int k = 0; k < inv.Length; k++)
                    {
                        if (IsModItem(inv[k]))
                        {
                            invWriter.Write((ushort)k);
                            Terraria.ModLoader.IO.ItemIO.WriteItem(inv[k], invWriter, writeStack, writeFavorite);
                            count++;
                        }
                    }
                }

                data = stream.ToArray();
            }
            if (count > 0)
            {
                writer.Write(count);
                writer.Write(data);

                return true;
            }
            return false;
        }

        internal static void ReadInventory(Item[] inv, BinaryReader reader, bool readStack = false, bool readFavorite = false)
        {
            int count = reader.ReadUInt16();
            for (int k = 0; k < count; k++)
            {
                ushort index = reader.ReadUInt16();
                Terraria.ModLoader.IO.ItemIO.ReadItem(inv[index], reader, readStack, readFavorite);
            }

        }

        internal static bool IsModItem(Item item)
        {
            return item.type >= ItemID.Count;
        }
    }
}

-------------------------------------------------------------------------------------------
using System;
using System.IO;
using Terraria;
using Terraria.ModLoader;

namespace MEquipment.Tools
{
    public class BasicMPickaxe : ModItem
    {
        private const int saveVersion = 0;
        protected double pressedKeyTime;

        public bool ironHeadInstalled = false;

        public override void SetDefaults()
        {
            item.name = "Basic Modular Pickaxe";
            item.toolTip = "A basic pickaxe, nothing special here...";
            item.value = Item.sellPrice(0, 5, 0, 0);
            item.width = 38;
            item.height = 38;
            item.melee = true;
            item.autoReuse = true;
            item.useTurn = true;
            item.rare = 9;
            item.useStyle = 1;
            item.useSound = 1;
            item.knockBack = 6;
            item.pick = 0;
            item.damage = 0;
            item.useTime = 0;
            item.useAnimation = 0;
        }

        public override void PostUpdate()
        {
            if (ironHeadInstalled)
            {
                item.pick += 200;
                item.useTime += 20;
                item.useAnimation += 25;
            }
        }

        public override void AddRecipes()
        {
          /* To-Do */
        }

        public override void SaveCustomData(BinaryWriter writer)
        {
            writer.Write(saveVersion);
            writer.Write(item.pick);
            writer.Write(item.useTime);
            writer.Write(item.damage);
        }

        public override void LoadCustomData(BinaryReader reader)
        {
            int loadVersion = reader.ReadInt32();
            item.useTime = reader.ReadInt32();
            item.pick = reader.ReadInt32();
            item.damage = reader.ReadInt32();
        }
    }
}
Do you have any advice for me?
Thanks in advance :)
You don't want to do things like += X on something that is run every frame unless you are somehow resetting it. Also, look up PostUpdate in the docs, it's not what you think it is.
 
You don't want to do things like += X on something that is run every frame unless you are somehow resetting it. Also, look up PostUpdate in the docs, it's not what you think it is.
I know that PostItem is associated with item pickup. But where should I insert the for loop that's detecting the items and updating the stats?
 
After installing tmodloader my fps dropped from 60 to 30, i have none mods installed. Any ideas?
I used to get a similar problem with tAPI. The problem went away if I Alt + Tabbed to desktop, then went back to the game. I don't know if it will help with you, though. Also, does it stick to exactly 30fps, or just hover around that number?
 
Is there a way to get a boss to play custom music? If so, then how?
There is. Take a look at the following code:
Code:
public override void SetDefaults()
{
    // Other SetDefaults stuff...

    music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/MyBossMusic");
}
This gets the SoundSlot of the .wav or .mp3 file at the given location (Sounds/Music/MyBossMusic).
I'd recommend putting your audio file in that location (Sounds/Music), but the filename can be changed around of course.
You also want to make sure sounds are autoloaded. If you know where Autoload is set, make sure th Properties look like this:
Code:
Properties = new ModProperties()
{
    Autoload = true,
    AutoloadSounds = true
};
 
Back
Top Bottom