Skip to content
This repository has been archived by the owner on May 5, 2021. It is now read-only.

Prefabs

GTD-Carthage edited this page May 22, 2019 · 97 revisions

Prefabricates are user-made constructions that Oblige can use to further add a human touch to its procedurally-generated levels.

Prefabs in Oblige use two files: a typical Doom WAD containing models, and an accompanying LUA script to determine how the prefab is to be used in-game.

Oblige performs CSG (binary operations), to additively combine prefabs into a generated map.

Types of Prefabs

While prefabs fulfill a lot of functions for the game, they can be best categorized by where they are positioned.

  • Edge prefabs are wall and fence sections as well as doors or archways on certain occasions.
  • Diagonal prefabs are diagonal wall and fence sections.
  • Seed prefabs are prefabs that occupy especially designated sections of a map, usually CLOSETS or JOINERS. Things such as lifts, stairs, doors (switch-locked and key-locked or otherwise), traps, and cages all fall under seed prefabs. Seed prefabs heavily rely on Oblige's shape grammar system.
  • Point prefabs are various fabs that are placed directly on the floor, such as crates, pillars, and other freestanding decorative objects along with important points such as item/key pedestals, including start and exit fabs if a closet doesn't exist for a seed fab to spawn in place of. Point prefabs often have different sizes, and Oblige will attempt to place them wherever it fits based on a provided size based on the Chunk is to be placed in.

BEFORE YOU BUILD THAT THANG

There are some important caveats and paradigms to understand when building prefabs for Oblige. Before you start building the mansion of your dreams and expect to appear inside Oblige, you'll want to know the following:

Rely on procedural generation

The goal of Oblige is to procedurally generate maps, which means delegating the creation of rooms and layouts to an algorithm instead of the human doing it. If you wish to alter a map's layout - it is done so via shape grammars (check the Shape Grammars page here for more info) rather than a prefab.

It is better to design a furniture-sized prefab that Oblige can build a house from than a house-sized prefab that you'd want to force Oblige to spawn.

Fat shaming

The size of prefabs greatly matters. Going with the above notion of designing components rather than whole structures Oblige can use, prefabs are limited by their size as, of course, rooms receive the priority before what prefabs in them are decided and placed. Creating overlay huge fabs means there must be enough incidental space and probability for such a huge fab to spawn in the map. The following is an overall size guide:

  • For edge prefabs. If you are just making walls, make it 16-units y, 128-units x. Special edges such as doors and windows can be longer than 128-units x. Edge prefabs can be of any height. Edge fabs taller than the room currently being rendered are disqualified from appearing in that room.

  • For point prefabs. Oblige subdivides rooms into squares called Chunks. Chunks are used for multiple important procedures such as the placement of items and traps but for the concerns of making prefabs, chunks also define a spot where a point prefab can be placed. Larger fabs will basically require more space to appear and sufficiently large fabs may never appear at all by virtue of its size. It is preferable to create fabs within a 256-unit radius. Most decor fabs in ObAddon average around 64-128 units in radius.

  • For seed prefabs. Seed prefabs are placed on especially marked spots of a map, particularly closets and joiners. Closets can contain item closets, monster cages, start closets, exit closets, or sometimes simply just have a decorative seed fab in place. Joiners are prefabs that connect one room to the other.

As of the current shape rules, the following are the current available sizes for closet fabs (as per the current ObAddon shape rules and in seeds [a seed being a single 128x128 unit grid space])

2x1, 2x2, 2x3,

3x1, 3x2,

4x2,

There are special additional sizes but only for Urban Streets mode, due to how ObAddon uses closets to build many of the building facades:

6x1, 8x1,

The following are the current available sizes for joiners:+

2x1, 2x2, 2x3,

3x1, 3x2,

4x1, 4x2,

+ L-shape joiners currently only have a 2x2 rule.

Because joiners are fabs that partially reach through either side of the room, you may also need to add an extra total depth of 32 units such that the joiner will properly align against the walls on either side.

