BZW(5)

πŸŽ€ BZW(5) β€” BZFlag πŸŽ€

✨ NAME ✨

bzw β€” the BZFlag world file format. That’s the name, bestie, and it’s lowkey the blueprint for the whole world. πŸ’–

🌈 DESCRIPTION 🌈

Okay so the BZFlag world file format describes a world environment that is used by the BZFlag game server, bzfs. Also, the source literally has the stray tag X BZW file format in there, so we’re preserving it like a tiny artifact. ✨

The BZFlag world file format describes an environment that includes the game map, physical world attributes, and automatic world weapons. The map may contain a variety of β€œobstacles” like buildings, pyramids, and meshes. These obstacles make up the world that the BZFlag tanks will drive around in. Map attributes may be set to create worlds of various sizes, the default size is 800x800. πŸ’…

Here’s a small example world:

# simple world containing a box, pyramid, and mesh
world
  name Simple World
  size 100.0
end
box
  position -20 -20 0
  size 10 20 10
end
pyramid
  position 20 20 0
  size 10 10 20
end
mesh
  vertex -10 0 0
  vertex 10 0 0
  vertex 0 10 0
  face
    vertices 0 1 2
  endface
end

The .bzw file is a plain text file with a relatively simple file format. The format of this text file consists of any number of objects listed in any order (except that physics, textureMatrix, dynamicColor, and material must come before they are referenced) separated by newlines and grouped into blocks of types. The list of world types consists of:

world
options
waterLevel
dynamicColor
textureMatrix
transform
material
physics
define
group
mesh
meshbox
meshpyr
arc
cone
sphere
tetra
box
pyramid
link
teleporter
base
weapon
zone

Each object is described by placing the type on one line, the word end on a following line, and a list of attributes for that object, one per line, in between. The exceptions to the rule are define and face, which are concluded with enddef and endface. Attributes may be listed in any order. Attributes have default values, and if that is good enough, the attribute need not be listed. 🫢

Words are always specified in lowercase. Line comments can be specified by placing a # sign at the start of the line.

For documentation purposes, you can tag each object by adding a name attribute. There is no set limit to the number of times you may use any of the objects except for the world, options, and waterLevel objects, they can only be specified once. The options object contains command line arguments that are used to configure the server’s game mode, but can not contain server specific options such as -p, -passwd, and -conf.

In the following examples, the values are the defaults. πŸ“

🌍 The World object 🌍

Header for the world. She’s giving main character energy, obviously.

world
  name example_world
  size 400.0
  flagHeight 10.0
end

πŸŽ›οΈ The Options object πŸŽ›οΈ

A world file interface for setting command line options for BZFS. No cap, it’s literally the command-line vibe tucked inside your world file.

options
  -set _tankSpeed 36
  -j +r -ms 3
  +f GM{5} +f SW{5}
end

🌊 The Water Level object 🌊

Sets how high the water is, in a matter of units.

waterLevel
  name example_waterlevel
  height -1.0 # anything below 0 turns it off
end

🧩 The Group Definition object 🧩

Defines a group, which may include other group instances. This does not place any objects into the world, a group instance must be used to generate world objects from a group definition. Periodt.

define <example_groupdef>
  # You can add any object to a group definition,
  # except for the following types:
  #   textureMatrix
  #   dynamicColor
  #   material
  #   physics
  #   links
  #   weapon
  #   zone
enddef

πŸŒ€ The Group Instantiation object πŸŒ€

Instantiates a group, and possibly modifies subobjects. It’s giving β€œcopy paste but make it fashion.”

group <example_groupdef>  # a valid group definition reference
  shift 0 0 0          # (repeatable)
  scale 1 1 1          # (repeatable)
  shear 0 0 0          # (repeatable)
  spin angle nx ny nz  # (repeatable)
                       # angle degrees about vector n
  team 0        # change all base colors within group
  tint 1 1 1 1  # hierarchically tints objects within this group
  drivethrough  # make all subobjects drivethrough
  shootthrough  # make all subobjects shootthrough
  ricochet      # make all subobjects ricochet
  phydrv example_phydrv     # reassign any valid physics drivers
  matref example_material # set material properties

                            # (except for the color)
 matswap oldMat newMat #replace a given material in the instance
