tModLoader Modding Tutorial: World Generation

Did this thread help you?

  • Yes it did!

    Votes: 54 93.1%
  • No, it didn't.

    Votes: 4 6.9%

  • Total voters
    58
  • Poll closed .
2022 Update
With tModLoader now on 1.4, this tutorial is going to be inaccurate with regards to most things.
I will keep this up for posterity, and those few still on 1.3, but if you need a tutorial, please use the following:
tModLoader World Generation Tutorial

I hope this helped people while it was still useful. Good luck on whatever you're doing!





Hello everyone!

I am GabeHasWon, a fairly experienced programmer, one who happens to be very experienced in World Generation. As such, I feel that redoing this ancient tutorial that covers the basics of worldgen would be a useful thing to do. So, here I am.

Before I start on worldgen itself, I implore you to have the following basics down and good already:
* A good grasp of C# and the basic Terraria framework
* A good grasp of math, mostly algebra, trigonometry and geometry
* An incredible amount of patience - no matter how good you are, the majority of worldgen is changing minor things constantly, and you will have to make a ton of worlds in order to test your code
and finally,
* an understanding of logic, as you will need a very high amount of conditions, comparisons and adjustments to make your programming and generation work as intended

Preface
There's a lot of minutiae involved in world generation. They will constantly hang over you even as you do the most basic of structures, and are pivotal to understanding why your code does or does not work.
The most basic of these concepts are the coordinate system Terraria uses, where the position (0, 0) is the very top-left of the world. You can then use the public variables Main.maxTilesX and Main.maxTilesY in order to grab the width and height of the world, respectively.
When doing this, however, note that the playable world stops before the player can actually reach coordinate 0 on either axis - I've never tested, but the world stops scrolling maybe 40 or 50 tiles before it truly stops. Keep this in mind when you want to add stuff to the edges of the world, such as Ocean or Space content.
Refer to this for a much better visual representation of the heights in-world:
1612298483774.png


Another thing that is very important to note is generation order - in Terraria, the game uses a list of tasks called GenPasses that tell the world how to be generated in order. This is incredibly important to keep in mind - if you generate your, for example, ores too early, they could easily be overtaken by new generation that follows it. For example, I made a biome a while ago, and after a bit of testing, found that the dungeon or Lihahzrd Temple could override it, making it basically nonexistant. So, I had to move it forward in the gen list in order to not make my biome disappear.
You'll also find it easier to debug if you understand where your generation is placed in the list.
For further reference on vanilla generation steps' order, follow this list here.

Finally, something you will always have to keep in mind is that tiles are stored in a 2D array. The ramifications of that are as follows:
1. If you go outside of the bounds of the array (i.e. try to access the tile at (-1, 0)), it will crash or fail to generate;
2. If you are to use, for example, player position, you will need to divide player position by 16 in order to access the tile at the same position - for example, if I wanted to get the tile directly above the player, I would use the following code:
Framing.GetTileSafely((int)(player.position.X / 16f), (int)(player.position.Y / 16f) - 1)
The same division operation would be conducted with projectiles, NPCs, dusts and gores.
3. These tile positions are also always an integer, and never a decimal of any sort. If you try to access the tile at 1.2f, 2, you will get an error.
4. Finally, every tile is always loaded in the world, but is only active when a tile is actually placed in-world - so, if you access an air tile, you might get a non-air type (i.e. Sand), but it will be empty.

Basics
So, with all of that aside, we can begin on the most simple methods and tools you can use to create or check or do whatever:
  • WorldGen.PlaceTile(int i, int j, int type, bool mute = false, bool forced = false, int plr = -1, int style = 0)
This, as you may guess, places a single tile at i, j, of type type, plays a sound if mute is false.
As for forced - I'd like to think that it forces the tile to be placed, but I don't often use this.
As for plr - I have no idea what this is. At all. Probably not important?
Finally, style is tough to explain - it is used to show alternate versions of a single tile. I'll explain this a bit more with PlaceObject.
  • WorldGen.KillTile(int i, int j, bool fail= false, bool effectOnly = false, bool noItem = false)