Monkey see, monkey do

The best way to create easily usable fabs for Oblige is to follow what already exists. By extracting the ObAddon package, you can explore how existing fabs are built in the games/doom/fabs directory. It is better to decide what fab to do based on how you want it to appear in the map, before simply just building a fab at random.

What's in Your WAD

A typical prefab WAD can contain multiple prefabs, spread over different MAPs. It is probably preferable to separate prefabs into different WAD's entirely to make it easier to add, remove, and modify what already exists.

In order to start, first create a large room - the actual size of your initial room doesn't matter as it will just house your prefab. Assign all surfaces of this room with the texture '_NOTHING'. All surfaces marked with _NOTHING are essentially ignored by Oblige, allowing the room the prefab is to be placed in to fill in these areas instead.

Set this room's brightness to 144. This is the neutral value used by Oblige. Brighter or darker sectors will be offset against the ambient brightness of the room the prefab is placed in.

Oblige's uses the concept of a 'skin' whereas a 'skin' is a grouping of a flat and a texture. These groupings can be found in the respective games' themes.lua.

The following are special texture names Oblige uses for dynamic texturing:

  • _WALL - Surfaces marked with this will use the wall skin of the room it's in.
  • _FLOOR - Surfaces marked with this will use the floor skin of the room it's in.
  • _CEIL - Surfaces marked with this will use the ceiling skin of the room it's in.
  • _OUTER - If your prefab connects to another room, _OUTER surfaces will be replaced with the wall skin of that room.
  • _FLOOR2 - If your prefab connects to another room, _FLOOR2 surfaces will use the skin of that other room.
  • _CEIL2 - Just like FLOOR2, surface will use the ceiling skin of the other room.
  • _LIQUID - This surface will be changed to the liquid texture chosen for that room. If this room has no liquid, it will default to the default texture specified in themes.lua instead.

A perfectly usable technique is to actually set ceiling textures to use _WALL instead, so it will receive the corresponding flat assigned to that skin. Seed prefabs connecting to outdoor areas especially would rather use _WALL and _OUTER for ceiling textures as opposed to the actual _CEIL due to the tendency for the outdoor sky ceiling to be copied into the seed's ceiling.

If you are making edge or seed prefabs, the south-west bounding box corner of your prefab is the origin point ( 0,0 ). If are making a point prefab, the center of the object is the origin.

What's in Your LUA

Each prefab has its own LUA definitions that change how Oblige will treat this prefab. If you have a box.wad prefab, for example, your script file must be box.lua. Check already existing examples of prefab LUA's as some fields are not required depending on circumstance or between types of prefabs.

A Prefab Struct

Each prefab is encapsulated by a group of fields that look like this:

PREFABS.<name_of_prefab> =
{
  <..fields..>
}