end

🌈 The Dynamic Color object 🌈

Behold, the dynamicColor object. The comments inside are doing the heavy lifting, so read them like the sacred texts they are. πŸ’…

dynamicColor
  name example_dyncol
  # there are 4 channels that can be modified:
  #   red, green, blue, alpha
  # there are 5 types of commands per channel:
  #   limits, sinusoid, clampUp, clampDown, sequence
  # except for "limits" and "sequence", the commands are repeatable
  # if a sequence is used, then clampUps and clampDowns have no effect
  # sequences can use three states (0, 1, 2).
  #   0 - equivalent to an active clampDown
  #   1 - equivalent to no clamps
  #   2 - equivalent to an active clampUp
  # if both clampUp and clampDown are active, the value is (min+max)/2
  # the sinusoid function starts at the max value
  # the sum of a channel's sinusoids is clamped between 0 and 1
  red limits 0 1               # min/max limits
  green sinusoid 0.1 0 0.25    # period, offset, weight
  blue clampUp 0.1 0 0.75      # period, offset, width
  alpha clampDown 0.2 0.5 0.5  # period, offset, width
  red sequence 0.0 0.0 2 0 1 1 2 0 ... # period, offset, list of states
end

πŸͺž The Texture Matrix object πŸͺž

Texture Matrix? More like texture slay. Anyway:

textureMatrix
  name example_texmat
  scale 0.0 0.0 1.0 1.0  # u/v freqs, u/v scales
  spin 0.0               # rotation freq
  shift 0.0 0.0          # u/v freqs
  center 0.5 0.5         # dynamic u/v center (for spin and scale)
  fixedscale 0.0 0.0     # time invariant u/v scale
  fixedspin 0.0          # time invariant rotation
  fixedshift 0.0 0.0     # time invariant u/v shift
end

🎨 Material Properties 🎨

Material properties may be set on several types of objects, including meshes, mesh faces, arcs, cones, spheres, and tetras. Here are the properties:

material
  name example_material
  resetmat                  # restore default values
  matref material_name      # copy another material's properties
  ambient  0.2 0.2 0.2 1.0  # ambient color
  diffuse  1.0 1.0 1.0 1.0  # diffuse color (main color)
  color    1.0 1.0 1.0 1.0  # synonym for 'diffuse'
  specular 0.0 0.0 0.0 1.0  # specular color
  emission 0.0 0.0 0.0 1.0  # emission color
  shininess 0.0             # shininess (0.0 – 128.0)
  texture filename     # set working texture
  # - non-interlaced PNG
  # - http:// or ftp:// hyperlinks can be used  (no spaces)
  # - BZFlag default texture names can be used  (.png not required)
  addtexture filename  # add texture
  notextures           # specify that no textures are to be used
  notexalpha           # don't use the texture's alpha channel
  notexcolor           # the color is not applied to the texture
  # if a texture is specified, but not found, the default texture
  # will be used. if the default texture is also not available, then
  # the color will be used (untextured)
  spheremap            # use spherical texture coordinate mapping
  texmat -1            # texture matrix  (-1 for none)
  dyncol -1            # dynamic color  (-1 for none)
  noradar              # do not display on radar  (except normal mode)
  noshadow             # do not render shadows
  noculling            # do not cull by face winding  (double-sided)
  nosorting            # do not do front-to-back alpha sorting
  nolighting           # disable lighting
  alphathresh 0.0      # alpha thresholding value
  groupalpha           # sort translucent faces as a group
  occluder             # faces with this material will occlude
end

πŸš€ The Physics Driver object πŸš€

Physics driver block, coming through:

physics
  name example_phydrv
  linear  0.0 0.0 0.0  # x/y/z linear velocities
  angular 0.0 0.0 0.0  # rotation freq, x/y coordinates
  slide 0.0            # time until max velocity  (> 0.0 enables)
  death Message goes here.
  # the 'death' property requires a non-blank message
end

🧚 The Mesh object 🧚

The mesh object πŸ•ΈοΈ