Also simple - kills the tile at i, j.
If fail is true, the tile is NOT removed. This is used for when you mine a pickaxe but it needs multiple hits, for example.
If effectOnly is true, the tile ONLY spawns dust, but does not break. Usually in tandem with fail. For example, mining a tile with too low of pickaxe power.
And noItem is simple, does not drop an item when the tile is killed.
  • Framing.GetTileSafely(int i, int j)
To be completely transparent, all I know is that this is a better way of grabbing any given tile. If you are trying to grab a tile through Main.tile[x, y], I'd recommend using this instead.
This is very useful for checking a given tile's type, if it's active, or certain qualities about it.
  • WorldGen.TileRunner(int i, int j, int strength, int steps, int type, bool addTile = false, float speedX = 0, float speedY = 0, bool noYChange = false, bool overRide = true)
Alright, this is a big more complex. TileRunner is a method that, in the only way I can explain, creates a 'diamond' with noisy edges if so chosen.
Here's a more in depth explanation:
i and j are the position of the TileRunner. Again, this is in tile position. so you'd have to divide by 16 if you want to use a player or npc position to gen something.
strength is how large the resulting chunk is - the "radius" in a way.
I think a better way to explain this is visual references:
Three different examples of a TileRunner with a strength of 2:
1611985758319.png
Three different examples of a TileRunner with a strength of 4:
1611985817752.png
Three different examples of a TileRunner with a strength of 8:
1611985961872.png
Two different examples of a TileRunner with a strength of 16:
1611986005783.png
And finally, two different examples of a TileRunner with a strength of 32:
1611986233247.png
For reference, every TileRunner there was exactly the following line:
C#:
WorldGen.TileRunner((int)(Main.MouseWorld.X / 16f), (int)(Main.MouseWorld.Y / 16f), STRENGTH, 5, TileID.Dirt, true, 0, 0, false, true);
Where STRENGTH = the strength value showcased.

step is a bit more confusing to me - as far as I'm aware, it's the amount of repeats, of loops, you do on this TileRunner call. This you to place stuff in a line if need be using speedX and speedY, explained after addTile.
addTile tells the TileRunner if you want to add tiles or not. If you set this to true, it will place new tiles. If not, it will only replace old tiles, as long as overRide is set to true.
speedX and speedY refer to the displacement of the new chunk made after a loop. For example, if I have a TileRunner of any size, in any position, with 3 steps and a speedX of 5 and a speedY of 0, it will place 3 chunks, each 5 blocks apart, starting from the original position (i, j) and going right. Alternatively, if I set speedX to a negative, it'll start at (i, j) and go left. Same principle applies to speedY; just that negative speedY goes up, and positive speedY goes down, respective to (i, j). This might be a bit of a wordy explanation, but it should make sense if you mess around with it a tad.
noYChange is...odd. I've not tested it ever, but I'm to guess it just makes the TileRunner ignore speedY. I dunno. Just keep this to false I guess.
and finally, overRide. This, when true, replaces existing tiles with the tile of your type if possible. For example, if I'm placing my ore, BananaOre, I would want to set overRide to true so it'd spawn in stone and mud and dirt and stuff. Set to false when you only want to add tiles.

TileRunner is incredibly helpful for smaller scale chunks of a tile, such as ore deposits (ore being one of the most common uses for TileRunner), sand, dirt and stone chunks, and similar things. However, I'd recommend against using this for large scale biomes and structures, as it's really hard to use when you want to fill an area completely without being inefficient. Similarly, it's also very hard to control exactly how you want.
  • WorldGen.digTunnel(int i, int j, float xDir, float yDir, int Steps, int Size, bool Wet = false)
Now, imagine TileRunner, but it removes tiles. This is that. It works functionally the same, just kills tiles.
The only difference is what Wet does; that places water in the tunnel it digs. Simple enough.

Positioning
With all those methods in mind, the biggest problem I see for people doing generation is positions. Where do I put my structure to have it in <x> biome? Where's the sky? Where's the surface? These are all valid questions, which thankfully, are quite easy to solve - especially when you've been doing gen as long as I have.

You have the five major values -
  1. 0, the very top of the world;
  2. Main.worldSurface, the surface of the world and the point at which going below is considered "underground";
  3. Main.rockLayer, the deeper caves of the world and the point at which going below is considered "caverns";
  4. Main.maxTilesY - 200, or the Underworld layer, at which point going below means you're in the Underworld;
  5. and finally Main.maxTilesY, the bottom of the world.