Fields

  • file - this field simply specifies which WAD is to be loaded. e.g. file = "decor/box.wad"
  • map - specifies which map to use for this template.
  • prob - the probability for this object to be spawned.
  • rank - gives a special priority for this object to be spawned. For example, a fab with rank=1 but prob=1 is prioritized for spawning over a prefab with a lower rank, or without a rank that has a higher prob value.
  • where - specifies what kind of prefab this is and where it is to be placed. Options are stated as per above as follows:"edge", "diagonal", "seed", "point"
  • group - this is a field that accepts a string. All prefabs that share the same string on this field will always be used with each other in a single room. (ex: low_gap) If this field is to be used, the group will only be recognized if it's also defined in the game's theme.lua.
  • *kind - this is used to further specify what sort of prefab this is. Oblige actually uses the folder a prefab it's in to identify its kind with this likely overwriting it if declared. (ex: "light" for light fixtures, "arch" for edge openings if the theme has archy_archs set to true in the themes tables)
  • env - specifies the kind of room this prefab should be in. Options are "cave", "park", "outdoor", and "building" with 'building' meaning interior. You can append a ! as a not-operator e.g. "!cave" means not in "caves". Not declaring this field or declaring env="any" means having the prefab spawn in any type of environment.
  • neighbor - used for seed prefabs with adjoining rooms - accepts the same options as env, limiting the acceptable adjoining room type.
  • theme - specifies what theme this prefab can be used in. The themes are "tech", "urban", "hell". Much like the env field, you can use a not-operator as well. Not declaring this field means this prefab will spawn in all themes. For Doom 1-ish games "deimos" and "flesh" are available. For ObAddon specifically, "tech" and "hell" are treated as Deimos theme-compatible fabs. "urban" and "hell" fabs are treated as The Flesh theme-compatible fabs.
  • game - specifies the game this prefab can spawn in such as "doom1", "ultdoom", "doom2", etc. "doom1" and "ultdoom" fabs are considered compatible with "tnt", and "plutonia".
  • engine - specifies what sourceport this prefab can spawn in i.e. "zdoom", "boom", and so on. Not declaring this means this prefab spawns for all sourceports. (you may want to prevent ZDoom slope prefabs from being used in non-ZDoom ports for example) As of Oblige 7.7, Oblige currently only supports "limit" (for any standard limit-removing engine), "boom" for Boom, "zdoom" and "gzdoom" for ZDoom and GZDoom respectively.
  • long - mostly for edge fabs, specifies how long the fab is in raw Doom map units. This is largely unused because seed_w is considered a better measure.
  • deep - specifies the extra depth of this prefab in front of it. (the extra y-axis length, such as on seed prefabs where it must occupy the seed space + the walls opening on either side)
  • over - specifies extra depth of this fab behind it. (same tidbit as above, thus must joiners will have something like deep=16 and over=16 to ensure that the joiner fab meets up precisely with the walls of either room)
  • seed_w - required for seed prefabs and edge prefabs that occupy more than 1 seed - specifies the width (x-axis length) in seeds (remember that 128-units is a single 'seed' in Oblige terms) this will fill. If a prefab, for example, is defined to be 3-seeds wide but the actual model less than that, Oblige will use the x_fit field to determine how to stretch this prefab in that space.
  • seed_h - required for seed prefabs - specifies the depth (y-axis length) in seeds. Much like seed_w, the y_fit field influences how the prefab is stretched across the specified amount of seeds.
  • shape - required for seed prefabs - specifies the implied layout shape of this prefab based on Oblige's shape grammars. Known options are:
    • I - used for straight joiners.
    • L - used for L-bend joiners.
    • U - used for terminating pieces. (closets, wall cages, wall secrets) Does not actually seem necessary.
  • height - specifies the minimum height of the room this object can spawn in.
  • size - required for point prefabs - this determines the size of your point prefab's bounding box from the point of origin. A smaller prefab will find itself easier to spawn than a larger one as large spaces are less common. Most decorative point prefabs such as crates are use 64-units of size.
  • item_kind - if this prefab has a thing of type 8166, item_kind can be used to limit the sort of item that spawns in place of thing 8166 i.e. a key.
  • key - used for key-locked door seed prefabs. Determines which kind of key this door opens against. Options are "k_red", "k_blue", "k_yellow", "k_ALL", "barred". k_ALL means this door only opens when all three level keys/skulls are in your inventory. Barred means this door is to be locked by a switch elsewhere.
  • door_action
  • bound_z1 - the lower bound (in z-axis) of this object's bounding box.
  • bound_z2 - the upper bound (in z-axis) of this object's bounding box.
  • [axis]_fit - Replace [axis] with x, y, or z. This determines how your prefab is stretched on the chosen axis. The following are the options:
    • stretch - this allows your prefab to be rubberband-stretched from end to end, filling the space intended for it.
    • top - for the z_fit option only, this means your prefab is placed from the floor and then the topmost vertices of your prefab will be pulled to the ceiling.
    • bottom - for the z_fit option only, your prefab is placed at the ceiling with the bottom-most vertices pulled down to the floor.
    • frame - your prefab is placed at the dead center. Think center-aligning text. The bounds of your prefab are then pulled to meet the floors/ceilings and so on. Think, uhh, Hellraiser.
    • { r1,r2, ... } - this allows you to specify a specific range around the center of your prefab to be stretched. e.g. { 48,56 }. For example, it would make sense for only the stem of your pillar to stretch, rather than the crown or the base with it. You can have define multiple ranges within the grouping. For example { 24,32 , 64,72 } means the stretching happens between those pairs i.e. useful if you have a double door fab and want the doors themselves to stretch, but not the pillars in between and so on.
  • sink_mode - only option is "never" or simply not declared. This ensures this fab will not spawn in 'sink' areas which are the little sunken sectors Oblige makes such as with liquids on walkable floors or just fancy trims. On ObAddon, roads in Streets Mode are considered sinks. Because of the way sinks are rendered on the CSG side, insufficiently tall fabs will often look broken when rendered over floor sinks, or reach too high into a ceiling sink.
  • solid_ents - true or false. Specifies whether things inside this prefab should have collision or not. You'll want candelabras to block your path, but probably not corpses.
  • open_to_sky - true or false. Seed prefabs with this property will spawn not being inset into a solid stucture such as the items and exit gazebos. As of the current Oblige/ObAddon build, only importants (key-containers, starts, exits) seem to spawn when open_to_sky is declared.