okay so the mesh object is the full DIY, build-it-by-hand geometry option, and it's a lot β€” but it does exactly what you tell it, no cap. You feed it vertices, normals and texture coords, then stitch them into faces yourself.

mesh
  name example_mesh
  # Material properties applied to a mesh apply to all faces
  # that follow the setting. Mesh faces will alter their own
  # properties without affecting the state of the mesh properties.
  # The same pattern is used to apply physics drivers.
  vertex 100 200 300  # add a vertex              (repeatable)
  normal 1.0 0 0      # add a normal              (repeatable)
  texcoord 0.1 0.75   # add a texture coordinate  (repeatable)
  inside 5.5 4.5 1.2  # add an inside point       (repeatable)
  outside 0 0 1000    # add an outside point      (repeatable)
  shift 0 0 0           # (repeatable)
  scale 1 1 1           # (repeatable)
  shear 0 0 0           # (repeatable)
  spin angle nx ny nz   # (repeatable)
  phydrv example_phydrv # assign a physics driver
  smoothbounce          # ricochets use normals
  noclusters            # render each mesh face individually
  face  # start a face   (repeatable)
    # the front-face winding is counter-clockwise
    vertices 1 4 0 3 5   # list of vertices (requires at least three)
    normals 2 6 0 4 7    # list of normals              (optional)
    texcoords 0 3 2 4 9  # list of texture coordinates  (optional)
    phydrv example_phydrv  # assign a physics driver
  endface  # end the face
  #
  #  This next element can be added to increase the rendering speed
  #  of the mesh object. If the client is capable of using this data,
  #  then it is used to draw the mesh instead of the face information.
  #
  drawInfo
    dlist                      # display list for all material sets
    decorative                 # older clients with not see this mesh
    angvel <degrees/sec>       # rotation about initial Z axis
    extents <minX> <minY> <minZ> <maxX> <maxY> <maxZ>
    sphere <x> <y> <z> <radiusSquared>
    corner <v> <n> <t>         (repeatable)
    vertex 0.0 0.0 0.0         (repeatable)
    normal 0.0 0.0 0.0         (repeatable)
    texcoord 0.0 0.0           (repeatable)
    lod                        (repeatable)
      lengthPerPixel <value>
      matref <name>            (repeatable)
        dlist                  # display list for this material set
        sphere <x> <y> <z> <radiusSquared>
        points    0            (repeatable)
        lines     0 1          (repeatable)
        lineloop  0 1          (repeatable)
        linestrip 0 1          (repeatable)
        tris      0 1 2        (repeatable)
        tristrip  0 1 2        (repeatable)
        trifan    0 1 2        (repeatable)
        quads     0 1 2 3      (repeatable)
        quadstrip 0 1 2 3      (repeatable)
        polygon   0 1 2        (repeatable)
      end  # matref
    end    # lod
  end      # drawInfo
end        # mesh

Let's decode this beast πŸ’…

  • Material properties you set on the mesh apply to all faces that follow the setting β€” and a mesh face changing its own properties does not touch the state of the mesh properties. Same pattern for physics drivers, iykyk.
  • vertex 100 200 300 β€” adds a vertex (repeatable).
  • normal 1.0 0 0 β€” adds a normal (repeatable).
  • texcoord 0.1 0.75 β€” adds a texture coordinate (repeatable).
  • inside 5.5 4.5 1.2 β€” adds an inside point (repeatable).
  • outside 0 0 1000 β€” adds an outside point (repeatable).
  • shift 0 0 0 β€” repeatable.
  • scale 1 1 1 β€” repeatable.
  • shear 0 0 0 β€” repeatable.
  • spin angle nx ny nz β€” repeatable.
  • phydrv example_phydrv β€” assigns a physics driver.
  • smoothbounce β€” ricochets use normals ✨
  • noclusters β€” renders each mesh face individually.
  • face / endface β€” starts and ends a face (repeatable). The front-face winding is counter-clockwise, bestie, remember it. Inside: vertices 1 4 0 3 5 (a list of vertices, requires at least three), normals 2 6 0 4 7 (optional list of normals), texcoords 0 3 2 4 9 (optional list of texture coordinates), and phydrv example_phydrv to assign a physics driver to that face.
  • drawInfo β€” this whole block can be added to increase the rendering speed of the mesh object. If the client is capable of using this data, then it's used to draw the mesh instead of the face information. Inside it lives:
    • dlist β€” display list for all material sets
    • decorative β€” older clients with not see this mesh
    • angvel <degrees/sec> β€” rotation about initial Z axis
    • extents <minX> <minY> <minZ> <maxX> <maxY> <maxZ>
    • sphere <x> <y> <z> <radiusSquared>
    • corner <v> <n> <t> (repeatable)
    • vertex 0.0 0.0 0.0 (repeatable)
    • normal 0.0 0.0 0.0 (repeatable)
    • texcoord 0.0 0.0 (repeatable)
    • lod (repeatable) β†’ lengthPerPixel <value>, and matref <name> (repeatable) which contains dlist (display list for this material set), sphere <x> <y> <z> <radiusSquared>, then all the primitives, each repeatable: points 0, lines 0 1, lineloop 0 1, linestrip 0 1, tris 0 1 2, tristrip 0 1 2, trifan 0 1 2, quads 0 1 2 3, quadstrip 0 1 2 3, polygon 0 1 2, then end for the matref.