Using any combination of these allows you to make sure that your given structure or biome or whatever it may be could spawn exclusively within a specific area, such as only in the Underworld, or just under the surface, for example. Use these wisely.

As for X coordinates, it's a bit more ambiguous, with only four major values (that I've used) -
  1. 0, the very left of the world;
  2. Main.maxTilesX / 2, the centre of the world;
  3. Main.maxTilesX, the very right of the world;
  4. and finally, Main.dungeonX. This value can be to the left of or to the right of the centre of the world, which allows you to know the position of the snow and jungle biomes. If Main.dungeonX is LESS THAN Main.maxTilesX / 2, the snow biome and the dungeon are to the left of spawn. Otherwise, they are to the right of spawn. Note that dungeonX may not be set if used before the Dungeon generation step.
This also allows you to generally guess where places and biomes will be.
Of note is also the variable WorldGen.UndergroundDesertLocation, a Rectangle. This stores the top-left corner of the Underground Desert through WorldGen.UndergroundDesertLocation.Location, and the size through WorldGen.UndergroundDesertLocation.Size(). This is useful in situations like Calamity's Sunken Sea, or Starlight River's Vitric Desert biomes.

Gen Passes, Cont.
Now for passes themselves.
GenPasses are, again, the way that Terraria handles world generation. It runs GenPass by GenPass in order, which builds the world piece by piece. These passes are as large as the whole dungeon, or as small as adding sand in early worldgen. It just matters on how you want to partition it.

GenPasses themselves end up being one of the most simple things to use, in all honesty.
Under the ModifyWorldGenTasks method, shown here,
C#:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
you simply add your method or even code directly into a new task, as shown here,
C#:
tasks.Add(new PassLegacy("My Custom Generation", MyGenCode));
and all you need to do is make a method called MyGenCode with a GenerationProgress parameter, such as this,
C#:
public void MyGenCode(GenerationProgress p)

However, in most cases, you do not want to Add() your gen pass to the tasks list.
Usually, you want to insert your pass somewhere specifically, as described in the "Generation Order" subsection of the Preface. For example,
Code:
            int shiniesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Shinies"));
            if (shiniesIndex != -1)
                tasks.Insert(shiniesIndex + 1, new PassLegacy("MyGenPass", MyGenPass));
This would insert your generation right after the Shinies step, which is a step most often used to place ores.
Again, you can find the names of all vanilla passes here.

You can organize your worldgen into as many (or as little) genpasses as you want, but, I do recommend trying to keep them in different steps as you see fit. Especially for different biomes which could place in different places with different overlaps, sometimes you want a biome or structure to be placed in a different place compared to another biome you may add. Just make sure you understand where and when your biome is placed at all times, and you should be good.

Chests
(Suggested by @-=Soul=-)
Chests are naturally a very important part of designing a biome or structure and filling it with content.

Filling chests during worldgen (or even during play) is fairly simple:
C#:
WorldGen.PlaceChest(x, y, type, notNearOtherChests, style)
PlaceChest is a method used during worldgen that, well, places a chest. It also returns the index of the Chest object in Main.chest that tile is associated with if the chest is placed successfully. If it's not placed successfully, it simply returns -1.
So, we can do this:
C#:
int ChestIndex = WorldGen.PlaceChest(x, y, (ushort)type, false, style);
if (ChestIndex != -1)
to check if, when we place down a chest, it is successful.
Then, within the if statement, we can do something like this:
C#:
Main.chest[ChestIndex].item[0].SetDefaults(ItemID.Bananarang);
This would set the first item in the chest you've placed down to a single Bananarang.
If you want to increase the stack, simply do:
C#:
Main.chest[ChestIndex].item[0].stack = 20;
And boom, you have a stack of 20 Bananarangs.
Further manipulation of chests and their inventories just requires some logic and thought, so that about rounds this section up.

Notices & Afterword
Thanks for reading through this tutorial, unless you really wanted to read the afterword for no reason.
I'll be updating this tutorial as inspiration strikes me, or at user request (if possible), so feel free to respond to this thread with whatever you may want to know.


