Omnomnom,
Could you share some details on your map generator algorithm?
the natural environment is created first - rock and lava (perlin noise). Then the output of that gets fed into the room generator. The room generator is very similar to this:
http://roguebasin.roguelikedevelopment.org/index.php?title=Dungeon-Building_AlgorithmThe room are picked from a fixed set of handmade templates. It would be better if rooms were generated procedurally rather than from a small list of templates, but I have no idea how to do that. Here is an example 7x7 template for a roundish room. Each template is a bitmap file, I decided to use that so I could make them with paint rather than needing to make some kind of template editor. Each pixel of the template is a tile:
The orange pixels are walls but also indicate the best places to put entrances. The generator gives them priority when creating entrances. The white pixels are empty. When placing the template over the map empty areas are not hit tested against existing structures or lava which means even though the templates are always square or cuboid the circular templates are really treated at circular, but there's just overhead of the unused empty tiles.
Everything on the map is from templates linking together at entrance positions. Even the corridors and bridges are templates (although they are dynamically created because they have varying lengths).
One thing I am doing differently from the above link is that the generator doesn't modify the map when a template is placed. Instead the template is placed "over" the map in its own layer. Basically each template has it's own X and Y position on the map and coupled with it's width and height (7x7 in the above example) it's possible to query whether the template has a tile at certain map coordinate and ask what that tile is. This wasn't intentional it just happened because i had to mess about with loading them from a bitmap so they had their own grid anyway and then realized it was easier to just pretend they were hovering over the map rather than building them directly into it and throwing them away. It turns out it makes some things much easier though. It makes it simple to move or remove templates after they are placed without having to revert tiles on the map.
It also separates the building process from the design process.
Also because each template represents a room and has a list of live entrances, they can be used as a connection graph. If a template is at position 20,30 on the map and has an in-use entrance at local coordinates (3,3) then you can find out where that leads by finding which template has an in-use entrance on map tile 23,33. It's messy as a connection graph but it does work (eventually).
Additionally with layers it should be possible to more easily copy-and-paste parts of the map a lot easier. Eg copy 3 connected templates and paste them somewhere else. Whereas doing that with a built map is a lot harder because you have to cut around all the other stuff.
the template placement process:
1. Pick a template at random from the handmade templates. Place the template at a random place over the map. This is the initial room. If the placement is invalid then retry until a valid placement is found. Templates can only overlap each other in some ways (eg share walls and entrances). Templates also can't overlap map tiles that contain lava (although I allow exterior walls to overlap with lava to encourage rooms to fit perch at the edge of lava)
2. Add all possible entrance tiles of the placed template to a global list of candidate entrances. Assign each one a priority. If the template has ideal entrance positions (marked in orange on the template above) give those a higher priority.
3. Choose an entrance candidate X from the global list. Higher priority entrances are picked first. This chosen entrance X will be used to expand a new room off of.
4. Create another template. This template is the new room that will be positioned so it joins to the entrance X of the existing room.
5. Choose a random entrance Y from the new template.
6. Join X to Y by positioning/rotating the new template over the map so that its entrance Y lines up with the entrance X of the existing template. Two options are used (50/50): Either a) join them directly (they will share walls this way) or b) place the new room some distance away and connect X and Y with a corridor.
7. Validate the new template placement (and the corridor if one was placed). If either do not validate (eg they overlap an existing template invalidly or overlap lava) then "give up". Remove the new template (and the corridor if one was placed) and go back to step 3. Before going back to step 3 reduce the priority of entrance X. Doing this suppresses entrances that repeatedly fail to work (perhaps there is insufficient space available) and other entrances are given a chance instead.
8. If the new template was successfully placed then set entrance tile X and Y priorities to zero. They they can't be used again. Go to step 3 to continue building.
For bridges everytime a template is placed a check is made to see if any potential entrances border lava on the map. If any do then a line is traced from that entrance across the lava to the other side. A bridge can only be created between two entrances. So first a room has to be created on the otherside of the lava. If one can't be created then the bridge project is abandoned.
The above process leads to a map without loops. Loops are added at the end as mentioned earlier in the thread.