The Arc object πŸ¦‹

arc
  name example_arc
  divisions 16   # number of subdivisions
  flatshading    # flat shading  (smooth is default)
  angle 360      # the sweep angle
  ratio 1        # (outrad - inrad) / outrad
  position 0.0 0.0 0.0
  size 10 10 10
  rotation 0.0
  shift 0 0 0            # (repeatable)
  scale 1 1 1            # (repeatable)
  shear 0 0 0            # (repeatable)
  spin angle nx ny nz    # (repeatable)
  phydrv example_phydrv  # assign a physics driver
  smoothbounce           # ricochets use normals
end
  • divisions 16 β€” number of subdivisions
  • flatshading β€” flat shading (smooth is the default)
  • angle 360 β€” the sweep angle
  • ratio 1 β€” (outrad - inrad) / outrad
  • position, size, rotation β€” the usual placement trio
  • shift, scale, shear, spin angle nx ny nz β€” all repeatable
  • phydrv β€” assigns a physics driver
  • smoothbounce β€” ricochets use normals

The Cone object 🍦

cone
  name example_cone
  divisions 16   # number of subdivisions
  flatshading    # flat shading  (smooth is default)
  angle 360      # the sweep angle
  position 0.0 0.0 0.0
  size 10 10 10
  rotation 0.0
  shift 0 0 0            # (repeatable)
  scale 1 1 1            # (repeatable)
  shear 0 0 0            # (repeatable)
  spin angle nx ny nz    # (repeatable)
  phydrv example_phydrv  # assign a physics driver
  smoothbounce           # ricochets use normals
end

literally the arc's sibling, minus ratio. You've got divisions 16, flatshading, angle 360 (the sweep angle), position, size, rotation, the repeatable shift/scale/shear/spin angle nx ny nz, phydrv, and smoothbounce. Slay.

The Sphere object 🌸

sphere
  name example_sphere
  divisions 4    # number of subdivisions
  flatshading    # flat shading  (smooth is default)
  position 0.0 0.0 10.0
  size 10 10 10
  radius 10      #  sets all size values to this value
  rotation 0.0
  shift 0 0 0            # (repeatable)
  scale 1 1 1            # (repeatable)
  shear 0 0 0            # (repeatable)
  spin angle nx ny nz    # (repeatable)
  phydrv example_phydrv  # assign a physics driver
  smoothbounce           # ricochets use normals
end
  • divisions 4 β€” number of subdivisions
  • flatshading β€” flat shading (smooth is default)
  • position 0.0 0.0 10.0
  • size 10 10 10
  • radius 10 β€” sets all size values to this value πŸ‘‘
  • rotation 0.0
  • shift, scale, shear, spin angle nx ny nz β€” repeatable
  • phydrv example_phydrv β€” assign a physics driver
  • smoothbounce β€” ricochets use normals

The Tetrahedron object πŸ”Ί

tetra
  name example_tetra