Now, remember:
  • I will not program your biome or structure for you.
  • I will not usually go out of my way to give you very specific information on how to generate or implement something - I'd like to keep this tutorial relatively general, as WorldGen is an art that I cannot really explain without reducing it's utility to the general public. However, that does not mean I will not sometimes find something interesting enough to tackle regardless.
  • I will not help with visual or texture-based errors; this is to be a programming-based tutorial and I'd feel that trying to add spriting to it would be difficult to balance.
  • I will add FAQ if needed.
  • I will always further remind you that this takes patience - for my mod, I've generated well over five hundred worlds and I'm guessing I have a couple hundred more to go.
  • I am just one lad, one man, and I can only do so much.
  • Finally, if something doesn't work, try to work it out a bit before coming here for help. Some problems are easily solved after a bit of thought, even if it seems difficult for a while. I, for one, know I've been stuck on many a problem despite them being as simple as a single number that's too high or the lack of a method call.
Note from 2021 Gabe: This tutorial is very outdated, and uses only the most basic of my knowledge. It also hasn't been rewritten in 5 years, so don't expect anything great here. I just wanted to keep it on this post in case people find that parts of this are missing from the main post while I redo it.

2016 Gabe:
Hello people!
It seems that there has been an explosion of World Generation in mods, and, well, I thought I'd throw whatever I can in.

Note: This tutorial is a bit complicated. You should know how to at least make a basic NPC before you read this. Or be crazy and read it anyways.

So, here will be a basic tutorial on how to make simple lines/passageways, blobs of block, or pools/mini biomes, which will come later.
Ok, let's start off now :D
First off, it'd be useful to have something to base off, so ExampleMod has a decent example (duh) with it's Well. Use that and tinker for a bit, change the water to dirt, as to get a feel for it.
Basic Blob Making
Then, once you're done turning a well into a blob, we can begin.
Go into your ModWorld.cs file add a method called ModifyWorldGenTasks()
The full method is here:
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)

Obviously, put {} around it. Now, let's start with a blob because I'm lazy.
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
{
    int genIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Micro Biomes"));
    tasks.Insert(genIndex + 1, new PassLegacy("Dirt Blob", delegate (GenerationProgress progress)
    {
         WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY - 46, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
    }));
}

