Standalone [1.3] tModLoader - A Modding API

ok, I saw the github things and its like just longer. got a few questions;
Must I have a weapon folder or just keep the Item folder with weapons inside?
say I want my weapon with a bit of coding must that weapon have 2 cs files? I learnt programming but I've yet to use my programming because still nervous.
Organization is good, but if you don't want to, just keep everything on the same folder level. If you do, make sure that the namespace is consistent, since namespace is mapped to folder structure for Autoloading textures and so forth.

So, for ExampleMod, you can restructure the Weapon folder by moving the files in that folder down to the Item folder, then change the namespace from "namespace ExampleMod.Items.Weapons" to "namespace ExampleMod.Items" in each of the files you moved.

I'm not sure where you are getting the idea that a weapon needs 2 .cs files. Every item in the ExampleMod is only one .cs file and one .png file.
 
Organization is good, but if you don't want to, just keep everything on the same folder level. If you do, make sure that the namespace is consistent, since namespace is mapped to folder structure for Autoloading textures and so forth.

So, for ExampleMod, you can restructure the Weapon folder by moving the files in that folder down to the Item folder, then change the namespace from "namespace ExampleMod.Items.Weapons" to "namespace ExampleMod.Items" in each of the files you moved.

I'm not sure where you are getting the idea that a weapon needs 2 .cs files. Every item in the ExampleMod is only one .cs file and one .png file.
I mean if I wanted to code my weapons, I would need to make 2 diff cs files? (or maybe just one. the start of code initializes the weapon data, and the rest is the arguments etc)
edit; is the build.txt the replacement of modinfo.json (tAPI)?
 
I mean if I wanted to code my weapons, I would need to make 2 diff cs files? (or maybe just one. the start of code initializes the weapon data, and the rest is the arguments etc)
No, no weapon in the ExampleMod follows that convention. Why bother? Just keep it in the same file. Look: https://github.com/bluemagic123/tModLoader/blob/master/ExampleMod/Items/Weapons/ExampleSword.cs

The SetDefaults method, from what I gather, is kinda equivalent to the rudimentary .json files that were present in older APIs. You can literally copy/paste most things in and just change them into c# syntax: "damage": 20, in json becoms item.damage = 20; For most things, they will be booleans, ints, and floats so it will be straightforward to convert. For others, like recipes, look at the examples in ExampleMod.
 
I mean if I wanted to code my weapons, I would need to make 2 diff cs files? (or maybe just one. the start of code initializes the weapon data, and the rest is the arguments etc)
edit; is the build.txt the replacement of modinfo.json (tAPI)?
No, you don't need two different files. The properties and the code are all combined into one file. Instead of json files, there is the SetDefaults hooks in the .cs file.

And for now yes, build.txt is the replacement of modinfo.json. However, one day in the future I want to replace build.txt with a json file.
 
No, you don't need two different files. The properties and the code are all combined into one file. Instead of json files, there is the SetDefaults hooks in the .cs file.

And for now yes, build.txt is the replacement of modinfo.json. However, one day in the future I want to replace build.txt with a json file.
ok thanks for the info! thats even better because I wont need to refer to other files and making amendments is far convenient.
EDIT: cant find .tmod reference :/
 
.tmod is the compiled mod. There is no reference.
oh wait.. straight from the log
Mod reference C:\Users\Trekko727\Documents\My Games\Terraria\ModLoader\Mods\ExampleMod.tmod was not found.
so I just build the first time and fix the rest?
EDIT I'm just adjusting my mods to suit tModLoader but what does "public class ExampleGun : ModItem" refer to (ExampleGun as the image or the name of the weapon)
 
Last edited:
Well, trees grow during UpdateWorld, we don't have hooks there yet. The code iterates through Main.tile[,] and checks active() and type.

Maybe you could use TileFrame to check Main.tile[i, j].type for surrounding tiles. If you detect the right tile, do whatever you want to do. (It might be hard. What exactly are you trying to do?)

I was thinking of trying to make a crafting station (i.e. a mechanical anvil) that only functions as a crafting station if one side of its sprite is directly adjacent to the side of another tile (i.e. a power source) .

I could then make more of these neighbour-dependent crafting stations and hook them up to the same thing the same way.

Is this too complicated to do in this version of tModLoader?
 
