the cutting room mirror

Ultima Underworld: The Stygian Abyss (DOS)

This article has a talk page!
view on tcrf.net

This page contains notes for the game Ultima Underworld: The Stygian Abyss (DOS).

Definition of Terms and Concepts#

Here is listed and explained some terminology and conventions used in the Ultima Underworld game engine and in this article.

Game Name#

This game is often called Ultima Underworld, Ultima Underworld: The Stygian Abyss, UU, UW, UU1, or UW1. All of these mean the same thing.

Zero-based List#

When a number begins with a pound sign it is from a zero-based list. In a zero-based list, #0 is the first item, #1 is the second, #2 is the third, and so on. In a 1-based list, 1 is the first item, 2 is the second, 3 is the third, and so on.

Version#

Some things in this article will be game-version dependant. The game version isn't presented anywhere obvious, it's not on the title screen or in the loading or exiting text. To see the version, be in the main game screen (the one with the message scroll along the bottom) and press ALT+F7. The two main versions in circulation are vF1.50S and vF1.94S (and vF1.99S for Ultima Underworld 2), with the latter being the most recent and recommended one to play. That is the version downloadable from GOG.

Strings#

A string is a string of characters, a block of text. Strings in UW1 are stored in strings.pak and compressed with some huffman-type encoding so they are not visible with a standard file viewer/hex editor. Strings in the file are grouped by purpose into blocks. Curiously, the list of blocks is 1-based while the strings in those blocks are 0-based. Block and string numbers are not necessarily sequential, there can be gaps of unused block and string numbers. Only particularly interesting unused strings will be listed in this article. For a complete list of strings see Hank Morgan or The Ultima Codex for reference.

Critters#

The game engine doesn't distinguish between hostile monsters, friendly NPCs, and mellow/peaceful creatures. All creatures in the game are defined as "critters" and those critters are placed into the levels of the game with a game object number and are assigned attitude (hostile, upset, mellow (or peaceful in UW2), or friendly). The player's actions can change their attitude. Critters are also optionally linked to a name and conversation through the npc_whoami parameter.

Game objects #64-127 map to critter definitions #0-63, which include a critter animation and palette (see below) in the file assoc.anm.

Any critter can be talked to if it has an associated conversation. This

So every critter has an object number, a critter number, a critter animation number, an auxiliary palette number, and a number of animation slots and frames. A critter can have a name and a talkative critter also has a portrait, conversation number, and a string block number. These are the conventions used in this article.

Conversations#

Conversations are stored in the file cnv.ark. There are 320 slots for conversations but not all slots are filled.

A critter placed in a level will have property npc_whoami with a value in the range of 0..255. A value of 0 means the critter gets the generic conversation for the critter, in a slot number that is the critter number plus 256, so slots 256..319 are generic critter conversations. Npc_whoami values of 1..255 link to conversations in those slots. It is not known what conversation slot #0 is used for, possibly a generic catch for generic critters who don't have a generic conversation.

Names are stored in string block 7 starting at 17. A critter with a npc_whoami value greater than 0 has a name stored in string block 7 at string number (npc_whoami + 16). It is possible for a critter to have a name with having a conversation, e.g. a spectre named Warren, the Slasher of Veils.

Generic portraits are stored in the file genhead.gr. Indices to portrait images match the critter number, so for example generic critter #7 will use genhead #7.

Critters with a npc_whoami greater than 0 get their portraits from the file charhead.gr where the indicies are one less than the npc number. So for example npc #1 uses charhead #0.

Each conversation slot contains code to run the conversation in a virtual machine. The names of opcodes and imported functions used by this virutal machine can be seen in the executable, see the strings in uw.exe sub-article. The slot also contains a link to a string block for text used in the conversation. See some examples in the strings sub-article.

See conversations in the conversations sub-article.

Critter Animations#

A critter animation is broken up into pages and each page is defined in a file named crXXpage.nYY in the crit folder, where XX is the critter animation number (not the actual critter number) and YY is the page number and both of these numbers are in octal notation.

