Skip to content

05. Selecting tiles

When we want to place something in a room, be it an enemy or a shrine, we need to make sure that the tile we select is valid - we don't want to place something on top of a wall or another entity. Because of this, there exists a tile selection system.

The TileRequirements interface

There exists an object type with a whole lot of properties, called LibLevelGen.TileRequirements. If you take a look at it in the link above, you'll notice that there really is a lot! But don't worry, all of them are actually optional, so you only need to specify the ones relevant to you.

Let's see how to use it based on some examples; we'll start with this as our initial code, which is more or less what you should have after the previous part (I didn't paste it here directly because it's getting long).

We'll use the Room:chooseRandomTile method here, which returns a random tile from the ones matching the requirements in the room:

local function placeEnemies(currentRoom)
    local selectedTile = currentRoom:chooseRandomTile {
        isFloor = true,
        hasEntity = false
    }
    -- In our case, we're sure that there's at least 1 tile
    -- that fulfils the reqs, but this may not always be true!
    selectedTile:placeEntity("Skeleton", 2)
end
skelly.png

The Skeletons don't start in the corners anymore! We can actually write it in a few less lines of code:

local function placeEnemies(currentRoom)
    -- This also does the nil check for us
    currentRoom:placeEntityRand({
        isFloor = true,
        hasEntity = false
    }, "Skeleton", 2)
end
as I said, I'm lazy

Generally, writing out the requirements every time you need them may not be the best idea; it's better practice to define a variable containing the requirements so that they can be easily reused. Speaking of which...

The helper table

Most of the time you do not actually need to write out the tile requirements yourself, because there already exists a decent collection of them built-in! We just need to add a require to use it:

-- naming it like this to avoid confusion with the Util
-- module from the base game.
local levelgenUtil = require "LibLevelGen.Util"

-- An alias because this name is too long to write every time
local tr = levelgenUtil.TileRequirements
Now we can go ahead and use it:
local function placeEnemies(currentRoom)
    currentRoom:placeEntityRand(tr.Enemy.Generic, "Skeleton", 2)
    currentRoom:placeEntityRand(tr.Enemy.OnWall, "Spider")
end
This is generally the best way to place entities in most cases. Methods using TileRequirements also include:

  • Tile:meetsRequirements, which checks the given tile and returns a boolean,
  • Room:selectTiles, which returns all tiles that meet the requirements in the room,
  • Room:chooseRandomTile, which returns a random tile matching the requirements,
  • Room:chooseRandomTiles, which returns a given amount of tiles,
  • Room:placeEntityRand, which places an entity on a random tile,
  • Room:spreadTile, which is used for placing things such as water or hot coals.

...and that's basically it. There isn't much more to talk about here, tile requirements are a pretty simple mechanism, but they can greatly simplify your code.

As a bonus, you can add a mainSegment:setTileset("Zone2") call right after creating the segment, since all these Zone 1 tiles are getting boring. This will make all placed tiles in the segment use the Zone 2 tileset as the default.