I was thinking of trying to make a crafting station (i.e. a mechanical anvil) that only functions as a crafting station if one side of its sprite is directly adjacent to the side of another tile (i.e. a power source) .

I could then make more of these neighbour-dependent crafting stations and hook them up to the same thing the same way.

Is this too complicated to do in this version of tModLoader?
This is just something I've done (which might not work for everyone, but it's worth the shot). Create 2 tiles, one names 'MechanicalAnvilInactive' and one MechanicalAnvilActive'. You can then (on the Inactive one) check the surrounding tiles and see if the tile you need is present. If it is, you can just replace the whole tile with the Active one (on which you'll have to check if the tile you need is present and change it back if it isn't) and just add the MechanicalAnvilActive to your recipe.

Like I said, something I've done and it might not be the solution you're looking for ;)
 
This is just something I've done (which might not work for everyone, but it's worth the shot). Create 2 tiles, one names 'MechanicalAnvilInactive' and one MechanicalAnvilActive'. You can then (on the Inactive one) check the surrounding tiles and see if the tile you need is present. If it is, you can just replace the whole tile with the Active one (on which you'll have to check if the tile you need is present and change it back if it isn't) and just add the MechanicalAnvilActive to your recipe.

Like I said, something I've done and it might not be the solution you're looking for ;)

Interesting idea. Could you give me an example in code? That might help a bit.
 
Well, I'm back, with more questions, this time regarding tile placement. Before anything else, here are the classes:

Code:
class totemPole : ModItem
{
  public override void SetDefaults()
  {
  item.name = "Totem Pole";
  item.width = 32;
  item.height = 64;
  item.maxStack = 99;
  AddTooltip("A decorative pole. Best not carry it.");
  item.autoReuse = true;
  item.useAnimation = 15;
  item.useTime = 10;
  item.useSound = 1;
  item.consumable = true;
  item.value = 400;
  item.createTile = mod.TileType("totemPole");
  }

  public override void AddRecipes()
  {
  ModRecipe recipe = new ModRecipe(mod);
  recipe.AddIngredient(Terraria.ID.ItemID.Wood, 10);
  recipe.SetResult(this);
  recipe.AddRecipe();
  }
}

Code:
  class totemPole : ModTile
  {
  public override void SetDefaults()
  {
  Main.tileFrameImportant[Type] = true;
  Main.tileNoAttach[Type] = true;
  Main.tileLavaDeath[Type] = false;
  TileObjectData.newTile.CopyFrom(TileObjectData.Style2xX);
  TileObjectData.newTile.CoordinateHeights = new int[] { 16, 64 };
  //TileObjectData.newTile.Direction = TileObjectDirection.PlaceLeft;
  //TileObjectData.newTile.StyleWrapLimit = 2; //not really necessary but allows me to add more subtypes of chairs below the example chair texture
  //TileObjectData.newTile.StyleMultiplier = 2; //same as above
  //TileObjectData.newTile.StyleHorizontal = true;
  //TileObjectData.newAlternate.CopyFrom(TileObjectData.newTile);
  //TileObjectData.newAlternate.Direction = TileObjectDirection.PlaceRight; //allows me to place example chairs facing the same way as the player
  //TileObjectData.addAlternate(1); //facing right will use the second texture style
  TileObjectData.addTile(Type);
  AddMapEntry(new Color(200, 200, 200), "Totem Pole");
  //dustType = mod.DustType("Sparkle");
  dustType = 5;
  adjTiles = new int[] { TileID.Chairs };
  }

  public override void KillMultiTile(int i, int j, int frameX, int frameY)
  {
  Item.NewItem(i * 16, j * 16, 32, 64, mod.ItemType("totemPole"));
  }
  }

The tile appears (almost) as expected when I attempt to place it, but cannot actually be placed. I'm going to guess that the unusual appearance (an elongation of the bottommost portion of the sprite) is a result of spacing errors, as I didn't include space between tiles in the image. When attempting to place it, I can lower the item to the point shown in the screenshot before it turns red.

vuLwggb.png


To clarify, nothing happens when I left-click in this situation. I have tried raising and lowering the item by one block at a time, with no effect.

Based on the code and the screenshot, what could be causing this error?