Here's an explanation of what's in the TileRunner method.
Code:
TileRunner(int i, int j, double strength, int steps, int type, bool addTile = false, float speedX = 0f, float speedY = 0f, bool noYChange = false, bool overRide = true)
So, I and J is X and Y, respectively. Strength decides how big it is (I can't understand the code enough to give a presise measurement.) Type is the type of tile, in TileID, int, or mod.tiletype. Add Tile checks if you're adding tiles or replacing them. SpeedX and Y sets the direction it goes is (also don't understand the code). noYChange is just that. It doesn't change Y. overRide means it can override other tiles.

That should place a blob of dirt above the player. You can replace the TileID with any other ID or mod.TileType("") if you wish.
That is the simplest of the things you can possibly do.

I'll keep the above code for future inserts, so I don't have to re-write it over. And over. And over again :D
So when I say something of this sort: Add code into your existing method, it means add the code into the Dirt Blob thing :D
Making a Line
Now for something a bit less...blobby.

I personally did this in a method as to make it easier to randomize, but you may do whatever you want.
So, there is a method in WorldGen called PlaceTile. It's a more precise way of using TileRunner.
Here is the method.
Code:
WorldGen.PlaceTile(int X, int Y, int TileType);
Please note that it places in tile positions, so if you want to place it in game at, say, npc.position.X, do npc.position.X / 16.

So, we use a for loop to make a straight line, like this:
Code:
for (int i = 0; i < 10; i++)
{
    WorldGen.PlaceTile(Main.spawnTileX + i, Main.spawnTileY - 30, TileID.Iron);
}

If you add that, it should make a 10 block long iron ore thing. I might've gotten the TileID wrong, but you get the point.
Capture 2016-08-03 09_47_40.png

Now let's get to the really fun stuff.
Overriding a Biome
Are you tired of having Jungles in your world? Don't Jungle Bats bother you when you're setting up your mud hut? Well, I got the fix for you! Code. yay?
Anyways, yes, you can remove biomes and put a bunch of whatever there.
Code:
int jungleGen = tasks.FindIndex(genpass => genpass.Name.Equals("Jungle"));
tasks[jungleGen] = new PassLegacy("More Dirt Blobs", delegate (GenerationProgress progress)
{
    WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY + 12, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
});
So now you should have no jungle (if I remembered the name correctly) and an extra blob of dirt, but below you. Do not put this is the same code block (These: { }) as the previous dirt blob, that will give an error.
Tested: it works with any proper gen step.

How to Place Multi blocks
can you post how to:
specify where in the world
how to prevent a certain world gen task
how to spawn multi tile blocks (chests tables doors etc)

EDIT: also, how to spawn structures with multi tile blocks

As shown above, people want to know how to place something such as a Table or Chair.
So, you have to use the WorldGen.PlaceTile method.
Code:
//PlaceObject(int x, int y, int type, bool mute = false, int style = 0, int alternate = 0, int random = -1, int direction = -1)[code] That's an explanation of the args.[/SPOILER]
So, this will place a modded chair in the X and Y:
[code] WorldGen.PlaceObject(Main.spawnTileX + 10, Main.spawnTileY, mod.TileType("ExampleChair"), false, 0, 0, -1, 1);
This, without testing, should place an Example Chair 10 blocks away from the player.
Placing a Chest
I've barely explored this concept; you could make a "starter chest" near spawn with some good lewt. Or, just a Meowmere. Either work.
So, you can't place chests with PlaceObject (for some reason) so you need PlaceChest. Code shown below.
Code:
WorldGen.PlaceChest(int X, int Y, int type, bool noNearOtherChests = false, int style = 0);
So, basic explanation of what those do: X and Y is duh. Type is what chest type. notNearOtherChests makes it so you can't place a chest there if it's near another. Style is what frame.X is should be at, used for placing locked chests.
So, just do
Code:
WorldGen.PlaceChest(Main.spawnTileX - 10, Main.spawnTileY, 21, false, 2);
for a chest to appear next to the player. Not sure what chest though, the chest tilesheet is the longest thing ever. (Needs testing)
Making a Meteor-like biome
SadCube said:
Hey, nice tutorial! But how to make something like meteorite biome?
Easy enough ;)
Code:
        public void OreComet()
        {
            int x = Main.rand.Next(0, Main.maxTilesX);
            int y = Main.worldSurface - 200;
            int[] tileIDs = { 6, 7, 8, 9 , 166, 167, 168, 169};
            if (Main.tile[x, y].type <= -1)
            {
                y++;
            }
            else
            {
                WorldGen.TileRunner(x, y, 2, 4, tileIDs[Main.rand.Next(tileIDs.Length)], false, 0f, 0f, true, true);
                return;
            }
        }
So, here is a method that makes a 'comet' out of any pre-hardmode ore, except Demonite, Hellstone and Crimtane. It places this anywhere above ground, with it initially spawning above the world, and doesn't place until it hits a block. This method won't do anything alone, though, you'll place it in the Kill method of a projectile, which is easiest. The projectile should call Kill OnTileCollide(). Code:
Code:
        public override void Kill()
        {
            OreComet();
        }
That should have a 0.1% chance to spawn every frame.
Have fun! :D
Floating Islands
Let's spam us some candy cane w/ red team block floating islands.

As suggested by @Jenosis ;)
REWRITTEN:
It's only clouds now, but the generation & code is much smoother.
Code:
        private void GenIsland(Point topCentre, int size, int type)
        {
            for (int i = -size / 2; i < size / 2; ++i)
            {
                int repY = (size / 2) - (Math.Abs(i));
                int offset = repY / 5;
                repY += WorldGen.genRand.Next(4);
                for (int j = -offset; j < repY; ++j)
                {
                    WorldGen.PlaceTile(topCentre.X + i, topCentre.Y + j, type);
                }
            }
        }
topCentre is the position of the, well, top and centre tile of the island. It'll be slightly under the top (around 4 blocks on a 50 tile wide island), but point stands.
size is the width. Not much more to say.
type is the TileID of the island; in the following screenshot, it's TileID.Clouds.
Capture 2018-08-30 13_29_20.png

I am willing to create a more functional floating island with dirt, grass, and the like, but for now this should be enough. It's much more efficient too.