ObAddon-specific fields

  • on_liquids - accepts "never" or "always". Mostly only for edge fabs, this will cause fabs not to spawn or be limited to spawning over liquid seeds.
  • on_scenics - accepts "never". Mostly only for edge fabs, this will cause edge fabs not to spawn in scenic areas. Fake doors over a sheer cliff? That's just too fake.
  • can_be_on_roads - accepts true. Allows a decorative point fab to spawn over a road area in Streets Mode. sink_mode will override this functionality as Street Mode roads are considered sinks. (despite them not being 'sunken', they are simply technically rendered as sinks.)
  • replaces - accepts the name of another prefab. When Epic Textures module is on, this fab replaces the fab in the field based on the behavior defined in the replace_mode field. If the replace_mode field is not defined, it is assumed to be a hard replacement.
  • replace_mode - accepts "hard" or "soft". Hard replacement causes the fab to be replaced to be completely removed along with its templates. Soft replacement simply causes the fab to be replaced have a probability of zero. Soft replacement is preferred most of the time.
  • need_solid_back - accepts true. For edge fabs only, this ensures that the seed behind this edge is completely solid, a necessity for things like fake doors and windows.

Special Fields

  • tex_[wall texture] - this allows you to change a wall texture on your prefab. e.g. tex_BIGDOOR1 = "BIGDOOR5" means any wall with BIGDOOR1 will be changed to BIGDOOR5.
  • flat_[flat texture] - this allows you to change a floor texture on your prefab. e.g. flat_CRATTOP = "FLOOR4_8" means any floor/ceiling textured with CRATTOP will be changed to FLOOR4_8.
  • sector_[special_id] - allows you to change the sector special of all sectors with this existing special.
  • line_[special_id] - functions just like sector_#, except for linedefs.
  • thing_[type_id] - allows you to change all entities of this type to another. e.g. thing_25 = impaled_twitch changes all things with type_id 25 (impaled humans) into impaled_twitch (the animated, twitching version).
  • tag_[id] - this is used in Oblige's quest generation (locked/switched doors). Options are ?switch_tag or ?door_tag.
    • ?switch_tag - linedef with tag [id] is treated as a switch for quest generation. This switch will open some other locked door in the level. This linedef should use reserved special 888.
    • ?door_tag - sector with tag [id] is treated as a door for quest generation.

Special fields can also receive a LUA table whereas you can specify multiple options and respective probabilities. For example:

thing_25 = 
{
  impaled_twitch = 50
  gutted_torso = 50
} 

This means thing_25 can be randomly changed to become an impaled twitching human or a gutted torso with the 50:50 odds. Another example:

sector_1 = { [0]=90, [1]=15 }