A critter animation page contains:

  • a number of slots and each slot has up to 8 frame indices listed. Generally slots serve the same purpose across all critters, for example slot #12 is always the death animation. Slot #13 seems to be a wildcard slot, the animation seems to be a different purpose for each critter. The other exception is the void creatures which have several completely different animations packed into a single critter animation.
  • the frames for the animations and these frames are referenced in the animation slots. The frames don't contain the final pixel colors used to draw the graphic, rather they contain atoms that must be translated through an auxiliary palette to arrive at a game palette color.
  • a number of auxiliary palette to translate the frame's atoms to game colors. A page can contain up to 256 palettes but in reality each animation contain 1-5 palettes. This is how for example the green and gray goblins use the same animation number but are drawn in different colors.

Special Colors#

The game is drawn in a 8-bit paletted graphics mode, meaning there are 256 unique colors that can be used onscreen. However not all 256 colors can be used as plain colors as some have special meanings in the game engine:

  • color #0 is a transparency color that will not normally be drawn (in some cases it will be drawn as black)
  • colors #16-23 are for animating fire and lava
  • colors #48-63 are for animating water
  • colors #251-255 are for translucencies

Translucencies#

The game uses 8-bit paletted graphics which do not use a modern alpha-blending/transparency channel. Translucency effects are achieved via look-up tables in the file xfer.dat. These effects are triggered by a sprite being drawn in certain placeholder colors in the main palette which the engine recognizes and draws using the look-ups to create the translucency effect. When noted in this article that a sprite won't appear in game in the color seen here it means that it was drawn with these place-holder colors and will have a translucent effect in-game.

Silver Sapling Trick#

The silver sapling can be exploited as a means of teleportation. When picking up the sapling it will become a silver seed in inventory. If the player "uses" that seed the game will attempt to plant it about 8 feet in front of the player's character. If that space is an open square (not a triangle) with a dirt floor then the seed can be planted. What the game fails to check for is if there is any obstruction between the player and that 8-foot-away spot. So if the player puts their face into a wall or door or other obstacle and uses the seed then as long as there is clear dirt on the other side the seed will be planted and the sapling will grow. The sapling sets the respawn point for the player, so now all they have to do is die and they will wake up at the site of the silver sapling. Using this technique the player can even get into areas not intended to be entered. See Unused Areas for some examples.

Roaming Sight Spell#

The Roaming Sight spell is a normal part of the game, noted in the documentation, and is not a hack or a glitch. It lets the player move their point of view around the level completely unrestricted. It can be used to find secret areas intended to be found but just as well can view areas maybe not meant to be seen, such as the volcanic shaft cavity in the center of nearly every level.

Daylight Spell#

The Daylight spell is a normal part of the game, noted in the documentation, and is not a hack or a glitch. However it has a feature where it can sometimes get areas to show up on the automap that the player hasn't actually seen. This behavior can be exploited to find secret hidden rooms but also to find areas the developers never intended to be known.

Summon Monster Spell#

The Summon Monster spell AKA Monster Summoning is a normal part of the game and is not a hack or a glitch. When cast it makes a random critter appear in front of the player. These summoned critters will not be hostile and usually will not communicate, but there are a few that do. Of these some will be clones of NPCs found elsewhere in the game but a few are unique and are not normally encountered in the game. For examples see Unseen Named and Conversational Critters.

Ally Spell#

The Ally spell makes nearby critters into allies of the caster. They will attack the next critter that they see the caster attack. There must be some logic errors with it however because often times the allied critters become hostile to the caster in the fray. None-the-less, this spell can be used to turn hostile monsters friendly, opening some conversations that aren't otherwise available in the game. This effect is the same as the Summon Monster spell but with a more predictable outcome.

Confusion Spell#

The Confusion spell sets all nearby critters' attitudes to upset. Some formerly hostile monsters can become conversable, opening some conversations that aren't otherwise available in the game. This effect is the same as the Summon Monster spell but with a more predictable outcome.