Introduction

It's possible for users to add custom sprites (animations made from pictures) to KeeperFX. Requires version 0.5.0 or newer.

Overview

Dungeon Keeper and KeeperFX use sprites from .dat files for all things in game, like Creatures, Objects, Traps and Projectiles. These are PNG images for every frame of animation, and when available, for each view direction too. The extracted images can be found here.

The custom sprites do not need to be merged into these .dat files, but can be bundled in .zip files, along with a json file that describe how these .png files make up the sprites.

Creating a Custom Sprite
Exporting the PNG files

Sprites in Dungeon Keeper can be as small as 32x32 (wooden barrel) or up to 128x128 pixels large (Hero Gate, big lairs).
Aim at roughly this target resolution when exporting your individual images.

PNGs will automatically be converted to Dungeon Keeper's limited palette.
Try to stay within Dungeon Keeper's limited range of colours. Otherwise, smooth gradients may turn into harsh cut-offs, or rogue pixels may stick out.
If there are issues, programs such as GIMP let you convert and clean up images manually. To import the DK palette into GIMP, use this file. For Photoshop use this file

You should have images for both perspectives (top down and first person).
When not possessing a creature, players look down at the game world at a ~45 degree angle. Top down sprites need to be displayed at this angle too, the exact value is (360 * 266 / 2048). (This is easier by making a 3D model and rendering it from different cameras.)

Simple sprites like the barrel have only 1 rotation.
Their image will act as a billboard and always face the player.

But optionally, sprites can have multiple rotations. They change their image as you rotate your view, faking a 3D appearance.
You'll need 5 rotations: a view from the Front, Right Front, Right, Right Back, Back.
The naming convention is "front", "rf", "right", "rb", "back".
The left side is mirrored automatically.

For animations, the number of frames should be somewhere between 4 (basic lairs) to 12 (Dungeon Heart) or even 16 (spinning spell books and door keys).

Finding or Creating a Model

3D modelling programs like Blender can be used to take a 3D model to then render into images.

Dungeon Keeper's limitations make it simpler than it would be for a modern game:

Details (and small mistakes) will get lost when rendering at such small resolutions.
Texturing is very simple and flat colours will often do the trick.
Simple shaders (e.g. Blender's Toon BSDF, Glossy BSDF) fit better than modern realistic standards.
Light bounces should be set to (near) zero to emulate 3D rendering from 1997.

If you can't make one yourself, many websites such as https://opengameart.org/ offer models for free.

In Blender:

Change "Output Properties -> Output" to define the folder your rendered images will go in.
Keep 8-bit color depth checked.

Check "Render Properties -> Film -> Transparent" to export the sprite with no background.

In the Compositing tab, round transparent pixels. That way, pixels with at least 50% transparency are removed.
Dungeon Keeper sprites are sharp, with distinct outlines. Consider lowering "Film -> Pixel Filter -> Width" to limit blurring further.

Blender template:

Download an example file here

It has 10 cameras set up: 1 for each angle, 5 for each perspective.

I use the Multiple Camera Render plugin to select them all and render all 10 at the same time.

The Pixelate node group in the Compositing tab does 2 things:

  1. Limit the number of colours slightly (to 256) - for more noticeable bands of colours, and easier conversion later.
    Change the first Value in the node group to tweak this.
  2. Round transparent pixels
Creating the JSON file

A JSON file needs to be created to explain to the game how the different png images come together to form a sprite. The easiest way would be to take an existing JSON file from another sprite and modify it for your custom sprite. A json file can be made with any text editor, but using an application that can validate them is recommended, as it's easy to miss a bracket or comma and have the entire file not work.

Enter all the filenames of the images making up the sprite into the json file, following this format:

[ // opening square bracket, for the entire file, needs closing up.
{ // opening curly bracket for each sprite you put in the zip. A comma after each one except the final one.
  "name": "CUSTOM_SPRITE_NAME", //The name given here will be used to assign the sprite to an object. May only use capitals.
  "rotatable": false,  //Set to either true or false, when set to false the first direction is the only one to ever be shown.
  "fp_offset_x": 24, // set these values to find the exact point where the sprite is set the object. Usually you want the bottom middle of the image.
  "fp_offset_y": 95, // The offset can be set per sprite, but also per file. This is at the "file" level.
  "td_offset_x": 23,
  "td_offset_y": 83,
  "fp_shadow_offset": 0, // Offset from bottom line of a sprite how shadow should be drawn for FP view
  "td_shadow_offset": 0, // Offset from bottom line of a sprite how shadow should be drawn for TD view
  "fp": [ // After the configuration settings, add all the directions of first person sprites. The 'fp' name is required, and the square bracket needs closing and a comma.
    [ // Square bracket for each direction. Front, Front Right, Right, Back Right, and Back in that order. A comma after each one except the last one. Non-rotatable sprites need only one direction.
      { // The list of the files for this direction, each file is an animation frame. If there's just one, the object does not animate. Again close each curly bracket with a comma except the last one. It is wise to put all files into a neat folder structure.
        "file": "banner3/fpfront0001.png",
        "offset_x": 23, // Per sprite offset would override fp_offset_x
        "offset_y": 95 // Per sprite offset would override fp_offset_x
      },
      {
        "file": "banner3/fpfront0002.png",
        "frame_flags": 1 // No shadow for this particular image
      },
      {
        "file": "banner3/fpfront0003.png"
      }
    ] //final direction, so no comma.
  ], // next view is coming, so you need a comma.
  "td": [ //The top down files added the same way as the fist person ones, but with unique file names.
    [
      {
        "file": "banner3/tdfront0001.png"
      },
      {
        "file": "banner3/tdfront0002.png"
      },
      {
        "file": "banner3/tdfront0003.png"
      }
    ]
  ] //closing the final view.
} // End of the sprite. Add a comma here if a second one follows.
] // Closing the file

The json file gets zipped in with the image files, and now the sprite file is ready to be used. Be sure to not use compression when zipping, since that adds load times to maps to decompress the zip.

Json parts

Per animation options:

  • name - how this animation would be referenced in other files
  • rotatable means object could be rotated and have multiple views. Each rotation angle should have same number of frames

There are following json options could be applied either to each individual image in animation sequence or for all FP or for all TD of animation They are listed as <per frame> then <First Person per file> then <Top Down per file>

  • frame_w fp_frame_w td_frame_w - width of sprite image (default for whole image size)

  • frame_h fp_frame_h td_frame_h - height of sprite image (default for whole image size)

  • offset_w fp_offset_w td_offset_w - width offset (defaults to 0)

  • offset_h fp_offset_h td_offset_h- height offset (defaults to 0)

  • offset_x fp_offset_x td_offset_x - x offset (defaults to 0)

  • offset_y fp_offset_y td_offset_y - y offset (defaults to 1 - height)

  • shadow_offset fp_shadow_offset td_shadow_offset - distance between bottom line of a sprite and shadow (defaults to y offset)

  • frame_flags fp_frame_flags td_frame_flags - Flags.

    • 1 - means no shadows
Using a Custom sprite on a map

When using a Custom sprite, first be sure it is installed properly. Do this by placing the zip file with the sprite in the \fxdata folder to use it game wide, in the CONFIGS_LOCATION as specified in the campaign/mappack config file to use it campaign/mappack wide, or name the zip file e.g. map00440.zip and place it with the other files of map 440 to use it on that map only. When the sprite is available for KeeperFX, the next step is to configure an object to use the new sprite instead of the default sprite.

Modifying an Object for a campaign or mappack

Objects in KeeperFX by default use sprites from the .dat file, defined on the AnimationID field for every object in objects.cfg. The default objects.cfg file can be found in the \fxdata folder, but the campaign or map pack you want to use it on may have a custom 'object.cfg' in the folder defined on the CONFIGS_LOCATION of the campaign config file. When creating a pack or campaign be sure to make such a custom object.cfg file which holds just those objects that are new or changed compared to the defaults.

The objects.cfg file - like all .cfg bundled with KeeperFX can be edited with any text editor, like notepad++.

When for example you want to make the placeholder statue look like a banner, look for the object in object.cfg:

[object132]
Name = STATUE5
Genre = DECORATION
AnimationID = 958

Then update the AnimationID with the name of the Custom Sprite. If this name is not known to you, open the zip file of the custom sprite, open the json file inside with a text editor, and take the value after "name". It should look something like this:

[object132]
Name = STATUE5
Genre = DECORATION
AnimationID = BANNER

When the sprite is rotatable, you could also set the wind direction of the object. Possible values here are: NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST and NORTHWEST. Add this direction with a colon attached to the AnimationID. This would look like this:

[object132]
Name = STATUE5
Genre = DECORATION
AnimationID = BANNER:SOUTHWEST
Changing an object with the Level Script on a single map

Using the SET_OBJECT_CONFIGURATION script command it is possible to change the AnimationID as well. You can make this conditional on map progress. Define the AnimationID as described in the previous chapter.

An example level script:

REM We should have banners facing south
SET_OBJECT_CONFIGURATION(STATUE5, AnimationID, BANNER:SOUTH)
REM If the heroes are defeated, the banner should face north.
IF(PLAYER1,DUNGEON_DESTROYED >= 1)
  SET_OBJECT_CONFIGURATION(STATUE5, AnimationID, BANNER:NORTH)
ENDIF

You can change between different Custom and default sprites, and wind directions as often as you want, provided you remain within the regular script limits.

It is also possible to bundle a map specific objects.cfg, for a map with number 2345, the file would be named map02345.objects.cfg and should be bundled with the other level files that start with 'map02345'. Here too be sure to only include the difference compared to the bundled objects.cfg

Bundled custom sprites

KeeperFX comes bundled with several custom sprites that are free to use for mapmakers. Look for '.zip' files in the '/fxdata' folder. Some notable ones:

  • fxdata/creatures.zip
  • fxdata/decorative_objects.zip
  • fxdata/natural_features.zip
  • fxdata/trapsdoors.zip
  • fxdata/druid.zip
  • fxdata/time_mage.zip