(And as an unrelated point, how is light value calculated in ModTile.ModifyLight? It seems like higher rgb values mean "brighter," but I can't find a way to prevent it from modifying the player's sprite color. But... only the player itself, for some reason. Equipped items retain their color, even when the player is at nearly 100% white.)
 
Interesting idea. Could you give me an example in code? That might help a bit.
The following is an example. I'll post the code first and explain after that:
Code:
public class MyTile : ModTile
{
    public override void SetDefaults()
    {
        Main.tileSolid[Type] = true;
        Main.tileMergeDirt[Type] = true;
        Main.tileBlockLight[Type] = true;
        Main.tileLighted[Type] = true;

        drop = mod.ItemType("MyTile");
    }

    public override bool TileFrame(int i, int j, ref bool resetFrame, ref bool noBreak)
    {
        if (Main.tile[i, j - 1].type == TileID.ClayBlock)
        {
            Main.tile[i, j].type = (ushort)mod.TileType("MyOtherTile");
            WorldGen.SquareTileFrame(i, j, true);
        }

        return base.TileFrame(i, j, ref resetFrame, ref noBreak);
    }
}
So, this example is just your average 1x1 block in Terraria (think a dirt block or something) with one exeption.
As you can see we override the TileFrame function, which gets called (according to the wiki) when the tile itself gets placed or a tile around it gets updated.
We then check if the tile above this one is a Clay Block and if that returns true, we convert this tile into 'MyOtherTile'. If you've got one tile consisting of multiple parts, you've got to think a bit further, but I guess you get the idea(?) ;)

Well, I'm back, with more questions, this time regarding tile placement. Before anything else, here are the classes:

Code:
class totemPole : ModItem
{
  public override void SetDefaults()
  {
  item.name = "Totem Pole";
  item.width = 32;
  item.height = 64;
  item.maxStack = 99;
  AddTooltip("A decorative pole. Best not carry it.");
  item.autoReuse = true;
  item.useAnimation = 15;
  item.useTime = 10;
  item.useSound = 1;
  item.consumable = true;
  item.value = 400;
  item.createTile = mod.TileType("totemPole");
  }

  public override void AddRecipes()
  {
  ModRecipe recipe = new ModRecipe(mod);
  recipe.AddIngredient(Terraria.ID.ItemID.Wood, 10);
  recipe.SetResult(this);
  recipe.AddRecipe();
  }
}

Code:
  class totemPole : ModTile
  {
  public override void SetDefaults()
  {
  Main.tileFrameImportant[Type] = true;
  Main.tileNoAttach[Type] = true;
  Main.tileLavaDeath[Type] = false;
  TileObjectData.newTile.CopyFrom(TileObjectData.Style2xX);
  TileObjectData.newTile.CoordinateHeights = new int[] { 16, 64 };
  //TileObjectData.newTile.Direction = TileObjectDirection.PlaceLeft;
  //TileObjectData.newTile.StyleWrapLimit = 2; //not really necessary but allows me to add more subtypes of chairs below the example chair texture
  //TileObjectData.newTile.StyleMultiplier = 2; //same as above
  //TileObjectData.newTile.StyleHorizontal = true;
  //TileObjectData.newAlternate.CopyFrom(TileObjectData.newTile);
  //TileObjectData.newAlternate.Direction = TileObjectDirection.PlaceRight; //allows me to place example chairs facing the same way as the player
  //TileObjectData.addAlternate(1); //facing right will use the second texture style
  TileObjectData.addTile(Type);
  AddMapEntry(new Color(200, 200, 200), "Totem Pole");
  //dustType = mod.DustType("Sparkle");
  dustType = 5;
  adjTiles = new int[] { TileID.Chairs };
  }

  public override void KillMultiTile(int i, int j, int frameX, int frameY)
  {
  Item.NewItem(i * 16, j * 16, 32, 64, mod.ItemType("totemPole"));
  }
  }

The tile appears (almost) as expected when I attempt to place it, but cannot actually be placed. I'm going to guess that the unusual appearance (an elongation of the bottommost portion of the sprite) is a result of spacing errors, as I didn't include space between tiles in the image. When attempting to place it, I can lower the item to the point shown in the screenshot before it turns red.

vuLwggb.png


To clarify, nothing happens when I left-click in this situation. I have tried raising and lowering the item by one block at a time, with no effect.