# there must always be 4 vertices
  vertex -10.0 -5.0 0.0
  vertex +10.0 -5.0 0.0
  vertex 0.0 10.0 0.0
  vertex 0.0 5.0 10.0
  shift 0 0 0            # (repeatable)
  scale 1 1 1            # (repeatable)
  shear 0 0 0            # (repeatable)
  spin angle nx ny nz    # (repeatable)
end

there must always be 4 vertices, bestie, that's the whole point of a tetra. Then the repeatable shift, scale, shear, and spin angle nx ny nz.

The Box object πŸ“¦

Adds a simple block. And honestly? Iconic for it.

box
  name example_box
  position 0.0 0.0 0.0
  size 30.0 30.0 9.42
  rotation 0.0
end

The Pyramid object πŸ”Ίβœ¨

Adds a triangular shaped object.

pyramid
  name example_pyramid
  position 0.0 0.0 0.0
  size 8.2 8.2 10.25
  rotation 0.0
end

The Teleporter object πŸŒ€

Adds an object that places a tank at another teleporter in a different area when ran through. Main character energy fr.

teleporter [name]
# the [name] tag is used for linkage
  name example_teleporter
  position 0.0 0.0 0.0
  size 5.06 4.48 20.16
  rotation 0.0
  border 1.12
end
the [name] tag is what's used for linkage β€” remember it, it comes back in like two seconds.

Adds a route to teleport a tank between two teleporters. The rules of the game, straight up:

# Teleporter names are terminated with either :f (forward)
# or :b (backwards). The forwards link points to 0 degrees,
# and the backwards link points to 180. Links are made by
# pattern matching the teleporter names. The '*' and '?'
# globbing characters can be used to make multiple matches.
# If there are multiple matches for the "to" link, then the
# destination will be selected randomly between the matches.
# in-game.

# NOTE: bzfs -d -d -d -d will print the linkage table.

So: forwards link points to 0 degrees, backwards link points to 180, matching is done on the teleporter names, and '*' and '?' globbing can make multiple matches. If there are multiple matches for the "to" link, the destination gets picked randomly between the matches in-game. Also bzfs -d -d -d -d will print the linkage table β€” write that down πŸ“

Here's the chaos option:

link
  name example_link
# this will link all teleporters randomly to all other teleporters
  from *
  to   *
end
link
  name  example_realLink
  from examp_tele1:f
  to   examp_tele2:b
end

The Base object 🏰

Creates a team base where the corresponding team's flag is stored. The oncap option will fire a world weapon of the specified type when the team flag for this base is captured. Obsessed.

base
  name example_base
  position 0.0 0.0 0.0
  size 60.0 60.0 0.0
  rotation 0.0
  color 0
  oncap V
end

The Weapon object πŸ’₯

Creates a world weapon, or a weapon fired automatically by the world. And it can be either timed or event driven β€” pick your vibe:

  • Timed weapons should use the initdelay and delay fields.
  • Event driven weapons need to use the trigger option to define what the trigger event is.
  • Valid trigger events are: OnCap, for flag capture events. OnSpawn, for player spawn events. OnDie, for player death events.
  • If the weapon is to be triggered only for a specific team, then the eventteam option should be used with a team number (1 to 4).
  • An eventteam value of -1 will trigger this weapon for any team. -1 is the default eventteam value.
weapon
  name example_weapon
  position 0.0 0.0 0.0
  rotation 0.0
  tilt 0.0
  initdelay 10.0
  delay 10.0 3.0 5.0 3.0
  type V
  trigger flagcap
  eventteam V
end

The Zone object 🫧

Specifies a certain range in the world, and what attributes that range has. It's giving "vibe check, but spatial".

zone
  name example_zone
  position 0.0 0.0 0.0
  size 1.0 1.0 1.0
  rotation 0.0
# where players may spawn
  team 0 1 2 3 4
# where flag may spawn
  flag GM SW good bad
# dropped team flags will fly to the closest safety zone
  safety 1 2 3 4
# attach a flag to this zone (always spawn in this zone)
  zoneflag GM 3  # type, count (type can be a team flag, ex: R*)
end

