Puzzle File Syntax

Puzzle files have a .puzzle extension and describe the layout of a single level. In this section, I'll frequently refer to data/puzzles/three-gears.puzzle, the sample puzzle that's listed in our the example expansion pack.

The layout of this document is the same layout as the .puzzle file format. If it seems daunting at first I recommend starting with the "Tiles" section. Things like "Animation" and "Board Layout" are a bit more advanced and for the most part can just be copied and modified from the official puzzles. --Brendan

Header

For every puzzle, the first line indicates the file type and version and should always look like this:

#cogs-puzzle v1.0

Comments

While not required, every puzzle that comes with Cogs includes a comment section following the header. These lines are preceded by the pound sign (#) and are ignored when the puzzle is loaded. Here is the comment block from data/puzzles/three-gears.puzzle.

# Good template for 25 tiles
#
#   0  1  2  3  4
#   5  6  7  8  9
#  10 11 12 13 14
#  15 16 17 18 19
#  20 21 22 23 24

The arrangement of the numbers shown here is a hint left by the puzzle author showing the relative positions of the board space ID's, which will be described in detail below. When creating new puzzle layouts, I strongly suggest putting this type of information in the header comments to make it easy to figure out tile positions and neighbors.

Note that, with a few exceptions, comments can only appear at the very beginning of the file and will cause problems if used elsewhere. Yes, this makes puzzle files somewhat fragile, but this decision was made, in part, to increase loading speed. The other place comments can be safely used are within Gadget definitions, discussed below.

Camera

The next four lines of the puzzle file describe the camera that looks at the puzzle.

CAMERA 0.0 0.0 -12.5
LOOKAT -1.7 0.0 0.0
CAMERAROTATE -0.1 0.0
BACKGROUND data/backgrounds/scroll-metal.dds

The CAMERA position and LOOKAT point describe where the camera exists in space and where it is directed. If we wanted the puzzle to appear in the very center of the screen, we would set LOOKAT to be (0,0,0). Instead, we set the lookat point slightly off-center to leave room for the Heads-Up-Display (HUD) on the left side of the screen. If you have a bigger puzzle, you should increase the values of both the CAMERA and LOOKAT points to make the puzzle appear smaller on the screen.

CAMERAROTATE Gives a rotation, in radians, around the y (vertical) and x (horizontal) axes. We usually start with (-0.1, 0.0) to compensate for the off-center LOOKAT point.

Next, the BACKGROUND keyword references an image file that is loaded for the puzzle background. Image files can have either a .bmp or .dds file type.

Board Layout

This section of the puzzle file describes the layout of the playing area. It starts with the BOARDCOUNT keyword, followed by the number of board positions. Board positions are zero-indexed, meaning that if a board has n tiles, they will be numbered 0 through n-1 (If a board has 9 positions, for example, they will be numbered 0 through 8).

Note: We use two separate types of indices to refer to positions on the board. In some instances, it's most convenient to use the board index, the zero-indexed position in the board described here. On other occasions, we may refer to a tile based on its tile index, the zero-indexed position in the list of tiles, as described in the Tiles section below. As tiles are moved around the board, their tile indices stay constant, but their board indices change.

BOARDCOUNT 25
-1  1 -1  5   0.707 -0.707 0.0 0.0  -2.0  2.0 0  0101
 0  2 -1  6   0.707 -0.707 0.0 0.0  -1.0  2.0 0  1101
 1  3 -1  7   0.707 -0.707 0.0 0.0   0.0  2.0 0  1101
 2  4 -1  8   0.707 -0.707 0.0 0.0   1.0  2.0 0  1101
 ...

Each line in this section can be broken down into the following info:

<leftID> <rightID> <upID> <downID> <rotX> <rotY> <rotZ> <rotW> <posX> <posY> <posZ> <slideOK>

The first four integers, <leftID>, <rightID>, <upID> and <downID> give the board indices of the left, right, up and down neighbors respectively. This is where it's particularly useful to reference the board layout in the comment section described previously. When you consider that many puzzles are 3D, it may seem peculiar that the only possible directions are left, right, up and down. When we create 3D puzzles, we have to "unfold" the surfaces to get a flattened representation. For instance, for the cylindrical puzzles that are 4 tiles high and 10 tiles around, we unwrap the layout into a grid of height 4 and width 10. We then label the neighbors such that the left neighbors of the far-left column match the grid values in the far-right column and vice-versa. Cube and pyramid levels are a bit more challenging to unfold, but the good news is that you already have plenty of example board layouts to choose from.

The next four values, <rotX>, <rotY>, <rotZ> and <rotW> define a rotation for this board position. When a tile is moved into that space, it will be rotated to this position. The rotation is defined as a quaternion, which I don't have time to cover here, but you can find lots of quaternion tutorials on the Web. You don't really need to know anything about them unless you eventually decide to design your own board layouts from scratch.

Next, we have <posX>, <posY> and <posZ>, the (x,y,z) position of this board space.

Finally, we have <slideOK>, four values, each 0 or 1, that indicate whether, from this board space, a tile can move left, right, up or down.

When you load a puzzle in Cogs the board is automatically checked for consistency, so most errors will be caught and reported to you in a console window.

Finish Conditions

The next section of the file lists the conditions that must be satisfied in order for a puzzle to be solved. We start with the FINISHCONDITIONS keyword and the number of conditions that we'll define. This is followed by each FINISHCONDITION, the condition type, and then the custom parameters for that particular condition, listed between open and close curly brackets {}.

FINISHCONDITIONS 15
FINISHCONDITION tileName {
  target  3
  name    tileGearUL
}
FINISHCONDITION location {
  tile    4
  target  4
}
...

All possible condition types are listed here, followed by their parameters.

  • powered: This condition is satisfied if the tile at the indicated board space has a gear that is actively powered by a steam input. i.e., the gauge gadget indicated by the gear's STEAMPOWER keyword is pressurized.
    • TILEID <boardIndex>: The board space ID that must be powered.
  • tune: We use this condition in tune puzzles to check if the correct tune has been played.
    • CHIMETILE <tileIndex> <layerIndex>: The tile index and layer index of a specific chime
    • WINDOWSIZE
    • <code>TIMEERROR <time></code>: The allowable error threshold, in milliseconds
    • <code>ENABLED <true/false></code>: By default this condition is always enabled, but under certain conditions we want to play this chime when we preview the tune solution, but we don't want to require that its tune was properly played in order to detect a solution. There as an example of this in the puzzle Moving Targets II, where we have two chimes that have the same pitch. Rather than checking their tunes, we instead just requires that the chimes are in the right positions.
    • <code>INTERVALS <num> <interval0> <interval1> ...</code>: The number of times we expect this chime to be played in the target tune, followed by the time intervals of each note. For instance, if <interval0> is set to 300 and <interval1> is set to 500, then we require that this chime was struck 300 milliseconds ago (plus or minus TIMEERROR/2) and that it was also struck 500 milliseconds prior to that (i.e., 800 milliseconds ago). I know, this is pretty complicated, but I have good news: We have a cheat code that does this for you. Create your puzzle with empty tune placeholders (INTERVALS 1 0). Launch your puzzle and arrange the tiles such that the tune is being properly played. When the tune is completed, type "ShowTune" and Cogs will print out the 10 most recent intervals for every chime. It's still your responsibility to prune this list down to only the important intervals, but much of the work is done for you.
  • speed: Check the speed of a rotating gear
    • <code>tile <tileIndex></code>: The tile index where we want to check the gear speed
    • <code>comparison <greaterThan/lessThan> <value></code>: Comparison to be made. Note that the comparison is not performed on the absolute value -- adjacent connected gears will have opposite signs for their speeds.
  • noTouch: Especially for tune solutions, we often want to make sure that the player hasn't made any moves while the tune is being played. This condition checks that no tiles have been moved over a given time interval. Note that this condition is ignored when playing in Time Challenge mode.
    • <code>TIME <time></code>: The time interval, in milliseconds.
  • pressurized: Check if steam is getting to a pipe with no leaks in the pressure system.
    • <code>PIPETILE <tileIndex> <layerIndex></code>: The tile index and layer index we want to check for pressure.
  • leakCount: Check for exactly the given number of allowed leaks.
    • <code>NUMLEAKS <numLeaks></code>: The total number of allowed leaks in order for the puzzle to be solved.
  • location: Make sure a particular tile has made its way to a specific location on the board. For a traditional 15-tile slider puzzle with an image, we would need 15 location conditions to check for a solution.
    • <code>tile <tileIndex></code>: The tile index we want to check.
    • <code>target <boardIndex></code>: The board index where that tile must be located.
  • tileName: This is similar to the location condition, except that rather than checking that the tile at a particular board index has a specific tile index, we check that the tile has a specific name. This is useful for verifying conditions where two tiles look identical and can be interchanged.
    • <code>name <strName></code>: The tile name.
    • <code>target <boardID></code>: The boardID where that tile must be located.
  • or: By default we require that all conditions are met in order to detect a solution (i.e., the conditions are connected by a logical AND). But in some cases we need to check for several different solutions. When this happens, we use this condition to perform a logical OR between various conditions. The or condition has slightly different syntax, so here's an example of what it might look like:
FINISHCONDITION or 2 {
  GROUP 1 {
    FINISHCONDITION location {
      tile    6
      target  0
    }
  }
  GROUP 1 {
    FINISHCONDITION location {
      tile    6
      target  1
    }
  }
}
    • <code>FINISHCONDITION or <numOrConditions></code>: This first line tells us how many subgroups of conditions there will be. If any single subgroup of conditions is satisfied, then the solution is found.
    • <code>GROUP <numSubconditions></code>: Each subgroup starts with this syntax, telling us how many subconditions are contained in that group.

Finish Actions

Finish actions dictate what happens after the puzzle is completed -- animations, sounds, volume changes, etc. We start with the FINISHACTIONS keyword and the number of actions that we'll define. This is followed by each action and its accompanying parameters. Here is the beginning of the finish action section of our example puzzle, <code>three-gears.puzzle</code>:

FINISHACTIONS 20
rotate 0 900 -0.1 0.0
animation 0 6 1
...

All possible finish actions are listed here, along with their parameters. Note that all time parameters are expressed in milliseconds and must be integer values. Starting times are relative to the time when the solution was found.

  • pause <code><startFrame></code>: This is the only required finish action for a puzzle. It indicates the time, in milliseconds, at which the iris should begin to close.
  • rotate <code><startTime> <endTime> <rot0> <rot1></code>: Smoothly animate the puzzle's orientation from the current position to the indicated rotation values. The rotation values correspond to the <code>CAMERAROTATE</code> parameters described above in the Camera section. This finish action is useful for moving a puzzle back to its original orientation when the puzzle is solved.
  • vibrate <code><startTime> <endTime> <amplitude></code>: Starting and ending gradually, shake the entire puzzle. This finish action is used when the rocketship levels are completed. The amount of vibration is determined by the floating point amplitude parameter.
  • translate <code><startTime> <endTime> <x> <y></code>: Starting and ending gradually, translate the entire puzzle to the indicated position (with z=0).
  • fadeAudio <code><startTime> <endTime></code>: Over the given time window, fade all music and sound effects to silence.
  • fadeAudioMusic <code><startTime> <endTime></code>: Over the given time window, fade only music to silence.
  • fadeAudioEffects <code><startTime> <endTime></code>: Over the given time window, fade only sound effects to silence.
  • hushAudio <startTime> <code><duration> <targetVol></code>: Over the given time window, fade all music and sound effects to the target volume, indicated as a floating point value between 0.0 (silence) and 1.0 (unchanged).
  • hushAudioMusic <code><startTime> <duration> <targetVol></code>: Over the given time window, fade only music to the target volume, indicated as a floating point value between 0.0 (silence) and 1.0 (unchanged).
  • hushAudioEffects <code><startTime> <duration> <targetVol></code>: Over the given time window, fade only sound effects to the target volume, indicated as a floating point value between 0.0 (silence) and 1.0 (unchanged).
  • animation <code><animId> <tileIndex> <gadgetIndex></code>: Animate a the gadget at the given tile/gadget location. The animationId is a zero-indexed integer that references the list of animation assets, described below.
  • globalAnimation <code><animId></code>: Apply the indicated animation to the entire model. The animationId is a zero-indexed integer that references the list of animation assets, described below.
  • playSound <code><soundId> <startTime></code>: Play a sound at the indicated starting time. The soundId is a zero-indexed integer that references the list of sound assets, described below.
  • scrollerSpeed <code><startTime> <tileIndex> <gadgetIndex> <speed></code>: Starting at the indicated time animate a scrolling canvas at the given tile and gadget location. The speed should be a floating point value. In the original levels included with Cogs this is only used for the end credits.

Models

In the next section of the puzzle file we indicate the 3D models that we'll be displaying. Cogs has a number of preloaded resources that are listed in <code>data/assetLibrary.txt</code>, so this section is for more unusual puzzle assets that aren't commonly loaded. The section starts with the MODELCOUNT keyword, followed by the number of models that we'll be using. After this, we start each model with the MODEL keyword and list the model's parameters between open and closed curly braces {}. Here's what the start of this section looks like in our example puzzle file.

MODELCOUNT 5
MODEL {
  NAME        meshBoard
  MESH        data/models/board5x5-01.obj
}
MODEL {
  NAME        meshSplitGear12
  MESH        data/gears/splitgear12a.obj
}
...

Within each MODEL, the following parameters can be used:

  • NAME <code><name></code>: The name that we assign to this mesh for reference later. The name must not start with a number or contain any spaces. For clarity, we usually start each name with the "mesh" prefix.
  • MESH <code><filename></code>: The file where the mesh can be found, relative to the cogs directory. For many of the meshes used in Cogs, we use a custom .strip file format, but you can also use a standard triangulated .obj file with positions, normals, and texture coordinates.

Note: if you add your own custom models to Cogs, depending on what software you use to make them they may be inverted in the Z axis when loaded by the engine.

Textures

This section of the .puzzle file lists textures (i.e., images) that will be used when rendering this puzzle. One or more textures can be used in each material, as described in the following section. As with models, many frequently used textures are preloaded when Cogs starts. These common files can be found in the global asset library, defined by <code>data/assetLibrary.txt</code>. If we need additional textures we list them here, starting with the keyword TEXTURECOUNT and the number of textures.

TEXTURECOUNT 5
TEXTURE {
  NAME      texGold
  TXFILE    data/textures/gold.bmp
}
TEXTURE {
  NAME      texSilver
  TXFILE    data/textures/silver.dds
}
...

Within each TEXTURE, the following parameters can be used:

  • NAME <code><name></code>: The name that we assign to this texture for reference later. The name must not start with a number or contain any spaces. For clarity, we usually start each name with the "tex" prefix.
  • TXFILE <code><filename></code>: The image file that the texture should be loaded from, relative to the cogs directory. Bitmap (.bmp) and DirectDraw Surface (.dds) file types are supported. The width and height of the image should both be powers of two, e.g. 16, 32, 64, 128, 256, or 512 pixels.
  • CUBEMAP: Use this keyword to indicate that this texture will be used as a cubemap. Cubemap textures must be in the DirectDraw Surface (.dds) format with six cubemap faces.
  • TXTRANSFORM <code><a> <b> <c> <d></code>: If this keyword is used, then the floating point values, a, b, c and d are used to modify the mesh's texture coordinates as the mesh is loaded. The new texture coordinates (x,y) are computed with the equations x=ax+b and y=cy+d.

Note: if you add your own custom textures they usually need to be reversed in the Y axis before showing up in the game correctly.

Materials

Materials list the appearance parameters that define how a model will be rendered in the Cogs engine. This section begins with the MATERIALCOUNT keyword and the number of materials that we will define.

Note that you can use the MatEditor cheat code to activate the realtime material editor while Cogs is running. This will allow you to modify the parameters of a material that includes the EDIT keyword in its material description. The changes to the material will not be saved to file, but you can use the editor to find appropriate material parameters and then copy those values from the console screen to your .puzzle file. This utility will be described in greater detail in the My First Mod section.

MATERIALCOUNT 3
MATERIAL {
  NAME          matBorder
  EFFECT        bumpReflectShadow
  BASEID        texFrame
  BUMPID        texFrameBump
  LIBCUBEMAPID  texGlossmap
  AMBIENT       0.10 0.10 0.10 1.0
  DIFFUSE       0.84 0.84 0.84 1.0
  SPECULAR      1.00 0.95 0.67 1.0 64.0
  BUMPINESS     0.5
  REFLECTION_CLARITY 0.6
  REFLECTANCE   1.0
}
...

Within each MATERIAL, the following parameters can be used:

  • EDIT: If this keyword is placed in the material description, then this material will be the one that gets modified by the in-game material editor. It is a good practice to never use this keyword in more than one material at a time.
  • NAME <code><name></code>: The name that we assign to this material for reference later. The name must not start with a number or contain any spaces. For clarity, we usually start each name with the "mat" prefix.
  • EFFECT <code><effect></code>: The name of the rendering effect that we will use. For modding purposes, this will almost always be <code>bumpReflectShadow</code>, an effect that uses a diffuse texture for the base color, a bumpmap for simulating small-scale surface bumps and a cubemap for specular reflections. In addition, per-pixel specularity can be encoded in the alpha channel of the diffuse texture.
  • BASEID <code><diffuse_texture></code>: The name of the diffuse texture that should be used for this material. This should match one of the texture names defined in the texture section, described above. If you would instead prefer to reference a texture from the global asset library, use the LIBBASEID keyword instead. Note that if the diffuse texture has an alpha channel, then that channel will be used to modulate the specular reflection as described below.
  • BUMPID <code><bumpmap_texture></code>: The name of the normal map texture that should be used for this material. This should match one of the texture names defined in the texture section, described above. If you would instead prefer to reference a texture from the global asset library, use the LIBBUMPID keyword instead.
  • CUBEMAPID <code><cubemap_texture></code>: The name of the cubemap texture that should be used for this material. This should match one of the texture names defined in the texture section, described above. The referenced texture must be defined in the texture section with the CUBEMAP keyword. If you would instead prefer to reference a texture from the global asset library, use the LIBCUBEMAPID keyword instead.
  • AMBIENT <code><red> <green> <blue> <alpha></code>: The ambient color for this material -- i.e., the color that gets multiplied with the diffuse texture everywhere, even in shadow.
  • DIFFUSE <code><red> <green> <blue> <alpha></code>: The diffuse color for this material -- i.e., the color that gets multiplied with the diffuse texture in lighted regions.
  • SPECULAR <code><red> <green> <blue> <alpha> <exp></code>: The specular color. This is the color of the specular reflection at parts of the surface that reflect the light. The <code><exp></code> parameter is used as the specular exponent and controls the size of the specular highlight. Note that the intensity of the specular reflection may optionally be controlled at the pixel level by adding an alpha channel to the texture specified with the BASEID. In this case, the red, green and blue values defined here are multiplied by the alpha channel.

is further controlled at the pixel level by the alpha channel of the diffuse texture.

  • BUMPINESS <code><val></code>: The amount by which the normal map texture influences the direction of the surface normal. 0.0 reduces the influence to zero and 1.0 is the standard value.
  • REFLECTION_CLARITY <code><val></code>: This value influences which mipmap is used when looking up values in the cubemap texture, causing the reflection to look more or less blurry. In general, this value should be zero.
  • REFLECTANCE <code><val></code>: The intensity of the specular reflection. The typical range is from 0.0 (dull) to 1.0 (very shiny).

Animations

Animation sequences used as FinishActions should be defined here. This section starts with the ANIMATIONCOUNT keyword, followed by the number of animation sequences that will be defined. There are two different ways that we can define animation sequences. The following excerpt from a puzzle file shows one example of each animation type. In each case, the parameters for the animation sequence are preceded by the ANIMATION keyword and enclosed in curly braces {}.

ANIMATIONCOUNT 2
ANIMATION {
  NUMKEYS 2 1
  POSKEY 0     0.0 0.0 0.0
  POSKEY 5000  0.0 0.0 -5.0
  ROTKEY 0    1.0 0.0 0.0 0.0
}
ANIMATION {
  TX 4 {
    10 0 0 0
    127 0.2931632653 0.4820994866 0.4820984482
    239 -0.5285714286 0 0
    344 0.5 0.06864767973 0.06864779094
  }
  TY 2 {
    10 0 0 0
    344 9.971428571 5.016702381 5.016706491
  }
  RZ 5 {
    10 0 0 0
    77 0.3205102041 2.150206045 2.150206045
    130 3.150306122 1.025866328 1.025865691
    276 -6.90877551 2.135706591 2.135706591
    344 5 1.744951262 1.744949226
  }
}

For each of these two animation types, we use animation keyframes to set positions and rotations at points in time. Time is measured in frames where we assume a fixed frame rate of 30 frames per second. Note that animations may actually be play faster or slower than 30 fps, in which case we skip frames or interpolate between frame positions to insure that animations always appear to run at a constant speed, independent of the actual framerate.

Auto-Keyframed Animations

The first type of animation shown above is the simplest.

  • NUMKEYS <code><position_keys> <rotation_keys></code>: The number of position and rotation keys that are used by this animation sequence. Each must be an integer value of 1 or more.
  • POSKEY <code><time> <x> <y> <z></code>: The time and position of a single keyframe. Time should be an integer, measured in frames assuming a framerate of 30 fps. The 3D position is defined by the floating point values (x,y,z).
  • ROTKEY <code><time> <w> <x> <y> <z></code>: The time and rotation of a single keyframe. Time should be an integer, measured in frames assuming a framerate of 30 fps. The 3D orientation is defined by the quaternion (w,x,y,z).
  • LOOP <code><start_time> <end_time></code>: Add this tag to loop the animation sequence. Each time the animation sequence reaches the end time, it will jump back to the start time.

If you're familiar with keyframed animations, then you may recognize that this animation definition does not include the derivitives that dictate how to smoothly interpolate between keyframe positions or rotations. Rather than forcing you to define this data explicitly, derivatives are calculated when the puzzle is loaded to guarantee smooth animations. If this doesn't give you the flexibility that you need for the particular animation that you'd like to achieve, then the next animation definition may be a better alternative.

Explicitly Keyframed Animations

As with the previous animation type, this definition uses keyframed rotations and positions with an assumed framerate of 30 fps. But in this case, we add extra data to explicitly set the derivatives of the animation curves.

Each subblock within the animation definition must start with one of the following keywords: TX, TY, TZ, RX, RY, RZ, corresponding to translation or rotation around the x, y, or z axes. This is followed by the number of keyframes for the particular data element and then a list of keys between curly braces {}.

Here's an example showing four keyframes for translation along the x axis, starting at a time of 10 frames (i.e., one third of a second at 30 fps)

  TX 4 { 
    10 0 0 0
    127 0.2931632653 0.4820994866 0.4820984482
    239 -0.5285714286 0 0
    344 0.5 0.06864767973 0.06864779094
  }

Each key within this list contains the time, a key value (which may be either a position or rotation, depending on the subblock type), and input and output derivatives for this key. Calculating these derivative values is difficult by hand. However, this is the type of data used by modeling studios like Maya or 3D Studio Max, so it's often easy to copy and paste these values from other tools. Lazy 8 Studios has a Maya plugin that we use to export animations, so contact us if you would like to use this plugin.

Sounds

Sounds that are used as FinishActions should be defined here. This section starts with the SOUNDCOUNT keyword, followed by the number of sounds that will be defined.

SOUNDCOUNT 1
SOUND {
  WAVFILE data/sounds/prop.wav
  LOOP
}

Each individual sound starts with the SOUND keyword, followed by its parameters nested between curly braces {}.

  • WAVFILE <code><filename></code>: The path to the audio file, relative to the cogs directory. Any .wav file is supported -- mono or stereo at any sampling rate.
  • LOOP: Add this keyword if you want the audio sequence to loop. For instance, this keyword is used for prop and wheel sounds that should be played until the puzzle animates off of the screen.
  • NOFADE: In many cases, a FinishAction fades the audio when a puzzle is completed. Add this keyword if this particular sound should not fade in volume with the rest of the sounds. This keyword is used for the tune played at the completion of the Jack-in-the-Box puzzles.

Tiles

This is the heart of your puzzle file, where you lay out your puzzle tiles and define which gadgets -- such as pipes, gears, chimes or hammers -- will be placed on each tile. This sections tarts with the TILECOUNT keyword, followed by the number of tiles. Note that one of the most common errors when editing a .puzzle file is to add or remove a tile without modifying the TILECOUNT accordingly.

Each individual tile begins with the POSITION tag and a board index to define where the tile should be positioned, as described in the Board Layout section above. If the position index is -1, then the tile will be at position (0,0,0) with no rotation; this is usually used for stationary parts of the puzzle like the decorative frame.

Next, we have the LAYERCOUNT keyword and the number of gadgets that will be used for this tile. This is followed by a list of gadgets, each of which starts with the GADGET keyword, another keyword to indicate the type of gadget, and the gadget parameters, listed between curly braces {}. The supported gadget types are geometry, chime, gear, hammer, pipe, gauge, balloon, and scroller.

Optionally, between the LAYERCOUNT keyword and the first gadget, you can also include the NAME keyword, followed by a name for the tile. This is the name referred to by the tileName FinishCondition. The name does not need to be unique, and in fact, in most cases, it is useful to use the same name for several tiles that appear identical.

TILECOUNT  41
POSITION    -1
LAYERCOUNT  1
NAME        tileFrame
GADGET geometry {
  LAYER       0
  MESHID      meshFrame
  MATERIAL    matFrame
}
...

Positioning Gadgets

How a gadget is positioned is defined by its translation and rotation.

Translations are given as values of x, y, and z as if on a 3D grid. A greater value of x shifts a gadget to the right, lesser to the left. A greater value of z shifts up, lesser shifts down. Y moves gadgets closer to the camera (greater value) or away (lesser value), if viewing the tile face on.

Rotations are defined by choosing an axis and adding a rotation value. Rotations are in radians which are just multiples of pi, with 3.1416 being 180 degrees. You can only rotate in one axis at a time, so sometimes the rotate keyword has to be used more than once. For instance...

 ROTATE      1.0 0.0 0.0  -1.5708
 ROTATE      0.0 1.0 0.0 3.1416
 TRANSLATE   0.0 0.35 0.0

...means the gadget will be rotated -90 degrees in the x axis, 180 degrees in the y axis, and shifted slightly outwards from the center of the tile.

In the majority of Cogs puzzles a tile is exactly 1.0 units wide with its origin in the center (and, respectively, each tile is spaced exactly 1 unit away from the next). Therefore, anything translated more than 0.5 or less than -0.5 in x or z will begin to extend past the edge of the associated tile.

Geometry Gadget

This is the simplest type of gadget as it doesn't have any special behavior. In short, it has geometry and a material and it can be set at a particular position relative to the board space where it is currently situated. At a minimum, you should plan to set the parameters for the layer, mesh and material.

Note: Some gadgets have attributes that reference other tiles and layers. When this is done, it's important to distinguish between board indices vs. tile indices and layer IDs vs. layer indices. As explained above, a board index references a position that a tile can occupy. In contrast, the tile index refers to the position in the list of tiles where the tile was defined. As tiles are moved around the board, their tile indices stay constant, but their board indices change.

When this document refers to a gadget's layer ID, then we're talking about any positive or negative number that we assign to a gadget as its operating layer. For instance, a gear with layer ID 99 can only connect with other gears on layer 99. In contrast, the gadget index refers to the zero-indexed position of the gadget in the list of gadgets. i.e., the first gadget on a tile always has gadget index 0, the second has gadget index 1, etc.

  • LAYER <code><id></code>: Gears and pipes on adjacent tiles can only interact with each other if they have the same layer. Use this keyword to set the layer id to an integer value. It is often a good practice to set the base geometry layer -- usually a wooden tile -- to 0, use positive integers for higher layers and negative integers for layers on the back side of the board. Note that gadgets must be listed in increasing layer order.
  • MESHID <code><name></code>: If you want to use a mesh that is listed in the local .puzzle file, use this keyword.
  • LIBMESH <code><name></code>: If you would instead prefer to use a mesh from the global asset library, reference that mesh with this keyword.
  • MATERIAL <code><name></code>: If you want to use a material that is listed in the local .puzzle file, use this keyword.
  • LIBMATERIAL <code><name></code>: If you would instead prefer to use a material from the global asset library, reference that material with this keyword.
  • ROTATE <code><axisX> <axisY> <axisZ> <angle></code>: Rotate the mesh around the normalized axis (x,y,z), by the given angle in radians. This keyword can be used more than once to apply multiple rotations in order. Note that the tile's origin is based on its position in the board layout, described above.
  • TRANSLATE <code><x> <y> <z></code>: Translate the tile to the given position, relative to the tile origin. Note that the tile's origin is based on its position in the board layout, described above.

Chime Gadget

A chime can use any of the parameters described for the Geometry Gadget, as well as the following:

  • SOUNDID <code><index></code>: The zero-indexed ID of the sound that should be played when this chime is struck. This indexes into the array of sounds defined in the local .puzzle file, as described above.
  • RINGVECTOR <code><x> <y> <z></code>: When a chime is struck, it vibrates back and forth along the (x,y,z) vector set here. The length of the vector indicates the maximum amplitude of the vibration.

Gear Gadget

A gear can use any of the parameters described for the Geometry Gadget, as well as the following:

  • ENGINESPEED <code><speed></code>: If this gear should always be powered or if it is steam-powered, indicate the engine speed as a floating point value in radians per second.
  • TYPE <code>engine1</code>: Use this keyword pair if this gear should always be powered.
  • TEETH <code><num_teeth></code>: The number of teeth in a gear. This value is used to calculate gear ratios and make sure that small gears mesh properly with large gears.
  • PEGS <code><peg_code></code>: Pegs can be used to activate hammers which, in turn, strike chimes. To indicate which pegs are active on this particular gear, use a combination of the letters ABCD to activate the pegs at 0, 90, 180 and 270 degrees. For instance, code AC will activate the pegs at 0 and 180 degres.
  • STEAMPOWER <code><tileIndex> <layerIndex></code>: If this gear is powered by steam, there must be a gauge gadget that should be pressurized to activate it. Use this keyword to indicate the tile and layer of the activation gauge. This references the tile index (not to be confused with a board index) and the gadget index (not to be confused with the layer ID) for the activation gauge.
  • SOUNDID <code><index></code>: The zero-indexed ID of the sound that should be played when this gear is turning. This indexes into the array of sounds defined in the local .puzzle file, as described above.

Note: if multiple gear gadgets are added as layers to the same tile, as long as one gear is rotating all gears on that tile will rotate the same (such as in puzzles like Synchro or Gear Layers).

Hammer Gadget

A hammer can use any of the parameters described for the Geometry Gadget, as well as the following:

  • POWERSOURCE <code><boardIndex></code>: The board index of the position where a pegged gear would drive this hammer. Note that since the board index is set to a constant value here, hammers must be stationary and cannot be placed on moving tiles.
  • POWERANGLE <code><angle></code>: The angle, in radians, at which pegs from an adjacent gear can activate this hammer and cause it to strike a chime.
  • CHIMETILE <code><tileIndex> <gadgetIndex></code>: For stationary chimes, use this keyword to indicate the tile index and gadget index of the chime that is struck by this hammer.
  • DYNAMICCHIME <code><boardIndex> <layerID></code>: For puzzles like Moving Targets that use dynamic chimes, use this keyword to indicate the board index (not to be confused with the tile index) and layer ID (not to be confused with the gadget index) of the target chime, aka the hammer's strike zone.

Pipe Gadget

A pipe can use any of the parameters described for the Geometry Gadget, as well as the following:

  • OPENING_L <code><posX> <posY> <posZ> <dirX> <dirY> <dirZ></code>: Add this tag to indicate that this pipe has an opening in the left direction. We use six parameters to indicate the position and direction of the steam or fire emitter that will be activated if this pipe is pressurized and leaking in the left direction. The position (posX, posY, posZ) denotes where the steam effect begins on the tile (in this case, the left preferrably), usually just inside the edge of a pipe. The direction vector (dirX, dirY, dirZ) determines what direction and with what velocity the steam goes once emitted; greater values make for a longer steam or fire jet. An x position of -0.4 with a dirX of 0.1, for instance, will place a steam jet on the left edge of a tile aimed back across the same tile. Increase the dirX to 0.5 and the steam will travel much further. Adding a dirZ of 0.5 will make it shoot at a 45 degree angle.

Note that since many puzzles are 3D, the directions left, right, up and down aren't necessarily accurate for indicating the relative positions of pipes. Instead, these directions usually refer to the relative positions in the unfolded design schematic.

  • OPENING_R <code><posX> <posY> <posZ> <dirX> <dirY> <dirZ></code>: Same as OPENING_L, but used for a pipe opening that faces right.
  • OPENING_U <code><posX> <posY> <posZ> <dirX> <dirY> <dirZ></code>: Same as OPENING_L, but used for a pipe opening that faces up.
  • OPENING_D <code><posX> <posY> <posZ> <dirX> <dirY> <dirZ></code>: Same as OPENING_L, but used for a pipe opening that faces down.
  • LAYERCONNECT<code><numConnections> <layer0> <layer1> ...</code>: By default, pipes can only be connected if they have the same LAYER ID. In some puzzles, like Radiator, we have pipes that go from one layer to another. This is done with the LAYERCONNECT keyword. The first parameter lists the number of other layers that will be connected to this pipe (usually 1). This is followed by a list of LAYER IDs.
  • SOURCE <code>true</code>: Use these two keywords to make this pipe always emit steam.
  • COLOR <code><id></code>: Set the color of the steam. This keyword should only be used if the SOURCE keyword is also used, otherwise the pipe will emit steam the same color as whatever source it is connected to. The following colors can be used:
0 = white
1 = red
2 = yellow
3 = orange
4 = blue
5 = purple
6 = green
7 = grey
8 = fuel (yellow-green)
  • EMIT <code>fire</code>: By default, all leaking pipes emit steam. To change this behavior, use this keyword pair.
  • IGNORELEAKS: Usually, steam-powered gears will not be activated unless there are no pressure leaks leading to the engine. Use this keyword if leaks from this particular pipe should not count toward the total number of leaks. We use this keyword to simultaneously power the cannon and engines in the Trike puzzle.
  • STARTSOUND <code><index></code>: When this pipe is pressurized, play the indicated sound. The index refers to the list of sounds defined locally for this puzzle.

Gauge Gadget

The gauge gadget is very similar to the pipe gadget, but it does a little more work behind the scenes to make sure that the path from the steam source to the guage is pressurized with no leaks. Gauges must be used for inflating balloons or activating steam-powered engines. A gauge can use any of the parameters described for the Pipe Gadget, as well as the following:

  • MATCHCOLOR <code><id></code>: The only steam color that will be accepted by this gauge. Any other colors of steam will be vented from the release valve, described next.
  • RELEASE <code><posX> <posY> <posZ> <dirX> <dirY> <dirZ></code>: Steam of the wrong color is vented from the release valve. The position (posX, posY, posZ) and direction vector (dirX, dirY, dirZ) for the release emitter are positioned relative to the tile's origin. You can change the visual size of the emitter by scaling the length of the direction vector.

Balloon Gadget

A balloon can use any of the parameters described for the Geometry Gadget, as well as the following:

  • STEAMPOWER <code><tileIndex> <gadgetIndex></code>: The tile index and gadget index corresponding to the gauge gadget that must be pressurized in order for this balloon to inflate.

Scroller Gadget

The scroller gadget is currently only used to roll the credits in the final level. It will probably not be useful to modders, but is included here for completeness. A scroller can use any of the parameters described for the Geometry Gadget, as well as the following:

  • LIBSTRING <name>: The name of the string in the global asset library that will be displayed to the scrolling canvas.

Scrambles

This section describes where each tile starts when a puzzle is loaded. There are three separate scrambles listed here -- one for Inventor Mode (SCRAMBLE), one for Time Challenge mode (SCRAMBLETIME), and one for Move Challenge mode (SCRAMBLEMOVES). Each scramble keyword is followed by one position index per tile. Note that this section is optional and may be excluded while the puzzle is being designed.

SCRAMBLE -1 10 22 34 46 47 ...
SCRAMBLETIME -1 10 22 34 46 ...
SCRAMBLEMOVES -1 10 22 34 46 ...

When designing a puzzle, it's often easiest to create the puzzle in its solution state, scramble the tiles in the Cogs engine, and then list the scrambled state of the puzzle and copy the scramble back into the puzzle file. Type the ShowScramble cheat code to list the current scramble position of the puzzle. This can be copied and pasted into the .puzzle file.

Checksum

This section is used to make it harder for players to edit official Cogs puzzles to make their solutions easier to find. The CHECKSUM should be excluded from your custom puzzle files.

CHECKSUM -1493629554 1523658698 -392692245