TerrainGraphicsTutorial

From The Battle for Wesnoth Wiki

Attention: This page has been marked for review for version 1.4. The information contained here appears to be outdated or obsolete.

If you can, please take the time to review and edit it to bring it up to date (if needed) for the lastest version of Wesnoth. For more information and discussion, check the appropriate thread in the fora.

Once this is done, remove this notice


Mordante: Please check that the translation from single-letter to multi-letter terrain codes is correct. The map strings in the examples of rotation contain 'g' and are thus almost certainly wrong. The section on Cumulative Probabilities also needs careful checking

Terrain Graphics tutorial

The [terrain_graphics] tag describes a terrain graphics rule, which associates a set of images to a given terrain configuration. Those are used to define how to translate a map into a set of bitmap images which will be displayed to the user.

[terrain_graphics] WML tags may be either top-level tags, or defined as direct children of scenarios.

Defining a rule

To define a terrain graphics rule, just add one [terrain_graphics] element. The simplest terrain_graphics rule looks like this:

[terrain_graphics]
[/terrain_graphics]

Of course, this rule does absolutely nothing, so it is completely useless.

Adding constraints to rules

For rules to do anything useful, one must first add some conditions which will specify where they will match. This is done using the [tile] WML tag. [tile] WML elements define what we will name, in the rest of this document, a "constraint".

For example, the following WML code adds a constraint to our empty rule:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
 [/terrain_graphics]

Let's describe the elements defined inside this WML tag:

  • x and y define the offset of the constraint.
  • type defines the type of the terrain which will be matched.

Suppose that the terrain map is the following one (the letter inside the hexes representing the terrain type):

  __    __
 /Gg\__/Gg\
 \__/Mm\__/
 /Gg\__/Ww\
 \__/Ww\__/
 /Ww\__/Ww\
 \__/  \__/

The rule we defined will match on each terrains marked "Gg"

What is the use of those "offsets", then? Those allow for a rule to match, a combination of terrains and not a single terrain. Suppose, for example, we want the rule to match the following terrain configuration:

  __ 
 /Gg\__
 \__/Ww\
    \__/

To achieve this, we will define the rule like this:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
    [tile]
       x=1
       y=0
       type=Ww
    [/tile]
 [/terrain_graphics]

Here, this rule has 2 constraints:

  • The first one which specifies that the terrain at the offset (0, 0), should be of type "Gg"
  • The second one which specifies that the terrain at the offset (1, 0) should be of type "Ww"

The hex coordinate system

To reference hexes with a system of 2 coordinates, the Wesnoth map model is used. The top-left hex is numbered (0, 0), then the hex immediately to its SE side is numbered (1, 0), then the hex immediately to that hex's (i.e, hex (1, 0)'s) NE side is numbered (2, 0), etc. The hex immediately below the hex numbered (0, 0) is (0, 1), and so on. Here is a picture representing coordinates of hexes:

   ____        ____        ____        ____
  /    \      /    \      /    \      /    \
 / 0,0  \____/ 2,0  \____/ 4,0  \____/ 6,0  \
 \      /    \      /    \      /    \      /
  \____/ 1,0  \____/ 3,0  \____/ 5,0  \____/
  /    \      /    \      /    \      /    \
 / 0,1  \____/ 2,1  \____/ 4,1  \____/ 6,1  \
 \      /    \      /    \      /    \      /
  \____/ 1,1  \____/ 3,1  \____/ 5,1  \____/
  /    \      /    \      /    \      /    \
 / 0,2  \____/ 2,2  \____/ 4,2  \____/ 6,2  \
 \      /    \      /    \      /    \      /
  \____/ 1,2  \____/ 3,2  \____/ 5,2  \____/
  /    \      /    \      /    \      /    \
 / 0,3  \____/ 2,3  \____/ 4,3  \____/ 6,3  \
 \      /    \      /    \      /    \      /
  \____/ 1,3  \____/ 3,3  \____/ 5,3  \____/
       \      /    \      /    \      /    
        \____/      \____/      \____/