Change any of the TileIDs to your liking. Have fun! :D
Placing a Tree, and growing the Tree
This one is pretty simple, really. I'll just slap in some code and done :p
Code:
WorldGen.PlaceTile(X, Y, TileID.Dirt);
do that as a base. Make it 3 wide, so the tree will go properly.
Then:
Code:
WorldGen.PlaceObject(X, Y - 1, mod.TileType("MagicSapling));
WorldGen.GrowTree(X, Y - 1);
This will grow the MagicSapling if it can. Otherwise, it'll simply place a sapling.
Notify me on this thread/my profile page if this doesn't work. Thanks!
Placing Walls
It's basically the same as placing a tile. But with walls. Woah.
Here's two:
Code:
WorldGen.PlaceTile(int i, int j, int type)
or
Code:
Main.tile[i, j].wall = WallID.MudUnsafe;
Simple enough :p
Changing Tile Slopes
Also simple.
Code:
Main.tile[i, j].slope(0);
From what I know, it goes from 0 to 12. Tell me if I'm wrong.

TileIDs can be found here: tModLoader/tModLoader

Some useful (ints) things for WorldGen are Main.maxTilesY, same thing but with X, Main.spawnTileY, and X.
Main.spawnTileX +/- 300-400 is the Snow/Desert biome. Main.maxTilesY - 200 is the top of the Underworld.

The amount of derps done here: 11 so far.

I will expand this upon user request, though I won't do your WorldGen for you.
Anyways, that'll be it for now. Leave any comments/questions/suggestions below :D
Credits
Thanks to @Graydee for being helpful with worldgen on occasion;)
Thanks to @EchoNex for the first WorldGen code he gave me.
Thanks to @jopojelly for random helps :D

I request that anyone who uses this tutorial and publishes it in any way, Mod Browser or not, gives me any sort of credit. Either it be a link to this thread, a link to me, a simple "thanks to gabe for some worldgen stuff", please do it :D
 
Last edited:
wooooooo thanks gabe this is amazing please expand. keep it up. I am forever in your debt. (this may sound crazy but ive been playing with world generation to no avail)
 
Last edited:
I tested it, and all (except the Jungle override) work fine now. :D
can you post how to:
specify where in the world
how to prevent a certain world gen task
how to spawn multi tile blocks (chests tables doors etc)

EDIT: also, how to spawn structures with multi tile blocks
 
Sure! I'll do all except specify where, as that is just putting the right X and Y coordinates, though I'll put a small list of X and/or Y locations for a little help ;)

Edit: Updated the thread!
 
Last edited:
Sure! I'll do all except specify where, as that is just putting the right X and Y coordinates, though I'll put a small list of X and/or Y locations for a little help ;)

Edit: Updated the thread!
wanna add pictures :p like, one of each one, currently you only have the line one
 
