Skip to content
This repository has been archived by the owner on May 5, 2021. It is now read-only.

Shape Grammars

GTD-Carthage edited this page Jul 17, 2018 · 9 revisions

Shape grammars are a method of procedural generation that Oblige 7.x relies on to create its new rooms. Shape grammars offers a balance between entirely computer-generated architecture and human design by allowing a user to input set of rules and products for which the procedural generation is restricted to, creating a balance of patterns that is still seemingly human-created.

I'm Here to Mod Oblige, Not To Become a Linguistics Expert!!!

Imagine building something with Lego blocks. When you start from nothing, you virtually have the option of using any block at all as a basis for constructing whatever. As you continue, the amount of possible blocks you can use drastically decreases - for example, you can't place a 2x8 brick over a slope - if you do, the rest of the block will be hanging off the side. If you used the slope block as your first block, your options for what block to place are limited. If you used a brick as your first option, you can keep stacking bricks until it ends in a slope again.

In this sense, we defined a rule and an effect for that rule.

  1. Place an initial 2x8 brick or slope block.
  2. If there are free 2x8 bricks remaining, we can stack more 2x8 bricks or place a slope block.
  3. If you place a slope block, that ends your construction.

Now imagine Oblige carving out rooms in a similar manner.

How Oblige Does It

Oblige's shape rules can found in scripts/rules.lua for all 7.x release except for the last, 7.70, where it is instead found inside games/<game_name>/shapes.lua.

Each rule at minimum contains a probability and a structure. An example:

GROW_SAMPLE_RULE =
{
  prob = 50
  
  structure = -- This rule essentially tells Oblige to look for an area with two bare floor spaces, and expands it 3-seeds (see Oblige glossary - a seed is a 128x128 grid section) farther.
  {
    "..","11"
    "..","11"
    "..","11"
    "11","11"
  }
}

The structure contains a matrix of symbols, signifying rooms and their elements seen from above. The left side of the structure is the matching pattern, the right side is the change to be made if this rule is picked.

The name of this rule is also significant - Oblige identifies what sort of action to perform given the elements by checking if the name has the string "ROOT", "EXIT", "GROW", "SPROUT", and "DECORATE".

Rule Patterns and Elements

Here are the various symbols used in both the pattern match and effect, as far as they can be known via example.

Basic Elements

  • . - this element is free - it has nothing in it (no room, no stairs, no whatever).

  • ! - this element is strictly free.

  • ~ - this element is liquid.

  • # - this element is disabled. Usually used only in the effect side. This element forces this area to be walled-off, and the shape grammar cannot open it again.

  • = - this element is a bridge. A bridge prefab will later fill in this entire area. (Currently only found in park outdoors...)

  • 1, 2, 3 - this element is an open room. (Only 1 is actually used, but the other numbers can probably also be used. The numbers are likely used for matching between specific rooms - think a puzzle piece where the 'socket' is different in one side. i.e. a 2 socket can only be plugged-in by another 2)

Staircase elements

  • <, V, >, ^ - this element is a staircase. Must be strictly used in conjunction with 'A' in that the staircase must end in an A element. See the A element below.
  • S - this element is a staircase, but without a defined direction. (there's no example on how to use this, but this was probably used for things like spiral staircases, as the code comment suggests defining some sort of info table for it)

'Magic' (match-only) elements

  • x - This element is a wildcard. It can be anything, such as an open space or walled off. It is usually used to allow shapes to have some wiggle room in connecting to others. If this element is used in the pattern match side, it cannot be changed and must also appear as-is in the same place in the right-hand side. There are other match elements but they don't have examples in use.

Special elements

  • A - effect-only. This element specifies the beginning of a new area in the same room. A new area possesses new floor, ceiling heights, textures, etc.
  • R - effect-only. This element specifies the beginning of a new room entirely. The new room will have different wall textures, monster setups, possibly locked behind a quest (switch or key), can become a cave, outdoor area, etc. This is usually used to specify a new room entirely exists behind a joiner or so.
  • C - this element is to be a monster cage.
  • J - this element is to be a joiner. Joiners are eventually replaced by joiner prefabs.
  • T - this element is a closet. Secrets, item closets, exit closets, trap closets, and start closets are eventually rendered in place.

Diagonals

  • / - this element specifies this is a diagonal transitioning between two kinds of elements. (running from lower-left to upper-right)
  • % - this element specifies this is a diagonal. (running from upper-left to lower-right)

Diagonals require specification on what the diagonal transitions to by declaring a diagonals = {} struct. For example, assume the following room:

structure =
{
  ".....","11111"
  ".....","1/~%1"
  ".....","1~~~1"
  ".....","1%~/1"
  "x111x","x111x"
}

This room specifies four diagonals - the diagonals struct will probably look like this:

diagonals =
{
  "1~","~1" -- Specify the diagonal's attributes in the order of them being read left-right, top-down.
  "1~","~1" -- This means the first diagonal will transition from an open room to a liquid.
}

Rule Actions

  • ROOT - Oblige will pick a ROOT shape first out of all other shapes to start from.
  • EXIT - Oblige will pick an EXIT shape to terminate the map.
  • GROW - Oblige will use this rule to grow new shapes from a ROOT and other GROWn shapes.
  • SPROUT - Oblige will use this rule as a lower priority from GROW.(?)
  • DECORATE - Oblige will use this rule as a lower priority from SPROUT.(?)

Think of an artificial Christmas tree - you place the base first (ROOT), attach the stem and branches from there (GROW), attach the plastic leaves (SPROUT), attach the lights and Christmas balls (DECORATE), and add a star on top as a finish. (EXIT)

Tips and Common Errors

Shape Openness

Much like the example regarding Lego slope bricks above, it is best for shapes to have as many plain borders as possible so it has more possibilities for matching against more shape rules. Oblige can accidentally close off a room with a dead ends, forcing the map to become smaller (and therefore terminate early)

No Outdoor Liquid Borders

Liquid tiles apparently cannot be used in the edge of any right-hand side of a rule unless the rule is strictly used indoors (env = "!outdoor"). Oblige doesn't seem to support resolving how a liquid from another room borders against an outdoor park. For a liquid tile to be used for outdoor shapes, it must be closed off from the edge by an extra non-liquid space.