Based on the code and the screenshot, what could be causing this error?


(And as an unrelated point, how is light value calculated in ModTile.ModifyLight? It seems like higher rgb values mean "brighter," but I can't find a way to prevent it from modifying the player's sprite color. But... only the player itself, for some reason. Equipped items retain their color, even when the player is at nearly 100% white.)
So, what you've doing is.... Well, will probably never work XD
You've got to do something more like the following (it's just the SetDefaults function of your ModTile):
Code:
public override void SetDefaults()
{
    Main.tileFrameImportant[Type] = true;
    Main.tileNoAttach[Type] = true;
    Main.tileLavaDeath[Type] = false;
    TileObjectData.newTile.CopyFrom(TileObjectData.Style1x1);
    TileObjectData.newTile.Width = 1;
    TileObjectData.newTile.Height = 4;
    TileObjectData.addTile(Type);
    AddMapEntry(new Color(200, 200, 200), "Totem Pole");
    dustType = 5;
    adjTiles = new int[] { TileID.Chairs };
}
Yeah, don't know if this will actually fix this. If it doesn't, it'd help if you were to post your texture, so that I can replicate your problem ;)
 
Last edited:
So, what you've doing is.... Well, will probably never work XD
You've got to do something more like the following (it's just the SetDefaults function of your ModTile):
Code:
public override void SetDefaults()
{
    Main.tileFrameImportant[Type] = true;
    Main.tileNoAttach[Type] = true;
    Main.tileLavaDeath[Type] = false;
    TileObjectData.newTile.CopyFrom(TileObjectData.Style1x1);
    TileObjectData.newTile.Width = 1;
    TileObjectData.newTile.Height = 4;
    TileObjectData.addTile(Type);
    AddMapEntry(new Color(200, 200, 200), "Totem Pole");
    dustType = 5;
    adjTiles = new int[] { TileID.Chairs };
}
Yeah, don't know if this will actually fix this. If it doesn't, it'd help if you were to post your texture, so that I can replicate your problem ;)

Afraid that didn't do much of anything. Your original method, using the Style2xX, cut off the bottom portion of the tile. The Style1x1 method leaves only the top-most portion of the design. Either way, it's still unplaceable. Sprite attached below.
 

Attachments

  • totemPole.png
    totemPole.png
    432 bytes · Views: 273
Afraid that didn't do much of anything. Your original method, using the Style2xX, cut off the bottom portion of the tile. The Style1x1 method leaves only the top-most portion of the design. Either way, it's still unplaceable. Sprite attached below.
Allright, I went ahead and fiddled with it a bit and came with the follwoing SetDefaults function:
Code:
public override void SetDefaults()
{
    Main.tileFrameImportant[Type] = true;
    Main.tileNoAttach[Type] = true;
    Main.tileLavaDeath[Type] = false;
    TileObjectData.newTile.CopyFrom(TileObjectData.Style3x4);
    TileObjectData.newTile.Width = 1;
           
    TileObjectData.newTile.StyleWrapLimit = 111;
    TileObjectData.addTile(Type);
    adjTiles = new int[] { TileID.Chairs };
}
This worked for me.
Also, you didn't include padding in your texture, so here you go (note that the code was done quite quickly, so there might be a better solution):
GUb7eIr.png

Hope this helps/works!
 
Code:
public override void SetDefaults()
{
    Main.tileFrameImportant[Type] = true;
    Main.tileNoAttach[Type] = true;
    Main.tileLavaDeath[Type] = false;
    TileObjectData.newTile.CopyFrom(TileObjectData.Style3x4);
    TileObjectData.newTile.Width = 1;
          
    TileObjectData.newTile.StyleWrapLimit = 111;
    TileObjectData.addTile(Type);
    adjTiles = new int[] { TileID.Chairs };
}
This worked for me.
Also, you didn't include padding in your texture, so here you go (note that the code was done quite quickly, so there might be a better solution):
GUb7eIr.png

Hope this helps/works!

That should be in the ModTile, right? I'm afraid it still can't be placed. :/
I really have no idea what could be wrong with it, at this point. My original code was pretty much copied straight out of ExampleChair.SetDefaults from the ExampleMod.
 
I have a couple of questions about PreNPCLoot and NPCLoot in GlobalNPC.

