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.
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.
Other layers in the image store additional information, because prefabs are obviously about more than just the layout.
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.
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:
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.
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.
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.
This is the fifth in a five-part series on procedural maps:
- Part 1: Procedural Map Generation
- Part 2: Tunneling Algorithm
- Part 3: Cellular Automata
- Part 4: Dungeon Metrics
4 Comments
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?
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.
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.
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 ;)