so real quick, what each of those does:

  • team 0 1 2 3 4 β€” where players may spawn
  • flag GM SW good bad β€” where flag may spawn
  • safety 1 2 3 4 β€” dropped team flags will fly to the closest safety zone
  • zoneflag GM 3 β€” attach a flag to this zone (always spawn in this zone). Format is # type, count and the type can be a team flag, ex: R*

πŸŽ€ FILE SYNTAX πŸŽ€

the grammar era, bestie. Let's get into it 🧚

The symbol '?' means that the item is optional.

The notation {a..b} means that the number of times the item can be present must be between 'a' and 'b', where '*' mean infinity. ('?' is equivalent to {0..1})

angle := <float>

2dpoint := <float> <float>

3dpoint := <float> <float> <float>

rgbColor := <float> <float> <float>

alpha := <float>

rgbaColor := rgbColor alpha? | <color_name> alpha?

channel := "red" | "green" | "blue" | "alpha"

(BZWReader.cxx/parseNormalObject)
allObjects :=
              "box"
            | "pyramid"
            | "base"
            | "link"
            | "teleporter"
            | "mesh"
            | "arc"
            | "meshbox"
            | "cone"
            | "meshpyr"
            | "sphere"
            | "tetra"
            | "weapon"
            | "zone"
            | "waterLevel"
            | "dynamicColor"
            | "textureMatrix"
            | "material"
            | "physics"
            | "transform"

(BZWReader.cxx/BZWReader::readWorldStream)
       Note: Blank lines and lines starting with # are discarded.

worldStream :=
              "end"
            | allObjects
            | "define" <group_name>
            | "enddef"
            | "group" <group_name>
            | "teleporter" <name>?
            | "options"
            | "include" <filename>
            | "world"

(ParseMaterial.cxx/parseMaterials)

material :=
            object
            | "matref" <material_name>
            | "resetmat"
            | "dyncol" <dynamic_color_name>
            | "ambient" rgbaColor
            | ("diffuse" | "color") rgbaColor
            | "specular" rgbaColor
            | "emission" rgbaColor
            | "shininess" <float>
            | "texture <texture_name>
            | "notextures"
            | "addtexture" <texture_name>
            | "texmat" <matrix_name>
            | "notexalpha"
            | "notexcolor"
            | "spheremap"
            | "noradar"
            | "noshadow"
            | "noculling"
            | "nosorting"
            | "nolighting"
            | "alphathresh" <value>
            | "groupalpha"
            | "occluder"
            | "shader" <shader_name>  # NOT IMPLEMENTED
            | "addshader" <shader_name>  # NOT IMPLEMENTED
            | "noshaders"  # NOT IMPLEMENTED

quick heads up on the last three β€” shader, addshader and noshaders are literally marked # NOT IMPLEMENTED, so don't come for me if they do nothing πŸ™ˆ

okay so we’re deep in the grammar era of this page now β€” this is the part where every object type gets its little recipe, and I’m keeping every single production because we do not skip lore in this house πŸ’…

(WorldFileObject:.cxx/WorldFileObject::read) β€” the object production, exactly as written:

       object := "name" <name>

(WorldFileLocation.cxx/readWorldFileLocation::read) β€” location is giving main-character energy with all these options:

       location :=
                     ("pos" | "position") 3dpoint
                   | "size" 3dpoint
                   | ("rot" | "rotation") <float>
                   | "shift" 3dpoint
                   | "scale" 3dpoint
                   | "shear" 3dpoint
                   | "spin" angle 3dpoint
                   | "xform" <transform_name>
                   | object

(WorldFileObstacle.cxx/WorldFileObstacle::read) β€” the obstacle production, iconic behavior flags included:

       obstacle :=
                     "drivethrough"
                   | "shootthrough"
                   | "passable"
                   | "ricochet"
                   | location

(CustomArc.cxx/CustomArc::read) β€” meshbox says hi:

       meshbox :=
                     "divisions" <integer>
                   | "angle" angle
                   | "ratio" <float>
                   | "texsize" <float> <float> <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "flatshading"
                   | material
                   | ("top" | "bottom" | "inside" | "outside" | "startside" |
              "endside") material
                   | obstacle