Um Gabe, i've done all of the three tutorials but I have a few questions in this
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
{
    int genIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Micro Biomes"));
    tasks.Insert(genIndex + 1, new PassLegacy("Dirt Blob", delegate (GenerationProgress progress)
    {
         WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY + -46, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
    }));
}
1. What is the 6 for "after the Main.spawnTileY + -46" is it for randomization, width, or what
2. after Main.rand.Next( what do the 1 and 3 do

These are simple questions; I just need to know what they do for future mistakes


and thank you for the great tutorial
 
Um Gabe, i've done all of the three tutorials but I have a few questions in this
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
{
    int genIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Micro Biomes"));
    tasks.Insert(genIndex + 1, new PassLegacy("Dirt Blob", delegate (GenerationProgress progress)
    {
         WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY + -46, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
    }));
}
1. What is the 6 for "after the Main.spawnTileY + -46" is it for randomization, width, or what
2. after Main.rand.Next( what do the 1 and 3 do

These are simple questions; I just need to know what they do for future mistakes


and thank you for the great tutorial

The 6 after the Main.spawnTileY + -46 is the strength, so if you make it larger, the blob will also get much larger.
The Main.rand.Next after the strength are the steps, which makes it look more natural. It's just to make it seem nice.

Also, thanks! :D
 
I don't know why this tutorial isn't more popular. It's a l really helpful resource and I hope to see it gain popularity. Thanks so much. It helped me a lot and I wish there was something like this for ai as well. Lol XD.
 
Last edited:
The 6 after the Main.spawnTileY + -46 is the strength, so if you make it larger, the blob will also get much larger.
The Main.rand.Next after the strength are the steps, which makes it look more natural. It's just to make it seem nice.

Also, thanks! :D
Ok Thanks!

I've really messed up the dirt blob, instead of a small plot I made a huge 300 block wide abomination that goes past the top of the map

Edit- also the placetile method isn't seeming to work for me
 
As in the example I gave, or just the method itself? If it's the method, I have to see the code. Start with a blatantly obvious thing, like a Hellstone Brick right next to spawn:
Code:
WorldGen.PlaceTile(Main.spawnTileX + 5, Main.spawnTileY, TileID.HellstoneBrick);
 
As in the example I gave, or just the method itself? If it's the method, I have to see the code. Start with a blatantly obvious thing, like a Hellstone Brick right next to spawn:
Code:
WorldGen.PlaceTile(Main.spawnTileX + 5, Main.spawnTileY, TileID.HellstoneBrick);
the example, ill show the code in a sec
 
GabeHasWon I finally figured out how everything works; the for loops and the x and y ints

but I'm having one tiny problem

how do you place a tree


p.s. like AXsmasher said, "I am forever in your debt"
 
any chance there could be sky and surface generations? (like genning small/medium patches of mushroom biome in the sky and on the surface)
 
Can you help with ore gen?
I know how to make it generate, but don't know how to modify its spawn height and amount.
Here is the code I have at the moment

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.World.Generation;
using Microsoft.Xna.Framework;
using Terraria.GameContent.Generation;

namespace PandaMod
{
    public class ModWord : ModWorld
    {
        private const int saveVersion = 0;
        public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
        {
            int ShiniesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Shinies"));
            if (ShiniesIndex == -1)
            {
                return;
            }
            tasks.Insert(ShiniesIndex + 1, new PassLegacy("Custom Mod Ores", delegate(GenerationProgress progress)
            {
                for (int k = 0; k < (int)((double)(Main.maxTilesX * Main.maxTilesY) * 6E-05); k++)
                {
                    WorldGen.TileRunner(WorldGen.genRand.Next(0, Main.maxTilesX), WorldGen.genRand.Next((int)WorldGen.worldSurfaceLow, Main.maxTilesY), (double)WorldGen.genRand.Next(6, 8), WorldGen.genRand.Next(6, 8), mod.TileType("PandaBlockOre"), false, 0f, 0f, false, true);
                }

            }));
        }
    }
}


Hope you can help!
 
Code:
WorldGen.TileRunner(WorldGen.genRand.Next(0, Main.maxTilesX), WorldGen.genRand.Next((int)WorldGen.worldSurfaceLow, Main.maxTilesY)
That snipped is the first two arguments, along with the method itself.
Change those two, to whatever. Currently, it places the ore anywhere in the world
Code:
WorldGen.genRand.Next(0, Main.maxTilesX) //the X
and anywhere below the surface
Code:
WorldGen.genRand.Next((int)WorldGen.worldSurfaceLow, Main.maxTilesY)//The Y
Hope that helped! :D
 
Last edited:
Thanks. So if I wanted to it to spawn at the bottom of the cavern layer, what would I put. I tried to do but it failed. Also, how would I change the amount that spawned?

Thanks!
 
Also, how would I change the amount that spawned?
Code:
for (int k = 0; k < (int)((double)(Main.maxTilesX * Main.maxTilesY) * 6E-05); k++)
Change any of this part: (int)((double)(Main.maxTilesX * Main.maxTilesY) * 6E-05, or if you want a precise number, just do:
Code:
for (int k = 0; k < 50; k++)
That would make exactly 50 ore patches spawn.
So if I wanted to it to spawn at the bottom of the cavern layer, what would I put.
These two variables are all I could find: rockLayerLow and rockLayerHigh. So do:
Code:
WorldGen.TileRunner(WorldGen.genRand.Next(0, Main.maxTilesX), WorldGen.genRand.Next((int)WorldGen.rockLayerHigh, WorldGen.rockLayerLow), (double)WorldGen.genRand.Next(6, 8), WorldGen.genRand.Next(6, 8), mod.TileType("PandaBlockOre"), false, 0f, 0f, false, true);
That should make it spawn in an about 200, 325 or 400 (Small World, Medium World, and Large World, respectively) area.
 
Back
Top Bottom