This means the sector with special ID 1 can have high odds (90) of being a normal sector, or lower odds (15) to become a sector with randomly blinking lights using sector special 1.

Templates

  • template - using templates, you can create a new prefab definition based on an already existing one. This is for when you want to create, for example, a door that gets different textures but is still the same door model all throughout. For example:
PREFABS.Basic_door = {
  file = "decor/mydoor.wad"
  map = "map01"

  theme = "tech"
  <..other fields..>
}

PREFABS.Basic_door_with_different_texture = {
  template = "Basic_door"

  theme = "urban"
}

In this scenario, Basic_door_with_different_texture copies all the properties of Basic_door, and all declared fields here will overrule whatever is declared from the previous template. Both Basic_door and Basic_door_with_different_texture will both be spawned as two different prefabs by Oblige. In this specific example, Basic_door will only spawn on tech-themed maps, while Basic_door_with_different_texture will only spawn in urban-themed maps.

Reserved Sector Specials for Oblige

  • 992 - WADFAB_REACHABLE - no idea what this does
  • 995 - this marks this sector as a MOVER (lift), and forces bottoms of sidedefs to be unpegged.
  • 996 - this marks this sector as a DOOR, and forces the tops of sidedefs to be unpegged.
  • 997 - WADFAB_DELTA_12 - no idea what this does
  • 987 - WADFAB_LIGHT_BRUSH - even if this sector is marked _NOTHING on the floor and ceiling, Oblige will adopt the sector's brightness setting

Reserved Thing ID's for Oblige

  • 8166 - spot for an item to pickup. Can be influenced with item_kind field to limit what item this should be.

Reserved Linedef Specials for Oblige

  • 888 - this linedef will be used as a switch for quest generation in Oblige e.g. this switch can open some other switched door in the level.

Caged Monsters

  • 8122 - spot for a cage monster with a radius of (I don't think any basic doom critter fits here)
  • 8123 - same as above, but for monsters below a maximum radius of 32 (lost soul)
  • 8124 - same as above, but for monsters below a maximum radius of 48 (imps, former humans, revenants, hell knights, etc.)
  • 8126 - same as above, but for monsters below a maximum radius of 64 (pinkies, spectres)
  • 8126 - same as above, but for monsters below a maximum radius of 128 (like a mancubus or cyberdemon)

Closet/Trap Monsters

  • 8132 - same template pattern as caged monsters above
  • 8133
  • 8134
  • 8136
  • 8138

Common Issues

Texture Alignment

Oblige ignores wall texture pegging set in the WAD. For specific cases such as lifts, texture pegging is achieved instead by using a reserved sector special for Oblige - i.e. 995 for lifts (bottom-unpegged), 996 for doors or crushers (top-unpegged). Any texture with a (0, 0) offset in either x or y-axis will have their alignments based on Oblige's world space, ignoring how it looks in the map editor. Any texture with a non-0 offset will have their texture alignments obeyed by Oblige. In order to force-align a texture that should have a naturally (0, 0) alignment, use (1, 1) instead. Oblige will rectify the offset by subtracting 1.

Thicc Edges

Edge prefabs deeper (longer in y-axis) than 16-units will NOT actually sink into walls, but press out against them. If you want a wall that occupies space behind it, you may want to create a U-shaped seed prefab instead. Beware that if you are also intending to make thicker walls, these walls will eventually interrupt other level geometry such as stairs - make them thick enough, you might as well prevent the player from passing through this area.

Vertex Density

Oblige's CSG seems to explode violently if verts are in coordinates smaller than 4x4 grid spaces. Beware! 4x4 grid space is the smallest safest you can work with.

Error Reporting

Oblige will sometimes be unable to peruse a prefab due to author error i.e. it tries to fit an object into a certain spot, but the actual physical object is much larger than the spot. Unfortunately, vanilla Oblige does not report which exact prefabs are the problems. More detailed error reporting is part of ObAddon's features, particularly with the Debug LOG Control.

Also see: OBLIGE Glossary

Clone this wiki locally