and arc is matching energy, same full recipe:

       arc :=
                     "divisions" <integer>
                   | "angle" angle
                   | "ratio" <float>
                   | "texsize" <float> <float> <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "flatshading"
                   | material
                   | ("top" | "bottom" | "inside" | "outside" | "startside" |
              "endside") material
                   | obstacle

(CustomBase.cxx/CustomBase::read) β€” base is short and slay:

       base :=
                     "color" <integer>
                   | obstacle

(CustomBox.cxx) β€” box is literally just obstacle, and honestly? valid:

       box := obstacle

(CustomCone.cxx/CustomCone::read) β€” meshpyr with all its texture and shading bits:

       meshpyr :=
                     "divisions" <integer>
                   | "angle" <float>
                   | "texsize" <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "flatshading"
                   | material
                   | ("edge" | "bottom" | "startside" | "endside") material
                   | "flipz"
                   | obstacle

and cone is right there with the same full list:

       cone :=
                     "divisions" <integer>
                   | "angle" <float>
                   | "texsize" <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "flatshading"
                   | material
                   | ("edge" | "bottom" | "startside" | "endside") material
                   | obstacle

(CustomDynamicColor.cxx/CustomDynamicColor::read) β€” dynamicColor is doing the most, respectfully:

       dynamicColor :=
                     object
                   | channel "limits" <float> <float>
                   | channel "sinusoid" <float> <float> <float>
                   | channel "clampup" <float> <float> <float>
                   | channel "clampdown" <float> <float> <float>
                   | channel "sequence" <float> <float> ("0" "1" "2"){1..*}

(CustomGate.cxx/CustomGate::read) β€” teleporter; yes, "horizontal" has a # NOT IMPLEMENTED note, so don’t act brand new about it:

       teleporter :=
                     "border" <float>
                   | "horizontal"  # NOT IMPLEMENTED
                   | obstacle

(CustomGroup.cxx/CustomGroup::read) β€” group production:

       group :=
                     "team" <integer>
                   | "tint" rgbaColor
                   | "phydrv" <physics_driver_name>
                   | "matref" <material_name>
                   | obstacle

(CustomLink.cxx/CustomLink::read) β€” teleporter_spec and link are here, wildcards and :f / :b included:

       teleporter_spec :=
                     <integer>
                   | <teleporter_name_with_wildcards> (":f" | ":b")?

       link :=
                     "from" <teleporter_spec>
                   | "to" <teleporter_spec>
                   | object

(MeshDrawInfo.cxx/MeshDrawInfo::parseDrawCmd) β€” drawInfoCmd is a whole buffet of primitives:

       drawInfoCmd :=
                     "points"    <integer>+
                   | "lines"     <integer> <integer> <integer>{2}*
                   | "lineloop"  <integer> <integer>+
                   | "linestrip" <integer> <integer> <integer{2}*
                   | "tris"      <integer> <integer> <integer> <integer>{3}*
                   | "tristrip"  <integer> <integer> <integer>+
                   | "trifan"    <integer> <integer> <integer>+
                   | "quads"     <integer> <integer> <integer> <integer>
              <integer>{4}*
                   | "quadstrip" <integer> <integer> <integer>{2}+
                   | "polygon"   <integer> <integer> <integer> <integer>{3}*

(MeshDrawInfo.cxx/MeshDrawInfo::parseDrawSet) β€” drawInfoSet:

       drawInfoSet :=
                     "matref" <material_name>
                   | "dlist"
                   | "sphere" 3dpoint <float>
                   | drawInfoCmd

(MeshDrawInfo.cxx/MeshDrawInfo::parseDrawLod) β€” drawInfoLod:

       drawInfoLod :=
                     "lod"
                   | "lengthPerPixel" <float>
                   | drawInfoSet

(MeshDrawInfo.cxx/MeshDrawInfo::parse) β€” drawInfo itself:

       drawInfo :=
                     "drawInfo"
                   | "dlist"
                   | "decorative"
                   | "angvel" <float>
                   | "extents" 3dpoint 3dpoint
                   | "sphere" 3dpoint <float>
                   | "corner" <integer> <integer> <integer>
                   | "vertex" 3dpoint
                   | "normal" 3dpoint
                   | "texcoord" <float> <float>
                   | drawInfoLod