When we talk about an offset OF (xo, yo) FROM (xf, yf), we talk about the point which would be at the position (xo, yo) if (xf, yf) was (0, 0). This is *not* always the sum of coordinates! For example, the offset (1,0) from (2,0) is (3,0), but the offset (1, 0) from (3, 0) is (4, 1)

Matching several terrains with Type strings

What if we want a constraint to be able to match several terrain types? To do this, just put the list of types we want to match in the type= element of the [tile] tag. For example, the following rule will match any terrain with is either grassland (Gg), or dirt (Re):

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg,Re
    [/tile]
 [/terrain_graphics]

The following characters are also possible:

  • The "*" character means 'any terrain'. Any constraint with the "type=*" element will match any possible terrain type. We'll see below for actual uses of such constraints.
  • The "!" character inverts the meaning of the terrain type list. Instead of matching terrains which are in the list, the constraint will match terrains which are not in the list.

Adding images to terrains

Now that we have "rules" which can "match", we need to make the do something useful, that is, adding new images to terrains. This is done using the [image] tag. The basic syntax for [image] tags is the following one:

 [image]
    name=<name>
 [/image]

Where <name> is to be replaced by the base filename of the image. The string "terrain/" will be prepended to this name, and the string ".png" will be appended to it, to generate the actual filename of the image.

Image tags may appear into constraints, or into rules; those have slightly different meanings.

[image] tags into constraints