If PreNPCLoot returns false, NPCLoot will still be called, right? I'm assuming it works this way since that's how other Pre- methods work but I just want to make sure.

Assuming that's true, I can use those two functions to essentially change what a certain mob drops, correct? So in PreLootNPC I can check whether npc.type == whatever, and return false to prevent its normal loot from dropping, then in NPCLoot I can drop whatever I want?

Now, what happens if two different mods both try to do this? Will both NPCLoots get called, or only one? If so, which one?

I am asking because I am making a mod that implements easy-to-make loot tables for bosses (or any mob really), and I'm wondering if it makes sense to have that mod override all the vanilla bosses loot drops, or to just leave the vanilla bosses alone in case another mod wants to modify their drops.

Also, does overriding NPCLoot also prevent a boss from dropping hearts, potions, coins, or a boss trophy? It seems that the code for those things is in a different part of the NPC class to the code that drops regular loot (items and masks). And do I have to do anything special to make sure that the expert mode treasure bag works fine (other than making sure to drop the special rainbow expert mode items if it's expert mode)?
 
Last edited:
Hey i have correctly instaled tModLoader, what do i do now? How can i make the mods active?
Are you building mods or just installing them?

If the latter, you have two choices:

1) First, check whether the mod you're looking for is in the in-client Mod Browser.

2) If it isn't, you need the .tmod file distributed by the mod developer. I'm not sure off the top of my head where you need to *put* it, but it's probably explained in the post at the top of the thread. I'd guess it goes in the Mod Sources folder, probably?
 
I have a couple of questions about PreNPCLoot and NPCLoot in GlobalNPC.

If PreNPCLoot returns false, NPCLoot will still be called, right? I'm assuming it works this way since that's how other Pre- methods work but I just want to make sure.

Assuming that's true, I can use those two functions to essentially change what a certain mob drops, correct? So in PreLootNPC I can check whether npc.type == whatever, and return false to prevent its normal loot from dropping, then in NPCLoot I can drop whatever I want?

Now, what happens if two different mods both try to do this? Will both NPCLoots get called, or only one? If so, which one?

I am asking because I am making a mod that implements easy-to-make loot tables for bosses (or any mob really), and I'm wondering if it makes sense to have that mod override all the vanilla bosses loot drops, or to just leave the vanilla bosses alone in case another mod wants to modify their drops.

Also, does overriding NPCLoot also prevent a boss from dropping hearts, potions, coins, or a boss trophy? It seems that the code for those things is in a different part of the NPC class to the code that drops regular loot (items and masks). And do I have to do anything special to make sure that the expert mode treasure bag works fine (other than making sure to drop the special rainbow expert mode items if it's expert mode)?
If PreNPCLoot returns false, NPCLoot will not be called.

All that you'll need to change what a mob drops is the PreNPCLoot hook. If you want to change all its drops, then you can return false. But really, the main reason I allow the modder to return false is to emulate the behavior of Meteor Head in hardmode. If you only want to change some of its drops, then NPCLoader has a blockLoot field to which you can add the IDs of the drops you want to change. This will disable the item from being created until NPC.NPCLoot ends, so if you still want to create the item you'll need to call Item.NewItem before you add the ID to blockLoot.

ModNPC.NPCLoot and GlobalNPC.NPCLoot gets called in addition to the vanilla loot, so the boss will still be able to drop all of its normal stuff. You shouldn't have to do anything special to make sure the expert treasure bags work fine (unless you're creating your own boss), but you will have to override GlobalItem.OpenVanillaBag and/or GlobalItem.PreOpenVanillaBag in order to modify their loot.

Hey i have correctly instaled tModLoader, what do i do now? How can i make the mods active?
Are you building mods or just installing them?

If the latter, you have two choices:

1) First, check whether the mod you're looking for is in the in-client Mod Browser.

2) If it isn't, you need the .tmod file distributed by the mod developer. I'm not sure off the top of my head where you need to *put* it, but it's probably explained in the post at the top of the thread. I'd guess it goes in the Mod Sources folder, probably?
You can either download mods from the Mod Browser menu, or you can download mods from these forums then move the .tmod file to the "Mods" folder inside your "ModLoader" folder inside your "Terraria" folder.
 
Back
Top Bottom