Tutorial 6 (Predefined runs)
r++ comes with a set of common runs, which can be used to quickly create basic automappers, without having to worry about the logic.
Unlike the functions we've used so far, predefined runs don't take any arguments. Instead we set them up beforehand:
Filter().SetIndices(1, 3, 5);
Run().Filter(); // this run is gonna filter tiles 1, 3 and 5
One thing to note here, is that calling a run resets its state. If we let's say wanted to filter the same tiles again, we would need to set them once more:
Filter().SetIndices(1, 3, 5);
Run().Filter();
// no tiles are set at this point, we need to set them again
Filter().SetIndices(1, 3, 5);
Run().Filter();
All of the predefined runs follow this principle.
Leaves specified tiles and removes the rest.
Sets the tiles to filter.
Filter().SetIndices(1, 3, 5);
Default: empty
Filter().SetIndices(red, green);
Run().Filter();
Randomizes tiles over the specified filler. If probabilities do not add up to a 100, the filler will be present after the run.
Sets the tiles to randomize.
Randomize().SetIndices(1, 2, 3);
Default: empty
Sets the filler tile.
Randomize().SetFill(1);
Default: g:mask.N
Sets the spacing between the tiles.
Randomize().SetSpacing(5);
Default: 0
Sets whether or not to include edges.
Randomize().SetIncludeEdges(false);
Default: true
Sets the tiles to randomize over.
Randomize().SetTestIndices(1, 3, 5);
Default: empty
Sets the probabilities for each tile. By default tiles are uniformly distributed.
Randomize().SetChance(1, 30, 69);
Default: empty
Randomize().SetIndices(red, green);
Randomize().SetFill(blue);
Randomize().SetTestIndices(yellow);
Randomize().SetChance(25);
Run().Randomize();
Moves tiles by the specified offset.
Sets the offset by which to move tiles.
Shift().SetOffset([21, 37]);
Default: [0, 0]
Sets the tiles to shift.
Shift().SetIndices(1, 3, 5);
Default: empty
Shift().SetOffset([-1, -1]);
Shift().SetIndices(red);
Run().Shift();
Creates a check pattern over non empty tiles.
Sets the size of the individual checker.
Checkerboard().SetSize([3, 3]);
Default: [1, 1]
Sets the tiles to fill white and black checkers with.
Checkerboard().SetIndices(1, 2);
Default: g:mask.N
, g:mask.V
Checkerboard().SetSize([2, 1]);
Checkerboard().SetIndices(red, green);
Run().Checkerboard();
Builds a border around the shape.
Sets the tile for a wall. We can choose 1 out of 4 walls: top
, left
, bottom
, right
.
Border().SetWall(red, top);
Border().SetWall(red, bottom);
Default: -1
Sets the tiles for all walls by rotating the given tile. We can choose 1 out of 4 walls: top
, left
, bottom
, right
.
Border().SetWallFrom(1, top);
Default: -1
Sets the tile for an outer corner. We can choose 1 out of 4 corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetOuter(red, topLeft);
Border().SetOuter(red, bottomRight);
Default: -1
Sets the tiles for all outer corners by rotating the given tile. We can choose 1 out of 4 corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetOuterFrom(1, topLeft);
Default: -1
Sets the tile for an inner corner. We can choose 1 out of 4 corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetInner(red, topLeft);
Default: -1
Sets the tiles for all inner corners by rotating the given tile. We can choose 1 out of 4 corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetInnerFrom(1, topLeft);
Default: -1
Sets the tile for a diagonal inner corner. We can choose 1 out of 2 diagonals: topLeft
or bottomRight
, topRight
or bottomLeft
.
Border().SetDiagonal(red, topLeft);
// same as
Border().SetDiagonal(red, bottomRight);
Default: -1
Sets the tiles for all diagonal inner corners by rotating the given tile. We can choose 1 out of 2 diagonals: topLeft
or bottomRight
, topRight
or bottomLeft
.
Border().SetDiagonalFrom(1, topLeft);
// same as
Border().SetDiagonalFrom(1, bottomRight);
Default: -1
Sets the tile for an I shape. We can choose 1 out of 2 orientations: vertical
, horizontal
.
Border().SetIShape(red, vertical);
Default: -1
Sets the tiles for all I shapes by rotating the given tile. We can choose 1 out of 2 orientations: vertical
, horizontal
.
Border().SetIShapeFrom(1, vertical);
Default: -1
Sets the tile for a U shape. We can choose 1 out of 4 orientations: top
, left
, bottom
, right
.
Border().SetUShape(red, left);
Border().SetUShape(red, right);
Default: -1
Sets the tiles for all U shapes by rotating the given tile. We can choose 1 out of 4 orientations: top
, left
, bottom
, right
.
Border().SetUShapeFrom(1, left);
Default: -1
Sets the tile for an L shape. We can choose 1 out of 4 orientations: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetLShape(red, bottomLeft);
Default: -1
Sets the tiles for all L shapes by rotating the given tile. We can choose 1 out of 4 orientations: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetLShapeFrom(1, bottomLeft);
Default: -1
Sets the tile for a T shape. We can choose 1 out of 4 orientations: top
, left
, bottom
, right
.
Border().SetTShape(red, top);
Border().SetTShape(red, bottom);
Default: -1
Sets the tiles for all T shapes by rotating the given tile. We can choose 1 out of 4 orientations: top
, left
, bottom
, right
.
Border().SetTShapeFrom(1, top);
Default: -1
Sets the tile for a shape transitioning from a wall to an I shape. We can choose 1 out of 4 walls: top
, left
, bottom
, right
.
Border().SetWallToIShape(red, top);
Default: -1
Sets the tiles for all shapes transitioning from a wall to an I shape, by rotating the given tile. We can choose 1 out of 4 walls: top
, left
, bottom
, right
.
Border().SetWallToIShapeFrom(1, top);
Default: -1
Sets the tile for a shape transitioning from an outer corner to an I shape. We can choose 1 out of 4 outer corners: topLeft
, bottomLeft
, topRight
, bottomRight
, combined with 1 out of 2 orientations for an I shape: vertical
, horizontal
.
Border().SetOuterToIShape(red, topRight, horizontal);
Default: -1
Sets the tiles for all shapes transitioning from an outer corner to an I shape, by rotating the given tile. We can choose 1 out of 4 outer corners: topLeft
, bottomLeft
, topRight
, bottomRight
, combined with 1 out of 2 orientations for an I shape: vertical
, horizontal
.
Border().SetOuterToIShapeFrom(1, topRight, horizontal);
Default: -1
Sets the tile for a shape transitioning from an outer corner to both I shapes. We can choose 1 out of 4 outer corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetOuterToDoubleIShape(red, topLeft);
Default: -1
Sets the tiles for all shapes transitioning from an outer corner to both I shapes, by rotating the given tile. We can choose 1 out of 4 outer corners: topLeft
, bottomLeft
, topRight
, bottomRight
.
Border().SetOuterToDoubleIShapeFrom(1, topLeft);
Default: -1
Sets the tile for a cross shape.
Border().SetCross(red);
Default: -1
Sets the tile for a dot shape.
Border().SetDot(red);
Default: -1
Sets the filler tile.
Border().SetFill(1);
Default: -1
Sets the tiles to test for when building a border.
Border().SetTestIndices(1, 3, 5);
Default: empty
Border().SetWallFrom(red, top);
Border().SetOuterFrom(green, topLeft);
Border().SetInnerFrom(blue, topLeft);
Run().Border();
Builds all objects inserted using InsertObject
.
InsertObject(blue:2x2, red:2x2).If(
Object().HasSpace().TestIndices(yellow)
).Roll();
Run().FillObjects();
In this example we will remake the grass_main
automapper from Tutorial 4.2 and make use of predefined runs.
We will start with a Border
run. Instead of writing a bunch of rules ourselves, we will simply set up tiles for each part of the border we're interested in:
Border().SetFill(dirt);
Border().SetWall(wall:top, top);
Border().SetWall(wall:right, right);
...
Border().SetOuter(outer:topLeft, topLeft);
Border().SetOuter(outer:topRight, topRight);
...
Border().SetInner(inner:topLeft, topLeft);
Border().SetInner(inner:topRight, topRight);
...
This approach gives us the exact same result, while also being less error-prone and much easier to read.
After we're done setting up our tiles, we simply create a run:
Run().Border();
Note: calling
NewRun
beforehand is not required.
Now that we have our border in place, we can proceed to randomizing bones. To do that, we will make use of a Randomize
run. Let's set it up in a way, that gives us a nearly identical result:
Randomize().SetIndices(bone:1, bone:2, bone:3, bone:4, bone:5);
Randomize().SetFill(dirt);
Randomize().SetTestIndices(dirt);
Randomize().SetChance(0.4);
Randomize().SetSpacing(1);
Randomize().SetIncludeEdges(false);
Now all that's left to do, is to create a run:
Run().Randomize();
And that's it. Without writing a single bit of logic, we've created a fully functional automapper.
#include "base.r"
#output "grass_main.rules"
int dirt = 1;
int bone:1 = 2;
int bone:2 = 3;
int bone:3 = 66;
int bone:4 = 67;
int bone:5 = 68;
int wall:top = 16;
int wall:right = 17;
int wall:bottom = 18;
int wall:left = 19;
int outer:topLeft = 32;
int outer:topRight = 33;
int outer:bottomRight = 34;
int outer:bottomLeft = 35;
int inner:topLeft = 48;
int inner:topRight = 49;
int inner:bottomRight = 50;
int inner:bottomLeft = 51;
AutoMapper("GrAss");
// place walls
Border().SetFill(dirt);
Border().SetWall(wall:top, top);
Border().SetWall(wall:right, right);
Border().SetWall(wall:bottom, bottom);
Border().SetWall(wall:left, left);
Border().SetOuter(outer:topLeft, topLeft);
Border().SetOuter(outer:topRight, topRight);
Border().SetOuter(outer:bottomRight, bottomRight);
Border().SetOuter(outer:bottomLeft, bottomLeft);
Border().SetInner(inner:topLeft, topLeft);
Border().SetInner(inner:topRight, topRight);
Border().SetInner(inner:bottomRight, bottomRight);
Border().SetInner(inner:bottomLeft, bottomLeft);
Run().Border();
// randomize bones
Randomize().SetIndices(bone:1, bone:2, bone:3, bone:4, bone:5);
Randomize().SetFill(dirt);
Randomize().SetTestIndices(dirt);
Randomize().SetChance(0.4);
Randomize().SetSpacing(1);
Randomize().SetIncludeEdges(false);
Run().Randomize();