When [image] tags are placed into constraints, they must specify a single-hex image (currently, that means the ipmage must be 72x72). When the rule which contains the given contraint matches (that is, when all the rule's constraint match,) the image will be added to the hex corresponding to the constraint. For example, if our rule looks like this:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
    [tile]
       x=1
       y=0
       type=Ww
       [image]
          name=foobar
       [/image]
    [/tile]
 [/terrain_graphics]

And if the terrain looks like this:

  __    __
 /Gg\__/Gg\
 \__/Mm\__/
 /Gg\__/Ww\
 \__/Ww\__/
 /Ww\__/Ww\
 \__/  \__/

Then the tile at coordinate (1,1) (at the bottom of the center column) will get the image "terrains/foobar.png". The other tiles will get nothing from this rule, even the tile at the coordinates (0,1), which corresponds to the first constraint of this rule.

Several images may appear in a single constraint. Images may appear each constraint of a rule.

[image] tags directly into the rule

When [image] tags are directly placed into a rule, they may specify a multi-hex image. The image will be split into sub-images the size of a hex, and each of those sub-images will be added to the corresponding hex, if the rule contains a constraint in that position.

For example, consider the following rule:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
    [tile]
       x=1
       y=0
       type=Ww
    [/tile]
    [image]
       name=foobar
    [/image]
 [/terrain_graphics]

The foobar image being a 126x108 image which looks like this:

________________
| /    \       |
|/  A   \____  |
|\ (0,0)/    \ |
| \____/  B   \|
|      \ (1,0)/| 
|_______\____/_|

The terrain still is the same map:

  ___     ___
 /Gg \___/Gg \
 \___/Mm \___/
 /Gg+\___/Ww \
 \___/Ww*\___/
 /Ww \___/Ww \
 \___/   \___/

Here, the part marked "A" of the image will be applied to the hex marked with a +, whereas the part marked "B" of the image will be added to the hex marked with a \*.

However, suppose we wish to define a village which casts a shadow on nearby tiles. We draw a 126x144 image like the following one:

________________
|              |
|        ____  |
|       /    \ |
|  ____/  V   \|
| /    \ (1,0)/| 
|/shadow\____/ |
|\ (0,1)/      |
|_\____/_______|

Notice that, when maps are cut, the top-left part of the map is always a full hex, namely the hex marked (0,0), even if it doesn't correspond to anything on the map.

The rule only matches villages, so we might be tempted to write something like that (assuming B is the village tile):

 [terrain_graphics]
    [tile]
       x=1
       y=0
       type=Dd^Vda
    [/tile]
    [image]
       name=shadow-village
    [/image]
 [/terrain_graphics]

However, this will not work: the village will be displayed, but not the shadow! Remember what was written before: those sub-images will be added to the corresponding hex, if the rule contains a constraint in that position. As there is no constraint at the location (0,1), there will be no image either.

So, the solution is to add a match-all constraint, like this:

 [terrain_graphics]
    [tile]
       x=1
       y=0
       type=Dd^Vda
    [/tile]
    [tile]
       x=0
       y=1
       type=*
    [/tile]
    [image]
       name=shadow-village
    [/image]
 [/terrain_graphics]

Here, everything will work correctly.

Using flags

Rules may also set flags upon matching, and check for the absence, or presence, of flags, before being applied. This allows, for example, to make some mutually-exclusive rules. Flags are character strings which may be added to each hex of the map. Flags are not visible to the user, and only are used for the purpose of calculating terrain graphics.

Setting flags

A [tile] tag may have the set_flag element present, followed by a comma-separated list of flags. This specifies that, when the rule which contains this constraint does match, the following flags are to be set to the terrain corrsponding to this constraint.

Testing for flags

A [tile] tag may have the has_flag element present, followed by a comma-separated list of flags. This specifies that this constraint will only match if the corresponding hex has *each* of the flags present in the list. Those flags may have been set be previous rules.

A [tile] tag may have the no_flag element present, followed by a comma-separated list of flags. This specifies that this constraint will only match if *none* of the flags present in the list are present on the corresponding hex.

Flags under [terrain_graphics]

set_flag, has_flag and no_flag may also be defined as children of [terrain_graphics] WML elements. Doing this is equivalent to defining those same flags in each constraint.

A common use for flags is to make mutually-exclusive rules. For example, if we have one rule which defines a 2-hex grassland tile, and another rule which defines a 1-hex grassland tile, we do not want both to appear on the same hex. So, the rules may be defined like that:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
    [tile]
       x=0
       y=1
       type=Gg
    [/tile]
    [image]
       name=2-tile-grassland
    [/image]
    set_flag=base
 [/terrain_graphics]
 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg
    [/tile]
    [image]
       name=1-tile-grassland
    [/image]
    no_flag=base
 [/terrain_graphics]

Here, the first rule, regarding the 2-tile grassland, will be checked first. If it does match, it will set, on both hexes, the flag "base". Hence, the second rule won't match on any of those hexes, because it has "no_flag=base".

It is quite common to add, in the same rule, "set_flag=flag" and "no_flag=flag". This allows to define a set of mutually-exclusive rules, irrespectively of the order in which they will be applied.

Cumulative Probabilities

When assigning a probability to a rule there are some non-obvious mathematical considerations.

When you have two or more rules to be applied exclusively (usually by way of setting and checking a flag), such as tile detail variants, the probabilities of rules other than the first one should be adjusted to indicate the probability of the remaining percentage, instead of 100%.

Example

You want to use rule A 33% of the time, rule B 25% of the time, rule C 10% of the time, and rule D the rest of the time. The rule probabilities should be as follows:

  • rule A, 33% (33% of the whole 100% = desired 33% of all cases)
  • rule B, 37% (37% of the 67% that did not match rule A = desired 25% of all cases)
  • rule C, 24% (24% of the 42% that did not match A or B = desired 10% of all cases)
  • rule D, 100% (100% of the 32% that are left)

Using map-strings

Defining large multi-hex terrains may be rather confusing when the number of tiles increase. To make this simpler, a shortcut notation was introduced: map-strings. Map strings are defined by adding a map element under a [terrain_graphics] tag.

Map string format

Map strings are stings, generally multi-line, which are parsed the following way:

  • Starting empty lines are discarded.
  • lines are interpreted as comma-separated fields
  • If the first non-empty line starts with an empty field, it is given the line number "1". Else, it is given the line-number "0"
  • If the line is odd-numbered, an empty first field is ignored
  • Trailing whitespace on fields is ignored
  • For each field:
    • If the field consists of a dot, it is ignored.
    • If the chunk consists of a *, a new wildcard rule is created.
    • If the chunk consists if digits, a new anchor is created (see below.)
    • The column-number is increased by one.

A rule created by a * in a map string will be the exact equivalent of the following WML:

 [tile]
    x=<x>
    y=<y>
    type=*
 [/tile]

Where <type> is the contents of the current field, and where x and y are given by the following formula:

x = (lineno % 2) + colno * 2
y = lineno / 2

"%" being the modulus operator, and "/" the integer division operator.

For example, the following notations will be equivalent.

Anchors

As was stated before, maps may, instead of specifying terrains, may also specify "anchors". Anchors do not define actual rules. However, when an anchor is set, any [tile] WML child tag may use, instead of x and y, the WML element "pos=<anchor>", where anchor is the index of the anchor, from 0 to 9. This will define a rule as normal, except that its offset will be the offset of the anchor.

An useful feature is that a same anchor may be specified multiple times. When a [tile] tag uses this anchor, this will create several rules at once! For example: the following notations are equivalent:

 [terrain_graphics]
    map="
 , 1,
 1,  1
 , 2
 1,  1
   1"
    [tile]
       pos=1
       type=Mm
       set_flag=adjacent_to_foo
    [tile]
    [tile]
       pos=2
       type=Mm
       no_flag=adjacent_to_foo
       [image]
          name=foo
       [/image]
    [/tile]
 [/terrain_graphics]

And:

 [terrain_graphics]
    [tile]
       x=1
       y=0
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
    [tile]
       x=0
       y=1
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
    [tile]
       x=1
       y=1
       no_flag=adjacent_to_foo
       [image]
          name=foo
       [/image]
    [/tile]
    [tile]
       x=2
       y=1
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
    [tile]
       x=0
       y=2
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
    [tile]
       x=1
       y=2
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
    [tile]
       x=1
       y=3
       type=Mm
       set_flag=adjacent_to_foo
    [/tile]
 [/terrain_graphics]

Rule parameters

The 2 elements probability, and precedence, and the x and y couple, may be added directly under the [terrain_graphics] WML tag. Those affect the rule as a whole, and have the following meaning:

Position: x and y

If a rule defines the x and y elements, it may only match on this position of the screen (provided all other conditions are met). May be useful for some scenario-specific terrains that only may appear at one given position.

Probability

The probability element defines the probability of a rule to match, when all other conditions are met. It is a number from 0 to 100, 0 meaning "this rule will never match", and 100 "this rules always matches, provided all other conditions are met." See Terrain Graphics Probability for mathematical complications.

Precedence

Usually, rules do not define any precedence, and are executed in the order they are defined. rules with a lower precedence will always be executed before rules with a higher precedence. This allows for custom scenario to define custom rules and to choose whether they have to be defined before, or after generic rules.

Layering images

When images are defined like what was explained above, without any layering information, they will be displayed on-screen in a first-to-last way, that is, images which are added first go into the background, and images which are added last go into the foreground. This may not be what we expect; so, in general, some "layering"-related elements are added to the images, directly into the [image] WML tags.

2 layering models exist; an image can use either model. The two layering models are the horizontal model, and the vertical model. Model is selected with the position element.

Horizontal-layered images

The simplest, default layering model is called the "horizontal" model. Images are set to usie the horizontal model by either specifying "position=horizontal" in the [image] tag, or by not specifying a position at all.

The horizontal layering model is pretty simple: each image may define, using the layer element, which layer it is in. The layer index is an integer number going from -1000 (most background) to +1000 (most foreground) (actually, using higher and lower number should work, but this may change.) Images which have negative layeris are displayed behind unit graphics; images which have positive layers are displayed in front of unit graphics.

Images which are in the same layer are ordered the classic way, in the order they are defined. If an image does not specify a layer, it will be assumed to be in layer 0.

For example, suppose the two following rules:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg^Ve
       [image]
          position=horizontal
          layer=-500
          name=village_foreground
       [/image]
    [/tile]
 [/terrain_graphics]
 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg^Ve
       [image]
          position=horizontal
          layer=-1000
          name=village_background
       [/image]
    [/tile]
 [/terrain_graphics]

In this case, village_background will be drawn behind village_foreground, even if it is defined after it.

Vertical-layered images

Images may also specify "position=vertical" in the [image] tag, so they use the "vertical" model. Vertical-layered images are not disposed in flat, stacked layers, but are instead assumed, when they are rendered, to have an (x, y) position on the screen. They are, then, drawn according to the rule which states that objects in the bottom are hidden by objects in the front.

To use the vertical model, [image] tags should contain the base element, like this:

 base=x,y

Where x, and y, are the coordinates, in pixels, of the base of the image (that is, the virtual point at which the image would be in contact of the ground). Those coordinates are relative to the top-left-corner of the image.

If the image is a single-hex image, this means that the base coordinates are relative to the top-left corner of the smallest square containing the tile hex.

If the image is a multi-hex image (see the `[image] tags directly into the rule`_ section for more info,) this means that the base coordinates are relative to the top-left corner of the multi-hex image. Please note that, when using multi-hex images, the top-left hex of the image always is assumed to ihave hex coordinates (0,0) (see above). The coordinates of base will always be relative to the top-left of **this hex**, even if the rules contains no constraint regarding (0, 0).

Note: for positioning purposes, units are supposed to be in the position (36,54) relative to the top-left corner of the square containing their hex. This means that any image in front of this may hide units.

Note: vertical-layered images are always drawn in front of horizontal-layered images which have a negative layer, whatever their respective layers and base coordinates may otherwise be. Vertical-layered images are always drawn behind horizontal-layered images which have a positive layer. However, this may be broken in wesnoth up to 0.8.11

Using rotation templates

Rules sometimes are rotated versions of other, similar rules. To simplify the definition of such rules, the notion of "rotation templates" was introduced. Those are [terrain_graphics] definitions which do not define one rule, but may define up to 6 rules, each one rotated by a Pi/3 (radians) angle.

To define a rotation template, defines a [terrain_graphics] rule, as usual, except that this rule should contain the rotations element, followed by a list of 6 comma-separated strings (usually short ones.)

The image names and flag names of the rule and of its constraints may contain template strings of the form @Rn, n being a number from 0 to 5.

A template rule will generate 6 rules, which are similar to the template, except that:

  • The map of constraints of this rule will be rotated by an angle, from 0 to 5 pi / 6. Note that the relative positions of the constraints will be rotated, too; and so will the "base" of images whose position is set to "vertical".

After being rotated, each set of constraint will be translated, so that:

    • There is no constraint with negative coordinates
    • There is at least one constraint which has x=0
    • There is at least one constraint which has y=0

This is important, because, for example, rules about multi-hex images will then apply as usual, using the modified set of constraints

  • On the rule which is rotated to 0rad, the template strings @R0, @R1, @R2, @R3, @R4, @R5, will be replaced by the corresponding r0, r1, r2, r3, r4, r5 variables given in the rotations= element.
  • On the rule which is rotated to pi/3 rad, the template strings @R0, @R1, @R2 etc. will be replaced by the corresponding r1, r2, r3, r4, r5, r0 (note the shift in indices).
  • On the rule rotated 2pi/3, those will be replaced by r2, r3, r4, r5, r0, r1 and so on.

For example, the following notations are equivalent

The compact template-based rotation:

 [terrain_graphics]
     map="
 1
   g"
     [tile]
        pos=1
        image=bar-@R0-@R3
     [/tile]
     rotations=se,s,sw,nw,n,ne
 [/terrain_graphics]

And the quite verbose classic notation:

 [terrain_graphics]
     map="
 1
   g"
     [tile]
        pos=1
        image=bar-se-nw
     [/tile]
 [/terrain_graphics]
 [terrain_graphics]
     map="
 1
  
 g"
     [tile]
        pos=1
        image=bar-s-n
     [/tile]
 [/terrain_graphics]
 [terrain_graphics]
     map="
   1
 g"
     [tile]
        pos=1
        image=bar-sw-ne
     [/tile]
 [/terrain_graphics]
 [terrain_graphics]
     map="
 g
   1"
     [tile]
        pos=1
        image=bar-nw-se
     [/tile]
 [/terrain_graphics]
 [terrain_graphics]
     map="
   g

   1"
     [tile]
        pos=1
        image=bar-n-s
     [/tile]
 [/terrain_graphics]
 [terrain_graphics]
     map="
   g
 1"
     [tile]
        pos=1
        image=bar-ne-sw
     [/tile]
 [/terrain_graphics]

Animating images

Images may may be animated instead of being static. To do this, specify a list of comma-separated images in the name element of the [image] tag. This will generate an animation, each frame being displayed during 100ms.

The duration of each frame may be specified, to have a different value than the default 100 ms, by adding, after the image name, a colon (:), followed by a number representing a time in milliseconds.

For example, take the following declaration:

 [image]
    name=frame1,frame2,frame3:300,frame4:200,frame5
 [/image]

It will define an animation composed of the following 5 frames:

Image  Duration
====== ========
frame1 100 ms
frame2 100 ms
frame3 300 ms
frame4 200 ms
frame5 100 ms

Time-of-day-specific variants of images

It is possible, for images, to have several variants; the actual variant displayed being selected according to the current time-of-day. The notation introduced above, using the name attribute to define the image used, actually defines the default variant of the image; that is, the variant that will be used, either if there is no time-of-day (for example, in the editor,) or if the current time-of-day is not specified in another variant.

Variants may be defined by adding the [variant] child tag to the [image] tag. [variant] child tags have 2 elements:

  • The tod elements which specifies the time-of-day this variant applies to (see the file data/schedules.cfg for the list of times-of-day.
  • The name element which has the same exact meaning as the name element of the [image] tag (and may, for example, carry animations etc), which will be used in place of the default name when the time-of-day matches.

For example, the following WML code specifies a village which has smoke when it is the night:

 [terrain_graphics]
    [tile]
       x=0
       y=0
       type=Gg^Ve
       [image]
          name=village
          [variant]
             tod=first_watch
             name=village-dusk,village-dusk2,village-dusk3,village-dusk4
          [/variant]
          [variant]
             tod=second_watch
             name=village-dusk,village-dusk2,village-dusk3,village-dusk4
          [/variant]
       [/image]
    [/tile]
 [/terrain_graphics]

Using macros

Macros are defined in terrain-graphics.cfg and the *.cfg in [wesnoth 1.8.2 directory]data/core/terrain-graphics folder.

The basic building block of macros can be thought of as functions which follows the format:

#define MACRO_NAME PARAMETER1 PARAMETER2 
[terran-graphic rules....]
#enddef

Well you might be thinking that isn't '#' a comment, yes it is, except when it's "#define"

An example is the following:

#define OVERLAY_PLF TERRAIN PROB LAYER FLAG IMAGESTEM
   [terrain_graphics]
       map="
, *
* , *
, 1
* , *
, *"
       [tile]
           pos=1
           type={TERRAIN}
           no_flag={FLAG}
           set_flag={FLAG}
       [/tile]
       probability={PROB}
       [image]
           name={IMAGESTEM}
           layer={LAYER}
           base=90,144
           center=90,144
       [/image]
   [/terrain_graphics]
#enddef

The parameters TERRAIN is substituted into the body within the macro definition tags.

You'll also see quite a bit of code enclosed in '{' and '}'. These can be thought of as macro function call.

Using back the previous example, you might see the following in terrain-graphics.cfg:

{OVERLAY_PLF             *^Xm                                   33    1   clouds3  cloud1_2}
{OVERLAY_PLF             *^Xm                                   50    1   clouds3  cloud2_2}

Well, what this essentially does is to substitute "*^Xm" into TERRAIN, "33" into PROB etc.. into the macro function "OVERLAY_PLF". Essentially, it creates 2 OVERLAY_PLF terrain graphics rules by just changing the parameters.

These macros can be recursive. E.g:

#define MACRO_1 PARA1 PARA2
{MACRO_2 M2_PARA1 M2_PARA2}
{MACRO_2 M2_PARA3 M2_PARA4}
{MACRO_2 M2_PARA5 M2_PARA6}
#enddef
#define MACRO_2 PARA1 PARA2
       [image]
           name={PARA1}
           layer={PARA2}
           base=90,144
           center=90,144
       [/image]
#enddef

Macros for base terrains

Macros for adjacent terrains

Macros for castles

Macros for canyons

Macros for bridges

See Also

This page originated as a wikified version of the first half of Ayin's detailed Terrain Graphics document. It has been translated to use the multiletter terrain codes introduced later.

This page was last modified on 9 June 2015, at 03:34.