Hubs not drubs

How to logically connect maps and use puzzle pieces

Prayer wheel

One of the striking features brought by the Hexen series is the hub concept consisting in connecting maps together to form episodes which are not just more-or-less random collections of standalone maps following each other like in Doom or Quake anymore, but a small sub-adventure in itself taking place over a set of strongly connected maps.
In this article we will discuss the various ways the maps within an episode can be connected together in order to form such a whole unit.

Going back and forth

The first and most evident trait of an Hexen II episode is that the maps don't form a forward-only succession but can be navigated back and forth, allowing as many backtrackings as you wish (and sometimes more that you actually wish if you have no idea what to do next, but that's another topic which is enough covered in Follow the Yellow Brick Road).

Quitting one map to the next is pretty simple. Basically you need
  • A trigger_changelevel in map #1 (origin) whose map property contains the name of map #2 (actually the name of its bsp file without extension)
  • An info_player_start in map #2 (destination) where the player will spawn

FAQ
  • What if once in the destination map I want the player to be able to get back to the origin map?
  • Simply make the same as above the other way around, by switching the respective roles of map #1 and #2.

  • What if I want several info_player_start entities in map #2 to get there through various possible routes?
  • Give each info_player_start a distinct targetname and make sure that each trigger_changelevel pointing to map #2 specifies which spawning point must be used by setting the info_player_start's targetname in the trigger_changelevel's target property. Please note it works exactly the same no matter the origin map (can be several times the same map and/or several maps).

    Puzzle pieces

    Some doors or triggers require a "puzzle piece", otherwise they will refuse to open or do anything. That makes a PP (puzzle piece) very similar to a key in Doom or Quake, except that it can take the form of a more fancy artefact (bones, potion, lens, scepter...) which offers a pleasant variety and more interesting/meaningful puzzles to solve.
    The entities susceptible to be made PP-dependent are: func_door, func_door_rotating, func_door_secret, trigger_activate, trigger_multiple and trigger_once.
    Each of them is told which puzzle piece it needs by setting the corresponding PP name in its puzzle_piece_1 property. Actually an entity can be told to need up to four PPs thanks to the puzzle_piece_1 to puzzle_piece_4 properties! Sounds a bit too much? Yes it is, and they at Raven did never use that feature actually. But it does work, I found a use for it in Ice Lake to deal with the net + catch fisherman's puzzle.
    The PP-dependent entities also feature additional interesting features:
    • What message they should display as long as the player doesn't have the needed PP yet (no_puzzle_msg property)
    • Whether firing the entity takes the PP off the player's inventory ("Remove puzzle" spawnflag): the only reason why it shouldn't be checked is that the same PP will trigger multiple things, but as long as the player won't need the PP anymore the good practice is to make sure it's taken out of their inventory, otherwise it could cause a long lasting confusion and inventory mess. Multi-use PP is a weird concept anyway, better stay out of it.
    • Whether firing the entity needs the player NOT having the PP ("No puzzle" spawnflag). Doesn't seem anyone felt like using it so far, but still an interesting concept (the lack of the key could not only prevent the door from opening but also trigger a deadly trap, who knows).
    About the puzzle piece itself, it's always a puzzle_piece entity no matter what kind of objet it represents (would it look like a key, an egyptian crown, a jade skull or whatever). The actual 3D model to use has just to be set in the puzzle_id property (put there the model name without path or .mdl extension, cf. picture below). A more player friendly name also has to be set in the netname property. Unlike most messages (for which you provide the line number of the actual text in the strings.txt file) here directly write your text; it's the one displayed to the player when they pick up the PP, prefixed by a short sentence like "You have acquired the ". You can put any name you like there, so no reason to stick to the fancy names used in the original game, invent your own fancy names!
    Caution with names, tho. There is a largely ignored Hexen II feature cryptically called Info / Frags bound to the 'Q' key to display the player's current puzzle pieces inventory with their names (unlike the traditional HUD showing pictures only without names). The problem is: the names don't come from the netname properties but from the puzzles.txt file instead! So if you use custom names for stock PPs or add your own custom PPs, be sure to bring your custom puzzles.txt as well. Its structure is simple: The first line tells how many lines follow, the others lines are puzzle‌_id net‌name (with a regular space between them; the netname itself can contain additional spaces). The file can be sorted for convenience: the lines order is not relevant.

    All vanilla puzzle pieces
    Comprehensive list of all the puzzle pieces of vanilla Hexen II + Portal Of Praevus with the corresponding puzzle_id
    (Click on the picture to enlarge)


    In order to view the PP 3D model directly in TrenchBroom, replace the puzzle_piece entity definition in your hexen2.fgd file by the one below. Thanks to this definition, you can change the PP's puzzle_id property and see the 3D model instantly updated in the editor. Very handy!
    @PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 16) color(80 0 200) model({ "path": "models/puzzle/"+puzzle_id+".mdl" })= puzzle_piece : "Puzzle piece"
    [
    	spawnflags(Flags) =
    	[
    		1 : "Spawn" : 0
    		2 : "Floating" : 0
    		4 : "Auto get" : 0
    	]
    	puzzle_id(string) : "Puzzle id (no path/.mdl)"
    	message(string) : "Message"
    	netname(string) : "Puzzle piece name displayed when picked up"
    ]

    A PP may take a few spawnflags:
    • "Spawn": The PP is not there from the beginning waiting for the player to pick it up; it only spawns to existence when triggered (like in demo1 - Blackmarsh with the Bones of Loric and the Mithril Transmutation).
    • "Floating": ???
    • "Auto get": To get the PP the player won't actually pick it up like a normal artefact but trigger it instead. Not used in vanilla maps but very useful for some complex settings where the actual PP is not directly something the player can normally pick up (like a catch for the fisherman in Wheel Of Karma's Ice Lake). Beware it will only work if the player is less than 200 units away from the puzzle_piece entity when they trigger it.

    FAQ
  • What if I want to make my own custom puzzle piece?
  • That's not such a big deal. First you must have a 3D model for it (.mdl file). A sprite (.spr file) might even work, who knows. Also make a 2D picture of the piece: it's the one displayed in the player's inventory once the PP has been picked up. The picture must be 26x26 pixels in size. It has to be converted to lmp format (thanks to Fimg). Both must share the same lowercase filename, except for the extension (.mdl v .lmp) which will be your puzzle_id property. Put the 3D model in the models/puzzle subdirectory of your mod and the 2D picture in the gfx/puzzle subdirectory. Create the subdirectories if they don't exist already.
    For the 2D picture, what I usually do is opening the 3D model in QuArK with a black background color, taking a screenshot and copying/pasting the picture in Paintshop to resize it down to the required size.
    Don't forget to update puzzles.txt as well with your PP's friendly name for the Info / Frags feature (cf. above).

    Confusing at first, another entity called puzzle_static_piece also exists. Similarly, puzzle_id is used to specify the 3D model. But this time the entity is only decorative stuff. It's used when the PP picked up by the player had to be brought by them to their final resting place (like the skulls from Mazaera or the crowns of Egypt). When the player arrives to where the PP must be dropped off, what happens behind the scene if that they trigger a PP-dependent trigger_once which removes the PP from the player's inventory and triggers the puzzle_static_piece to make the model spawn at the right place.

    Having spoken several times about the player's inventory, it's time to make it clear that there's a separate inventory for PPs which is not the one used for the various boosters like Quartz flasks, Craters of Might, Glyphs of the Ancients, etc. Although being two distinct storage spaces, they share a common characterics which is that they follow the player wherever they go, and notably from one map to another.
    And that's how we come full circle back to our core problematics which is connecting maps together: PPs are an essential part of the connection since they are objects the player is able to pick up in one map and carry to another map to trigger things there. That is actually the most common and straightforward way to set up cross-maps puzzles.

    Cross-level triggers

    Cross-level triggers are the other possible way to go. It's what you use when you want a player's action in map #1 (like pressing a button) trigger something in map #2 (like a new section of that map opening). Obviously it doesn't especially require any PP.
    It's fairly simple to set up:
    • In map #1 put a trigger_crosslevel entity and check any of its "Trigger 1" to "Trigger 8" spawnflags.
    • In map #2 put a trigger_crosslevel_target entity and check the same "Trigger 1" to "Trigger 8" spawnflag.
    And that's it.
    When the trigger in map #1 is fired, it sets a server flag corresponding to its checked spawnflag. When the player enters a new map, the game checks all the possible trigger_crosslevel_target entities there and triggers them if their own spawnflag correspond to a server flag previously set.
    Since the activation depends on a server flag, it's not a map-specific thing: the same trigger_crosslevel may trigger several trigger_crosslevel_targets throughout the whole episode. You have no way to specify that only the trigger_crosslevel_target located in such or such map should be fired: all of them will be fired anyways upon player arrival. So don't trust the presence of the map property sometimes found in incorrect fgd files: it's useless.

    Another thing concerning trigger_crosslevels is that there are only 8 available flags. Hopefully that would be enough for your needs but if you plan to rely a lot on cross-level activations, 8 might feel short. It's all the more true if you consider implementing cross-episode triggers (not a vanilla thing, but read Ending on a high note to learn how to do that, along with many other interesting things!). It seems that Raven actually coded a way to reset a server flag to allow some reuse of the same slot later on within the same episode, but the code involves a trigger_check entity and looks pretty obscure (to me anyway). Better leave such black magic away and do with what we have. Eight available flags per episode are really not so bad already, and you can always use puzzle pieces on top of that for even more (and more diversified) cross-maps interactions.

    Touch

    Let's not leave this page without a few lines about the touch.
    Although Quake's start map might technically be considered a kind of hub map where the runes play the role of puzzle pieces, it doesn't really fit the common acceptation of the term because it's rather used like a "playable menu" at game level. Concerning Doom or Heretic, they obviously lack any hub system or similar mechanics. Yet each one of those games' episodes has its own coherence brought by a common overall theme, matching ambiences, textures and architectures, relevant monsters, and an increasing difficulty as the player gets closer to the end of the episode (and in all probability a boss battle or any kind of climactic ending).
    Each Hexen II episode has a very strong identity thanks to its maps representing places all located in the same continent. They share the same kind of visuals, use the same sets of buttons, the same distinctive cross-map portals (skull doors in Blackmarsh, trapezoid doors in Mazaera, etc.), feature specific unique monsters and tell a small story of their own through various plaques and successive puzzles conveying sub narrative arcs (quest for the bones of Loric and the Castle key, then quest to get to the Altar of Hunger then quest of the Crystal Golem...). On top of that, each episode in Hexen II has its own flavor as far as gameplay is concerned: clever interwoven puzzles in Blackmarsh, lots of platforms and jumps in Mazaera, straightforward puzzles and hidden rewards in Septimus, etc.
    Those things are all about atmosphere, distinctive touch, and direct or indirect storytelling. And they are what tie a bunch of maps together into an episode at least as much as the cross-level mechanics described above. Don't underrate that aspect when working on an episode. A set of maps doesn't automatically make an episode in its own right just because they're connected by portals: they might as well form a mismatched hodgepodge if you don't pay attention.

    What if you'd like to make an episode out of heterogeneous maps, tho? Then take the vanilla Hexen II way: make your storyline revolve around items dispatched in very different parts of the world and needing to be gathered. That trick tied a whole game together allowing it to feature Middle Ages, Ancient Egypt, Mesoamerica and Greece seamlessly. Why not your own content, then?


    Map names Since a hub is made of several maps, you have to find a name for each. In order to help the player navigating smoothly between them without feeling lost, each map name should ideally be meaningful and relate to the most striking landmark of the map: The Mill, Stables, Reflecting Pool...
    Failing to do so (notably by using too abstract names or proper nouns) may put the player in trouble. Remember Thysis and its Temple of Horus, Temple of Nefertum, Temple of Light, whatever, all looking the same, being equally labyrinthine and having meaningless names adding to the player's perplexity... Even without changing anything else, wouldn't it make things a little clearer just renaming them something more indicative like The Pyramid, The Wheel of Constellations and The Treasure Room respectively?
    Proper nouns are not evil, they can truly add to the storytelling and bring a nice exotic touch. Just be careful not overusing them, and don't hesitate to mix them with more recognizable terms (notice how The Village of Turnabel is easier to figure out compared to if the map would just call Turnabel).

    Want to ask for clarification, report an issue with this trick or propose another one? Drop me an email If you use the trick please credit me and put a link to this website.