(CustomMesh.cxx/CustomMesh::read) β€” mesh, with the full face/vertex/phydrv situation:

       mesh :=
                     "face"
                   | face
                   | "endface"
                   | "inside" 3dpoint
                   | "outside" 3dpoint
                   | "vertex" 3dpoint
                   | "normal" 3dpoint
                   | "texcoord" <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "noclusters"
                   | drawInfo
                   | material
                   | obstacle

(CustomMeshFace.cxx/CustomMeshFace::read) β€” face production:

       face :=
                     "vertices" <integer>{3..*}
                   | "normals" <integer>{3..*}
                   | "texcoords" <integer>{3..*}
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "noclusters"
                   | "drivethrough"
                   | "shootthrough"
                   | "ricochet"
                   | "passable"
                   | material

(CustomMeshTransform.cxx/CustomMeshTransform::read) β€” transform production:

       transform :=
                     "shift" 3dpoint
                   | "scale" 3dpoint
                   | "shear" 3dpoint
                   | "spin" angle 3dpoint
                   | "xform" <transform_name>
                   | object

(CustomPhysicsDriver.cxx/CustomPhysicsDriver::read) β€” physics; note that "radial" has # NOT IMPLEMENTED, so keep that energy in mind:

       physics :=
                     "linear" 3dpoint
                   | "angular" <float> 2dpoint
                   | "radial" <float> 2dpoint  # NOT IMPLEMENTED
                   | "slide" <float>
                   | "death" <string>
                   | object

(CustomPyramid.cxx/CustomPyramid::read) β€” pyramid is tiny:

       pyramid :=
                     "flipz"
                   | obstacle

(CustomSphere.cxx/CustomSphere::read) β€” sphere with hemispheres and all:

       sphere :=
                     "divisions" <integer>
                   | "radius" <float>
                   | ("hemi" | "hemisphere")
                   | "texsize" <float> <float>
                   | "phydrv" <physics_driver_name>
                   | "smoothbounce"
                   | "flatshading"
                   | material
                   | ("edge" | "bottom") material
                   | obstacle

(CustomTetra.cxx/CustomTetra::read) β€” tetra comes with two notes, and I’m preserving them exactly:

Note: At most 4 vertices can be specified. Note2: material will apply to all vertices when specified first, otherwise like "normals" and "texcoords" they apply to the previous vertex.
       tetra :=
                     "vertex" 3dpoint
                   | "normals" 3dpoint
                   | "texcoords" 2dpoint
                   | material
                   | obstacle

(CustomTextureMatrix.cxx/CustomTextureMatrix::read) β€” textureMatrix production:

       textureMatrix :=
                     "fixedshift" 2dpoint
                   | "fixedscale" 2dpoint
                   | "fixedspin" angle
                   | "fixedcenter" 2dpoint
                   | "shift" <float> <float>
                   | "spin" <float>
                   | "scale" <float> <float> <float> <float>
                   | "center" 2dpoint
                   | object

(CustomWaterLevel.cxx/CustomWaterLevel::read) β€” waterLevel:

       waterLevel :=
                     "height" <float>
                   | material
                   | object

(CustomWeapon.cxx/CustomWeapon::read) β€” weapon production:

       weapon :=
                     "initdelay" <float>
                   | "delay" <float>{1..*}
                   | "type" <flag_short_name>
                   | location

(CustomWorld.cxx/CustomWorld::read) β€” world:

       world :=
                     "size" <float>
                   | "flagHeight" <float>
                   | object

(CustomZone.cxx/CustomZone::read) β€” zone, kept exactly as it appears:

       zone :=
                     "team" <integer>{1..*}
                     "flag" ("good" | "bad" | <flag_short_name>){1..*}
                   | "safety" <integer>{1..*}
                   | "zoneflag" <flag_short_name> <integer>?
                   | location

🌈 SEE ALSO 🌈

that’s the whole rest of the BZW(5) grammar, bestie β€” sourced from BZFlag 2.4.30, dated 2025-04-19. periodt πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from