Official development blog

Dungeon Prefabs

13 Flares Filament.io Made with Flare More Info'> 13 Flares ×

Procedurally generated maps are great, but even with variety factored into an algorithm it naturally won’t produce anything outside its parameters. This is good in that it keeps the style consistent, but individual areas sacrifice character as a result.

Hand-crafted map pieces can restore some of that character where you really need it, be that interspersed with generated content to mix things up, or at key plot areas where a specific environment is necessary. Prefabs integrated with the rest of the map will really stand out, and be more memorable for it.

prefab_skull

Just a silly example, but writing a separate algorithm to procedurally generate skulls would be overkill.

Prefabs are a way to deviate from what may otherwise be a repetitive experience (even if that repetition is masked behind layer upon layer of random content). They also give players a “common ground” from which to discuss specific parts of a game. The more a roguelike is completely random and unpredictable, the more discussion is limited to “general survival tips.” Static areas open up a whole different category of discussion--”what can we do here” rather than “what can we do when XYZ.”

And it’s not only strategy--a whole new category of stories emerges from static areas, since readers who’ve played the game will have a much clearer idea of where the story takes place, having explored that same area themselves.

Creation

I chose to draw prefabs in REXPaint, assigning different palette colors for each cell type and painting them on the first layer.

prefab_skull_REXPaint

Initial tests used the same palette as the algorithm development program.

Other layers in the image store additional information, because prefabs are obviously about more than just the layout.

cogmind_prefab_skull_REXPaint

I changed the palette to give it the black background similar to what would be seen in game, to simplify the design process.

Above is a fully “rigged” prefab with some test content. Layer 2 (above layer 1) contains map linking/integration information (that yellow ’2′, which I’ll talk about later). Layer 3 is where unique machines/props are drawn (those gray lines and boxes). Layer 4 contains references indicating static object locations (the green letters/numbers).

Any prefab that includes specific objects (most), needs an accompanying text file that describes the objects placed in layer 4.

cogmind_prefab_skull_script

Test data/script for the skull prefab, containing a random assortment of objects.  Ideally this information could be entered/viewed/manipulated directly in the prefab editor, but in the case of Cogmind prefabs and their objects are fairly simple so I’ve opted to use a text file instead.

Objects can be listed in any order, and use any letter or number as a reference. More features, including the potential for randomized objects, will be implemented when necessary--this is just what the game currently needs to get things working on a basic level.

And here it is loaded in game connected to an actual map:

cogmind_prefab_skull_ingame

Entering the skull test in game. (The map generator dropped an extra robot and item into it because the area wasn’t set as off limits to random spawning.)

Integration

The main issue with prefabs is how to connect them to the rest of the map. Letting the map generator do whatever it wants could make a mess of the prefab and defeat the purpose, so dark gray cells surrounding the skull keep the map generator from encroaching on it. Instead we control the connection from the prefab end.

First, based on instructions from a map definition text file the algorithm reads in .xp files (produced by REXPaint), parses them for their contents, then places those cells on the map (at a random position if indicated) before any other generation begins. The yellow cell on the skull example indicates that when corridor-building begins, a 2-wide tunneler will start digging south (the nearest edge) from there, and will eventually connect with the rest of the map.

cogmind_prefab_skull_placement

The section of the map definition file that places a prefab, where the “type” is the file name containing the image. Maps also support other general [FEATURE]s besides prefabs, most useful for designating areas that are off limits to the generator.

Because the features are placed before any tunneling and random generation begins, they also support randomized placement so that, for example, you won’t always find the same point of interest in the same area of a map.

Update 3/16/2016: I’ve since written Generating and Populating Caves, demonstrating how prefabs are integrated with cave maps as part of the post-generation process.

Update 1/11/2017: And the newer Map Prefabs, in Depth covers prefab integration in room-and-corridor style maps, as well as the elements that go into constructing an individual prefab itself.

Uses

Carving skulls and other fun shapes from the map isn’t entirely what I meant by “character.” Prefabs are ideal for more functional layouts that fit specific needs of a game, like special NPC and plot-related areas.

I don’t want to rely on “finding” the right place in a map for a certain encounter to occur. I’ll just build it.

prefab_base

You meet a potential ally in the main hall and if he doesn’t like what you have to say his minions hanging out in side rooms ambush you, otherwise he lets you check out the secret weapon stash in the back. (Or: You use a terrain scanner to find that you can just blast/drill a hole into the back room from another part of the map and take whatever you like ;)

More or less the same method is used to add hand-crafted content to caves, although direct links are used instead of a tunneling algorithm so they don’t get out of control and take over the caves.

prefab_cavebase

Hm, we could walk in the front door… or not.

This is the fifth in a five-part series on procedural maps:

13 Flares Twitter 0 Facebook 0 Google+ 1 Reddit 12 StumbleUpon 0 Filament.io Made with Flare More Info'> 13 Flares ×
This entry was posted in Design, Dev Series: Procedural Maps and tagged , , , . Bookmark the permalink. Trackbacks are closed, but you can post a comment.

4 Comments

  1. Posted July 14, 2014 at 9:48 pm | Permalink

    Thanks! A very insightful series of posts about dungeon design which have forced me to revisit my dungeon design process. Have you though about the following:

    1. Having diggable and undiggable squares in the prefab? I use a “hook” like your yellow 2 icon to link my prefabs to the main map, but I also use the index “-1″ as blank, digable squares, while “0″ are walls which won’t be disturbed during the linking process. Could this allow prefabs to fit more “organically” in to the rest of the level? Is it something you already do?

    2. Having multi level prefabs? That’s something I’m thinking about right now… How do you handle matching stairs up and down within a prefab? How about pits?

    • Kyzrati
      Posted July 14, 2014 at 10:39 pm | Permalink

      Good points for discussion, and I’m sorry for having “forced” you to do anything =p

      1) Ah, I could have expanded on the prefab cell types. They can be set as completely blocked, diggable, doors (as well as a kind of “secret door,” a new mechanic not yet mentioned), stairs (of a specific or general type, and the game will pick from the available pool if there are too many), and of course any specific type of open cell like tunnels, junctions, halls, rooms, caves… (although I probably won’t be using more than tunnels and rooms for open prefab areas). The diggable area is brown in the second REXPaint skull testing image; it’s small and not very noticeable in this case, plus it’s made diggable purely for the link tunneler to use. I’ve done other tests with bigger chunks on the prefab set as diggable for the standard procedural algorithm to fill in. This is precisely to allow more organic integration as you suggest, though it only really makes sense with larger prefabs, and I imagine most of those in Cogmind will be on the smaller side.

      2) Multi-level prefabs aren’t an issue in my case because in Cogmind you aren’t allowed to travel backwards to previous maps. That and due to how the world is constructed, if I really wanted a prefab to lead into another prefab, it could be done at the standard world map organization level. I do/will have multi-level prefabs in X@COM, but that’s because it uses 3D maps and the entire map is built from prefabs, so it’s not quite the same issue you’re dealing with. I can imagine there’s a whole host of problems to address when you’ve got prefabs that can span multiple levels and you need to make sure they are valid in each of their respective maps. In that case I would probably pre-generate as many maps into the future as necessary to make sure all multi-level prefabs are accounted for and confirmed valid.

      Cogmind also doesn’t have the concept of pits, or falling into other levels, because unlike most roguelikes you are constantly traveling up, and traveling to earlier levels, whether intentional or unintentional, has never been a part of the design.

  2. Reiver
    Posted July 15, 2014 at 9:07 am | Permalink

    Looks neat. A query on the example skull, as a rider to the more general question: Are you arranging things so you can declare, eg, “Put a Machine [level x-y] in the eye socket” or is it “I have placed this particular terminal in the eye socket, and there it shall always be”?

    The Vault system of Angband comes to mind -- where you could learn that certain spots would contain unusually valuable treasure, and also potentially powerful monsters -- but you didn’t know the details beyond that until you’d looked.

    • Kyzrati
      Posted July 15, 2014 at 10:18 am | Permalink

      Currently the gray “machines” you see, and the only type supported by prefabs, are non-interactive and exist purely for decoration purposes. For the test, most use the simple “generic” script that tells the engine “this block of ASCII is a single machine.” That’s just an easy way to design more interestingly shaped machines that fit a specific map layout. The generic ones don’t even have names, and differ primarily by integrity so that they aren’t too easy or difficult to destroy at a given depth.

      A script can also specify a name (tag), in which case that machine’s specifications will be drawn from the object file for props, allowing for more machine-specific behavior like exploding, a unique sound, unique name, etc.

      Most non-interactive machines are placed according to algorithms after the map layout is complete. They are all gray, and generally rectangular and therefore not as suited to the unique form-fitting possibilities of drawing prefab-specific machines directly into a REXPaint prefab. You can see a few examples of those here.

      Because I want each standard type of interactive machine to be recognizable, they cannot be drawn with a unique appearance. I will most likely, however, make it possible for prefabs to specify the inclusion of standardized interactive machine(s) (haven’t gotten around to it, but it’s at the top of the to-do list). Later there are likely to be very special types of interactive machines that don’t fall into the normal classification/hacking system, and these will definitely need to be placed in prefabs (because they will be plot related and want to appear in specific locations).

      I’ve been leaning towards writing the next blog post about the topic of decoration and machine/object placement.

      As for items, see the script where it uses a more general “ENGINE” specifier as the type, and sets prototype to true--this would select a random engine, and force it to be from among the prototype category (better parts). Static robot placement will also have some more general scripting possibilities. The system overall will no doubt continue to evolve once I actually start using it ;)

Post a Comment

Your email is never published nor shared.

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>