Ultima 7 Object Database

This is an object database for Ultima 7: Black Gate with the Forge of Virtue expansion.

This description is written in a way that can be used as a C++ include fragment if suitable state machine operating functions are defined outside it that match the definition commands. You can probably also write a parser for it.

It names objects from the game that are plausibly a single thing with nontrivial three-dimensional structure and possible animation. Shapes and frames in the game data are treated as views to the objects, with possibly different facing directions.

The default facing direction is south. Rule of thumb is that the "face" of an object is the direction from which a human interacts with it. So the actual face for living things and the side where the human operator is on for machines. If it's neither a creature or an operated machine, go with a "face" that is symmetrical and has more geometric complexity visible. The game's set of shapes has objects facing all cardinal directions.

Try to name items so that closely related items get alphabetically sorted together. Eg. box-sealed and box-unsealed rather than sealed-box and unsealed-box like they're named in the game, because the sprites are practically the same. This makes it easier to find related objects in an alphabetized catalog.

Try to merge things into one object whenever they are plausibly different views or animation states. The one place where alternative states of the same thing are made into different objects is when the states have engine or gameplay significance that's difficult to express with just an animation. Lit light sources emit light while unlit ones don't, and if you break the seal on the sealed Fellowship box, the game script will recognize this. So lit light sources and the unsealed box are separate objects.

Syntax:

The naming function picks the category of the object, all use the same parameter convention.

obj([name]); Start defining a new named object.

Category definitions

  • prop Catch-all category for mostly built large objects that need a custom mesh.
  • human Human character that can use human animations
  • creature Nonhuman creature that is likely to need custom mesh and animation
  • item Small item that characters can pick up and carry.
  • tree Trees
  • rock Natural rocks
  • plant Miscellanous plants.
  • pile Item that forms piles, like coins and lockpicks
  • ammo Item that forms piles and has projectile frames.
  • weapon Item has attack frames
  • shield Default orientation is flat, can have upright frames.

Items are assumed to be lying flat on the ground. Shields have both an item frame (flat) and upright frames.

Definition variants: - prop("objname", 321); All frames in shape 321 make up object's south-facing view. - prop("objname", 321, 0); The first frame in shape 321 is the object's south-facing view. - prop("objname", 321, 5, 7); Views are the sequence of frames from 5 to 7 (inclusive). - prop("objname") Object has no south-facing view, subsequent command will declare an alternative view.

The other variants mostly work similarly. Character definitions are different in that character shapes always have 16 north-facing frames and then 16 south-facing frames, so a character will always be defined like

  • human(321)

Which will then declare the first 16 frames of shape 321 as north views and the rest as south views.

Alternative views

If a view shows the object from a different direction, it can be declared with the name of the direction.

  • east(321); All frames from shape 321 show the object facing east
  • east(321, 0); Only first frame from shape 321
  • east(321, 5, 7); Frames 5 to 7 (inclusive) from shape 321

Similarly for north, west and south. South is the default view so it should not be usually needed, as the frames are already specified when the object is being declared. Sometimes there might be identical frames in later shapes that should be included in the south-facing view though.

There's also - alt(shape, [frame, [frame2]]) for declaring general extended or duplicate view for the default south-facing one. It's used with character definitions that don't really use defined facings.

Offset adjustment

  • offset(x, y); The previous view's sprite needs to be shifted by +x, +y pixels. This is used to center sprites on their bounding box base.

Large objects

Object offsets are given in 3D tile coordinates. Tile coordinates are converted to pixels in the following way: x = tile_x * 8 - tile_z * 4 y = tile_y * 8 - tile_z * 4

Extend uses the same facing direction as the previous statement. Start by declaring the base object for a given view direction, then add the extended objects.

  • extend(tile_x, tile_y, tile_z, shape); Extend the object with all frames from the given shape.
  • extend(tile_x, tile_y, tile_z, shape, frame); Extend the object with the given frame from the given shape.
  • extend(tile_x, tile_y, tile_z, shape, f1, f2); Extend the object with frames from f1 to f2 (inclusive) from shape.

Shape Table

shape_data

Entry looks like this:

889 0 0 0 8 8 0 8 8 33 8 0 33 8 3 1 0.9 0.7 0.1 0.2 0.3 0 1 2 2 3 3 1 Models/3dmodels/lamp-post-0.obj 1 0 889 0 
  • Value 0: Shape ID
  • Value 1: "0":
  • Value 2: "0":
  • Value 3: "0":
  • Value 4: "8":
  • Value 5: "8":
  • Value 6: "0":
  • Value 7: "8":
  • Value 8: "8":
  • Value 9: "33":
  • Value 10: "8":
  • Value 11: "0":
  • Value 12: "33":
  • Value 13: "8":
  • Value 14: DrawType (0=Billboard, 1=Cuboid, 2=Flat, 3=Mesh)
  • Value 15-17: Dimension Tweak (x, y, z)
  • Value 18-20: Position Tweak (x, y, z)
  • Value 21: "0":
  • Value 22: "1":
  • Value 23: "2":
  • Value 24: "2":
  • Value 25: "3":
  • Value 26: "3":
  • Value 27: "1":
  • Value 28: Path to Mesh File ("Models/3dmodels/lamp-post-0.obj")
  • Value 29: "1":
  • Value 31: "0":
  • Value 32: "889":
  • Value 33: "0":