Enclave
Examples
& Additional Documentation
Version
1.14,
Updated May 2023Written by Shawn Davison, Additional Copy Editing by Melissa Lo ![]() This is meant to be a supplement to the already available Ogier documentation as opposed to a replacement. There won't be too much coverage of areas already dealt with by the main documentation, and it's highly recommend to look through that as well. The information contained within this document is considered to be intermediate, having some knowledge of the tools or experience working with similar engines is assumed. I would also like to extend special thanks to the developers who helped answer some of the questions along the way, and who were involved with the release of this great game and toolset. If you have any questions about the game or tools, feel free to contact me and I'll do my best to answer them. Online communities for discussion of the engine and editing tools are available at the Ogier-Editor Forum and the Enclave Discord Server. Files Included With This Document
Additional Ogier Tips Common Editor Troubleshooting Useful Console Commands Example Map Documentation
File Editing
Sky Listing & Atmospheres Importing Brushes Surfaces, Textures, Models, Sounds, & Animations
Files Included With This Document There are a number of files included with this documentation, the following are for the main examples:
The following files are completely optional: Atmospheres.xmp
- A map
which includes preset skies, NH fog, distance
fog, and sunlight taken from each level in the game.
nodetype.txt - An updated definition file to use with Ogier, adds previously missing functionality. (Goes in ..\Enclave\Sbz1\Dev) Surf_DM01_NoBump.xtx - A surface file which includes the Iellon Dungeon sewer textures without the bump map effect. Surf_LightningAlign.xtx - Example surface file containing a material to help align the lightning texture. (Goes in ..\Enclave\Sbz1\surfaces) SoundExample.mmp - Example of a MMP file used to compile audio files and 'complex' sounds for use with the game. TextureExample.xtx - Example of a XTX file used when compiling textures for use with the game. Gothic.ttf, FontExample.cfg, & FontExample.mpp - Example of files used when compiling fonts for use with the game. The following are also optional, and relate to the File Editing section of this document:
Additionally there are files not included with this documentation which may be downloaded separately: Ogier_Documentation.zip
- The official Ogier documentation which this file and its samples are
a companion to.
Ogier_ModelExample.zip - Example files for compiling custom models. These files are included with the KotT GDK. Enclave_SoundBrowser_Fix.zip - Recompiled audio files and source which can be used for enabling in-editor sound. Enclave_DeveloperTextures.zip - Developer textures for use with Ogier. Useful for blocking out and planning levels. Enclave_NorthernWatch_Source.zip - Source files for the user made survival level 'Northern Watch'. Additional Ogier Tips Below are a number of general Ogier tips to keep in mind.
Common Editor Troubleshooting Below are tips regarding issues which may be experienced with Ogier.
Useful Console Commands Enclave's console can be activated either by adding the line CON_ENABLE=1 to ..\Enclave\environment.cfg, or by renaming the Config.mmp to DevConfig.mmp in ..\Enclave\. (Renaming to DevConfig might also activate a number of additional key bindings.) Once activated, the console is opened using the ~ key. Additional console commands and their usage can be found by typing 'help' into the console and then using Page Up and Page Down to scroll.
Example Map Documentation The following is detailed documentation regarding each example in the included map. Each section describes how the effect is achieved and offers related tips and details. The level also includes a large amount of geometry prefabs for reference or use in your own projects. If you would like to view the precompiled demo map in-game, place it in ..\Enclave\Sbz1\Worlds, then open the in-game console and type 'map sandbox'. When it comes to the scripting, you may see similar things done different ways in some examples. For many cases there are any number of methods to set things up to similar effect, so keep this in mind! Liquids & Fog Flowing
Lava
(Lava that flows, as in Kam-Zara) ![]() The lava flow is made using a spline sheet (Shift + 6) with modified subdivisions and a LAVARIVER material from the Water surface file applied to it. In order to create the effect of being liquid, brushes were added below the spline with the top texture set to *PHYSLAVA (this material has special properties which causes brushes it is applied to act as a liquid with predefined depthfog). In order to make the effect a little more believable, a cm_smoke object was added to create puffs of red smoke rising from the lava, and a sound object was placed with ambient and random sounds. Lava (Simple lava) ![]() Water tiles are used to create 'waving' liquids, and the lava surface here is using a watertile object with the ELM6LAVA material specified. (Water tiles can also have their size, tessellation, and amplitude / period changed.) In order to make it act like a liquid, a brush with the top texture set to *PHYSLAVA is used. A trigger_damage is also placed below the lava surface to hurt any character that falls in. Flowing Water (Water that pushes the player along, as in Jassindra) ![]() The water itself is made using a spline sheet with modified subdivisions and a WILD2STREAM material applied to it. In order to create the effect of being liquid, brushes were added below the spline with the top texture set to *PHYSWATER. These brushes also have their 'Medium_velocity' key set to '3,0,0', meaning they will push the player on the x axis by a speed of 3, and on the y and z axis 0. Water (Water, with and without waves) ![]() Two versions of water are shown. Standard water is simply a brush with a water material applied to the top surface. The more complex is rippling water done using a watertile object and a brush with the *PHYSWATER material below. A trigger_waterjump is also placed along the edge in both examples. When the player enters this trigger, they can press use to leap up and out of the pool. Additional effect is added by a trigger_ext set to play a sound every 3 seconds the player is within the liquid. This trigger only has the 'Player' flag checked so that AI characters won't activate it. Healing Pool (A pool that heals a character, as in Deserted Temple and Ancestors) ![]() This water will heal a character standing in it. To create this effect there is a trigger_ext with a message to damage the $activator by -2 every 0.2 seconds (using a negative value for damage adds health to the target). For effect, a second trigger_ext plays a sound every five seconds a character stands in the pool, and an engine_path is used to create a sparkling particle effect. Toggling Water (Disabling and enabling water) ![]() Water brushes can be disabled and re-enabled through the use of the model_toggle object. After setting your water brush or brushes to this class, you will then want to add values to its 'impulse' fields. In the example, a value of 'none' has been placed into the 'impulse0' field, and a value of 'bspmodel' into the 'impulse1' field (when sent an impulse, the command in the appropriate field will be activated). With this setup, when the model_toggle receives an impulse of '0' it will be disabled and vanish, while an impulse of '1' will make it reappear. A model_toggle can be used to disable or enable any brush and not just water. Changing Water Levels (Changing water levels like in Sanctuary) ![]() Water can be made to move using two methods, both shown in this set of examples. The first uses an engine_path with the *PHYSWATER material applied to the top to create the actual water volume, while a watertile object is parented to it using an added 'parent' key (see the Parenting & Attaching section for more information). Be sure the engine_path has the 'GamePhysics' flag checked otherwise the watertile will not parent properly. If needed, a trigger_waterjump and trigger_ext can also be parented. The second uses an engine_path with a water texture applied to the top surface and the 'GamePhysics' flag checked. In this situation, the animation on the water texture will not work when the path is stopped so I've demonstrated a workaround to solve this. The engine_path has a blank first sequence and the 'AutoStart' flag checked so that the water animation begins playing right away. When the impulse is sent to begin changing the water level, it first stops the path (with an impulse of '0'), and then starts the path's second sequence which is the water's actual movement. Water Leaks (Leaking water, as in Sanctuary) ![]() This effect uses two engine_paths with three particle systems to create the water particles, and a wallmark object to add a water splash on the floor. There is also a sound object with a looping water sound specified. (Note that an engine_path can have up to three particle systems. Add a new key for 'model1' or 'model2' and place an additional particle string into it to do this.) Volumetric Fog / NH Fog (Non homogeneous fog used for the volumetric fog in the game) ![]() NH Fog is seen throughout the game such as in pits, and also for the vertical sunbeams in a couple levels. To create it, simply add a brush and optionally set the texture to *FOG, then convert it to a brush_fog object. In the object properties select the 'Structure' flag. You can also specify the color and resolution of the fog in the properties. In the example, a trigger_damage has also been included within the fog to kill any character that falls in. FogResolution controls the amount of tessellation used for the fog volume. Lower numbers result in more tessellation allowing for (at times) more detailed fog rendering. This can often be left at the default but may be lowered if artifacts are seen or increased if the fog covers a large area. The option to change the 'FogPlane' (i.e. the direction and mid-point of the fog) is also available, but can be left with the default setting for simple pit or ground fog. The first three values plot a point in the X,Y,Z format to use as a vector from 0,0,0 which will be the direction that the fog will travel. An example is '32,0,0' to have the fog travel left to right along the x axis, or '0,0,-32' to have the fog travel top to bottom on the z axis. The last three values are modifiers in the x,y,z format for the location of the plane that acts as the top of the fog (this can be considered the fog's 'sealevel'). When the viewpoint is looking in through this plane the player is outside the fog. When looking out through this plane the player is inside. Note that when the viewpoint moves far enough past this plane the entire fog bush will show, not just up to where this plane is. Any fog_brushes which share a face will be merged into one fog volume. If the brushes use different 'FogPlane' values then artifacts may be visible. Light Beams (Brush based light beams) ![]() These brush based beams were used in levels including The Deserted Temple, The Great Wall, and others. They simply use the DM01_01_14FOG material (DM01_01_14FOG is a material which is transparent and animated to give a light beam effect). The brushes have also had the 'Solid' flag unchecked and 'Air' and 'DualSided' checked to make the light beam passable and (optionally) give the material a double sided look. Note that the 'DualSided' flag can sometimes cause sorting issues if the light beam is in front of another transparent texture (e.g. a window). In this case a brush with a small amount of thickness and the light beam material applied on both sides can be used. A brush_fog with a modified 'FogPlane' can also be used to create light beams, although these are not as flexible. Sunlight Shafts (Shafts of sunlight using volumetric fog) ![]() Vertical shafts of sunlight were used in Iellon Dungeon and The Ancestors and are based on brush_fog objects. The exact setup needed to create this effect is not known, but it appears that a lower FogResolution is used and that the FogPlane values are adjusted, perhaps with multiple fog brushes, to have the fog directed outwards from the shaft center. Dynamics, Hooks, Rotation, & Explosions Fuses
& Explosions
(A fuse which burns down, causing a barrel to explode) ![]() Fuses can be created by plotting out a sequence using an engine_path, and then setting its 'Model' key to 'fuse'. (This will automatically generate a fuse model along the path which will ignite when the engine_path starts.) This engine_path is also given a fuse Timedsound and sets off the rest of the explosion effects from its TimedMsgs. Two emitter objects are used to spawn the actual explosions, and a wallmark object creates a darkened patch on the ground. (Note: To spawn a wallmark it needs to be sent an impulse of '1'.) Finally, as the explosions are being set off, a destroy message is used to make the barrel vanish as if it had been blown up. Crumbling Walls & Camera Shake (Crumbling wall similar to the ones in Iellon Dungeon) ![]() The bricks that make up the collapsing wall are brushes which have been made into dynamic objects. Dynamics allow for the creation of prerecorded physics simulations, even having the ability to hold multiple sequences so different effects can be triggered depending on the impulse sent (refer to the Ogier Documentation for information on creating these). The engine_script in this example uses ShakeCamera message to shake the screen, and also triggers the engine_paths used for dust particle effects. The individual dynamic objects use Timedsounds for the impacts of the various stones. (See the Sound Browser section for some tips on setting sounds for dynamics.) As the falling stone should collide with characters, the 'GamePhysics' flag has been set, while a value filled into the 'Damage' field causing them to hurt any character blocking their path. The 'Pushing' flag can also be checked if the dynamic object should push the player while colliding rather then clipping through them if blocked. Note that the engine_path used to create the physics simulation has been left behind, but as it has the 'Exclude' flag checked, it will not be compiled into the playable level. Breakable Windows (Shattering window like the ones in Divided City and Kam-Zara) ![]() The main window example is set up similarly to those found in The Divided City. The window itself is made up of dynamics which have two sequences recorded, one for falling in either direction. In front to either side of the window is a trigger_destroy which, when damaged, triggers the dynamics to fall in the proper direction (by sending an impulse value matching the needed sequence number). In order to clean up collision, the 'GamePhysics' flag on the dynamics was left unchecked (making them non solid), and instead an engine_path with the *PHYSICAL material applied has been added. This engine_path also has two sequences and will move away from whichever trigger_destroy is damaged. (This makes the window seem solid, but keeps the shards from impeding movement of the player once broken.) A simpler example of one of the windows from Kam-Zara is also included, although only set up with one sequence. Bombs & Arrows (Spawning items, such as a thrown bomb, or arrow) ![]() Emitter objects can be used to spawn a wide array of items or enemies, including bombs or arrows. In this example, a set of three emitters are used to spawn a bomb and two fire arrows. Using the 'Velocity' key, these items can appear to be thrown or launched in the direction the emitter points. Hierarchy (Hierarchy example based on the breakable door in Ark Moor) ![]() This is a simple example showing the idea of a hierarchy when setting up dynamics. Each board has three sections; a top and bottom portion, and a center piece connected to the crossbeam. Damaging any of the top or bottom pieces will cause just that part to break off, while hitting it along the center beam will cause the entire door to collapse. (In this example an engine_script is used to relay this message, trigger_destroys do not seem to support more than one target in their 'Target' key.) Hooks (Used to create complex machinery) ![]() Hooks link objects together with joints. These are used to create the machinery found in Sanctuary, and also for the drawbridge in Kam-Zara. Two examples are included, one with a piston similar to Sanctuary, and one displaying the three common types and their differences. There are five types of hooks all together: hook_norotate (Connect with a joint, this object will move but never rotate.) Such as the piston in the example. The connecting arm pulls it up and down, but its rotation will never change.
hook_to_target (Connect with a joint, this object will rotate to stay lined up with another point.) Such as the rope in the drawbridge example. The rope is connected by a joint to the drawbridge, but rotates so that it's always aligned with the opening above.
hook_to_line (Connect with a joint, constrain the other end to a vector.) Such as the connecting arm in the piston example. One end is connected to the rotating wheel, while the other is only able to move up and down along a defined line.
hook_to_circle (Connect with a joint, allow the other end to rotate to stay within a specified circle or sphere.) The object will rotate from the connected joint to point towards the specified origin. It is 'loose' in that the object will be able to move further from or closer to the origin within the user defined area rather than having to be be connected directly to it.
hook_projectile (Allows an object to be launched like a projectile.) The object will be pushed in the desired direction at a set speed. Note that the velocity does not seem to diminish over time, and the object will continue to move indefinitely. You may want to use dynamics or an engine_path to simulate this instead.
The 'Attach' fields should be in the format of an x,y,z value followed by the name (if required) of the object to attach to. (e.g. '-8,0,128, gatepath'.) The x,y,z coordinates of the mouse cursor can be found in the Status Bar at the bottom of Ogier. In all cases the 'Helpaxis' usually needs to be set to '1,0,0', '0,1,0', or '0,0,1' for the hook to work properly. If the hook vanishes when you run a simulation, try changing this field. Rotation & Wheels (Rotating objects and wheels) Simple rotating objects or wheels with acceleration can be created using an engine_rotate. (The 'Interval' field can be used to make an object that rotates in stages; the first number is how far to turn with '1' being 90 degrees, while the second is the delay to wait before turning again.) The first example includes one of these, but also has a connecting arm which links to a piston (a hook_to_line and hook_norotate). An engine_rotate can be stopped with an impulse of '0'. If it has the 'NeverInterrupt' flag set, it will only stop once it has returned to its original position (rather than stopping immediately). The older (and unused) func_rotateplat object is also available, although it functions differently from engine_rotate. These objects have collision by default and can be stopped by a character blocking them (an effect which can be simulated on other rotating objects using parented triggers). They don't respond to stop messages like an engine_rotate or engine_path does. Enclave's player collision behaves better when standing on a spinning func_rotateplat compared to other objects, though the character's position doesn't keep up with the platform. The Forceorigin key is used to specify an origin point, while the Hookorigin field does not seem to have an effect (objects, including hooks, do not appear to be able to attach correctly to func_rotateplat objects). The engine_wheel can also be used to create wheels which rotate automatically when an object they're attached to moves (these were used on the cannons and catapults in Enclave). In practice they can be a bit unreliable with the direction they turn, so you may want to use other methods to simulate wheels depending on the case instead. An engine_wheel can be connected to an object using the 'Attach' field to set the point where the wheel will rotate, and to specify what it will connect to (x,y,z,name). Another field, 'Attach_radius' should be set to a point on the wheels outer radius. Finally, an axis that the wheel should rotate on should also be set. ![]() Example of an engine_wheel with the 'Attach' point set in the wheel's center, and the 'Attach_radius' set as a point on the outside of the wheel. In all cases axis keys can use negative values to reverse the rotation direction (e.g. '0,0,-1'), and can also include decimals to have rotation to occur on multiple axes but at different rates (e.g. '0.5,0,1'). Rotating objects can also be created using engine_paths. In some cases this allows for better control, for example if the rotation happens at an angle. Pushable Cart (Dynamics rigged up to create a wheeled cart simulation) ![]() To create a physics simulation for this wagon, a mockup was first made using dynamics which had axles being held to what represented the wagon bed. Once a simulation with this had been recorded, the actual wagon geometry was simply added to these dynamics using the Workspace causing them to inherit the movement. (The Workspace window can be found under the View menu in Ogier. You can move geometry into a dynamics hierarchy to add them to the dynamic.) The original wagon mockup has been left in the example, but has the 'Exclude' flag checked so that only the final wagon will be compiled into the level. Doors & Keys Doors
(Standard doors using engine_door and engine_path) ![]() There are two common ways to create doors, either using an engine_door, or by using an engine_path. In either case, you will want to set the 'Attach' key to be the point where the door should rotate from. (You can see the x,y,z coordinates in the Status Bar at the bottom of Ogier.) Generally engine_doors work well for standard doors which open then close, while engine_paths are better if you need more control over the door (e.g. have it open and stay open, or have it open and close based on a lever or other contraption). One or two trigger_ext objects are placed in each example which send an impulse to the doors to open. (Sending an impulse of '2' to an engine_door causes it to open in the opposite direction as normal.) Both types of doors can use the 'userportal' key (you must add this key manually for engine_paths though) which allows them to be linked to a userportal for optimization purposes. When a door is closed the linked userportal will also close, and when a door opens the linked userportal will also open. (Userportals stop the engine from rendering anything behind them when closed.) Note that for AI characters to try and move through closed doors, the 'Navigation' flag should also be checked. If using an engine_path as a door, the 'BlockNav' flag can also be set. Locked Doors (Locked doors that need a key) ![]() Two examples of locked doors are included, each based on a different style found in the game. The first emits a lock rattle sound when approached and prints a message on the screen "You need a key to open this door". This is done using a trigger_ext which can be re-triggered after a delay of five seconds that plays the sound using the door as a source, and sends a Speak message to the nearby narrator object. The narrator object displays the text located in a dialog file on the screen. (In this case, dialog 2 from the DM02 file.) Note that the trigger_ext is only set to send its messages when a player enters it by having the 'Player' flag being the only one checked. Next we have two trigger_exts placed on either side of the door to open it as normal, but both have the 'Waitspawn' flag checked. having this flag checked means these triggers will not be active until a spawn message is sent to them, and so the door will not actually open until this occurs. Another trigger_ext is placed which has the 'Player', 'Use', and 'Once' flags checked and a 'Use Object' set. This trigger will show the use icon once the player carries the item set in the 'Use Object' field, and allow them to activate it. Finally, we have the key itself. This is a pickup object with the key type set in the 'Rpgobject' field. When the player picks the item up, it sets off the 'OnPickup' message which destroys the sound / text trigger (thus disabling the rattling sound and narrator text). Now that the player has the key, when they approach the door the usable trigger will bring up the icon to use the key. Once the key is used, the 'Waitspawn' triggers are spawned and the door will now function as normal. The second door is a simpler example and is similar to the locked log book room door in Ark Amar. This door does not print text to the screen, and the rattling sound only stops once the player uses the key. A re-triggerable trigger_ext with the 'Player' flag checked plays the rattle sound, and another trigger_ext with the 'Player', 'Use', and 'Once' flags checked has the 'Use Object' set to a key. When the key is used, the sound trigger is destroyed and the door opens. AI Scripting Leading
Character & AI Following a Path
(A character that leads the player somewhere) ![]() This shows two methods used when having an AI character lead the player. The first is using an engine_path and the 'Lead' AIImpulse which causes the AI to follow the path but stop and wait before continuing if the player gets too far away (used for the halfling in Divided City). Note that 'Lead' only works if the player character is on the same team (e.g. Light or Dark side). The second uses the 'Follow Me' AIImpulse to have the AI simply follow a path when triggered. (Used for the engineer in Outland Wastes. The engineer moves to a point where a trigger_ext is then activated. Once the player enters this trigger, the engineer will follow another engine_path to the next point and the process repeats.) Note that in both examples the engine_path has the 'GamePhysics' flag checked, AI characters will not follow paths unless this is done. (There are other options to make an AI follow a path as well. A few of these are made note of below, and most are also described in the official Ogier documentation.) Patrolling AI, Walking AI, & Dropping Items (An AI using a patrol path, and one that drops an item) ![]() This example has a goblin following an engine_path as if patrolling. In order to make the path repeat in a loop, the 'Loop' flag has been checked. The 'AutoStart' flag is also checked in this example to make the engine_path begin when the level loads. (Note that the engine_path has the 'GamePhysics' flag checked, AI characters will not follow paths unless this is done.) To make the goblin follow this path, its 'Behavior' has been set to 'Patrol', and the 'Path param' has been set to the engine_path. (Alternately, you could use an AIImpulse such as 'Follow Me' or 'Patrol' for the same effect.) To make an AI walk while not yet alerted, simply lower their 'Idle Max Speed' to '3'. To make an AI drop an item when killed like in this example, add it to the 'Dropitem' field. Note that for the 'Dropitem' field to have an effect, at least one pickup object must also exist in the level. This dummy pickup object does not need to have anything specified. Speaking, Simple Moving, NPC Bar, Protection Missions, & Trigger Filters (Making an AI talk and basic settings for protection missions, as in Celadia Village) ![]() This is a small example with the character Marcus showing how to make an AI speak, use simple movement, add a health bar to the HUD for an AI, end the mission if they die, and have a trigger filter for a specific named object. Making a character talk is done using the 'Speak' message and the value of a line contained within a dialog file. The dialog files for characters can be found in ..\Enclave\Sbz1\Dialogues, and are specified in the AIs 'Dialog' field (see the Dialogs & Subtitles section for more information). The 'SetNPCBar' message with a 'Target' of $player is used to add a health bar of the named object to the players HUD, in this case of the Marcus character (to add a custom name to an AI Character, refer to the Custom Targets section below). This health bar can be removed by using another 'SetNPCBar' message with a different or nonexistent 'NPC' value. To end a mission when a character is killed, set an 'OnDie' message of 'EndRound' with a 'Target' of $game, as well as a condition and 'EndMessage' if preferred. Also shown in this example is moving an NPC using a simple 'Move to Object' AIImpulse. Unlike using paths, this will simply make the NPC attempt to move to the desired location using the navgrid (this appears to be useful for small movements, but unreliable for long distances). The trigger_ext that Marcus moves into is set to activate only for him by using the 'Intersect Objects' field. Placing the name of an object into this field will check anything that enters the trigger for a match before sending its messages. Sitting AI (A sitting AI which stands up when alerted, as in Divided City or Ark Amar. Sleeping AIs are set similarly) ![]() A sitting AI character that is alerted and stands up when a player / enemy walks near, or when injured. The standing up sequence is controlled by the engine_script (engine_scripts are simplified versions of engine_paths intended just for scripting) which has four timed messages. The first targets the AI character with a 'PlayAnim' message and starts the standing up animation. One second in, a 'PlaySound' message is used to make the AI sound surprised. Lastly at 2.3 seconds (when the standing animation ends) the AI character is sent a 'Release' AIImpulse, and shortly after a 'Spot Character' AIImpulse with $player as a 'Target'. This releases the AI from its scripted state, and alerts it to the player's location. The AI character has an 'OnSpawn' message set to 'PlayAnim' targeting $this and an animation value of 'Gameplay\elm_5:10' (starts the AI in the sitting pose), an 'onEnemySpotted' & 'OnInjured' message targeting the engine_script (to begin the standing sequence if an enemy is spotted, or if hit with a projectile), and an 'OnDie' message set to destroy the engine_script (a fail safe to prevent the sound from playing after the orc has been killed). The 'OnStart: Pause' flag is also set to prevent the AI from doing anything unscripted until released. Finally, there is a trigger_ext set for players which also targets the engine_script. (This makes certain the AI runs the stand up script even if it's not alerted directly by the player. Also handy to make the range at which it should stand up more precise.) Dead AI (A dead character with blood decal and arrows) ![]() To create a body, place an AI character and set the 'SpawnDead' flag. You will also need to specify a 'Force Anim'; in this case 'Gameplay\diverse_animation:16' was used. The bloodstain is done using a wallmark object with one of the materials from surf_gore specified. The arrows are simply model objects. Counters (Keeping count in scripting) ![]() For this example and engine_script was used, and is set to count three goblin deaths before revealing a congratulatory message and sound. This is done using the 'WaitImpulse' message which pauses an engine_script or engine_path until the specified impulse is received. In this case, the engine_script is told to wait for two different impulses, while each goblin has an 'OnDie' 'Impulse' message set. The first goblin starts the script which then stops at the first wait impulse, the second goblin starts the script again which then stops at the next wait impulse, and the third goblin starts the script one final time and allows it to complete. Area Infos (Keeping AIs in a specific area) ![]() These act as home areas for AI characters, and are commonly used with wraiths so they don't stray too far outside the level. Simply set the 'Area Param' on the AI to the name of the areainfo. Enemies that are exploring or fleeing will also try not to stray too far from their areainfo if one is provided. Note that areainfos appear to be treated as cubic volumes, i.e. the bounding box of the areainfo rather than its actual geometry. Spawning & Pushing AIs (Spawning an AI, as well as launching them) ![]() Spawning an AI is as easy as setting the 'Waitspawn' flag, and then sending a 'Spawn' message to it. Adding a value to the 'OnSpawn:' numerical field will also push an AI forward when it spawns, perfect for ambushes (such as a goblin jumping out of foliage or from behind a wall). Three examples using these two elements are included. A goblin as described above, spawns and is pushed forward. A Scaara lunging from the water as in Sanctuary. Two engine paths are used for the particle effects; when the first is sent an impulse it triggers the second effect, uses a 'PlaySound' message, spawns the Scaara, and then uses a 'Spot Character' AIImpulse with $player as a 'Target'. A stone gnome being thrown from lava as in Outland Wastes. In this case a model object was used for the particle effects and has been parented to the AI character by adding a 'Parent' key containing the name of the gnome. (Using the 'New Key' button in the objects properties. Parenting is described more in depth below, but in this case it causes the model object to inherit movement from the target, thus making the particle system follow the gnome.) An engine_script spawns the gnome, and then uses the 'SetModelFlags' '1' message to enable the particles. Three seconds later, another 'SetModelFlags' '0' message disables the particles, and shortly after, a 'destroy' message removes the model object entirely. The gnome also has a sound specified 'OnSpawn' to complete the effect. The final example uses an emitter with 'ai_bombardier_l0' in its 'Spawn' field. Although offering less control over the AI character out of the box, this method is useful if you need a spawn to be repeated many times (such as in Naglagard). If it's required to spawn a large number of characters while still having a high level of control, you can create a template xrg file with custom characters. (Refer to the Creating Prefabs and Campaigns & Rewards sections further on for more information on file editing.) You can also push characters using trigger_accpad objects. See the Acceleration Pads section for more information. Switching Weapons (Forcing an AI to switch weapons) No example of this is shown in the sample level, but when it is desired to have an AI change weapons, the 'Switch Weapon' AIImpulse can be used. Leaving the 'Weapon Index' field blank or using a value of '0' will cause the AI to cycle to the previous weapon, while using a value of '-1' will cause the AI to cycle to the next weapon. Forcing AI Off Ledges (Different methods of forcing an AI off a high ledge or doing a precision jump) ![]() AI characters following the navgrid generally won't jump off high ledges, these examples show three different ways of forcing this behavior. The first uses an engine_path with a sequence set up in an arc to imitate a jumping path. When triggered, the engine_path sends a 'Fly Follow Me' AIImpulse to an Assassin which causes the AI to move to, and then follow the path by flying. This gives the effect that the AI is jumping off the edge and landing where the path ends. (Used in Ark Moor for the assassins jumping off the entryway ledges. This is great for precision jumps.) The second is probably not the optimal option, but demonstrates the 'Vector Move' AIImpulse. This forces the AI to move in a specified direction until disabled by other means. (In this case a trigger_ext sets it back to '0,0,0', you could also release the AI to stop the scripted movement.) The third may be one of the most common ways to do this, using an engine_path with a 'Follow Me' AIImpulse targeting the AI character. The AI will simply follow the path and walk off the ledge when doing so. You can also push characters using trigger_accpad objects. See the Acceleration Pads section for more information. Spawning Magic Users (Effects for spawning characters like wizards) ![]() This shows off a few ways magic users can be spawned in the game. One simply spawns in place, while two others have particle trails moving to their location before spawning. Also shown is a wraith following a path which would be used for the Ark Moor liches. (Note that an engine_path can have up to three particle systems. Add a new key for 'model1' or 'model2' and place an additional particle string into it to do this.) The first lich spawns in place similar to those in levels like Kam-Zara. This is done using an engine_path which has two particle systems and, after a slight delay, sends a spawn message to the waitspawned lich character. The next two examples include both a lich and wizard which have particle trails flying through the air before spawning. In both cases there's an engine_path with two particle systems and a spline path to where the magic user will spawn. After a delay, they use timed messages to activate a second engine_path (with the actual spawning particle effects), and spawn the lich / wizard similar to the first example. Note that a feature to average the time of a path is built into Ogier which can be very useful in situations like these. See the Averaging Speed / Time of Paths section for more information. The wraith simply uses an engine_path with a 'Fly Follow Me' AIImpulse to make it fly through the air. In Ark Moor, this was coupled with the above effects to make a lich spawn. Additionally the wraith is sent a 'Look at object' impulse for a second engine_path which is kept slightly ahead of the first, this can be used to prevent an issue where the wraith follows paths while tilted at a 45 degree angle. Wizard Orb & Scripted Sequence (Wizard similar to those in The Guardian, and an example scripted sequence) ![]() This scripting demo uses many of the already mentioned elements, but assembled to make a small sequence. The trigger_destroy sets off the engine_script above the orb when damaged, causing the orb to burst and the wizard's shield to drop. A few things that haven't been mentioned previously are orbs, stopping engine_paths, 'Ghost', 'Immune', and 'Teleport Follow Me'. Orbs can be created using an engine_path or model object, with the string 'sphere' typed into the 'model' field. (Similar to particle systems, there are lots of options to modify these.) To stop an engine_path or engine_script, simply send an impulse of '0' to it. (Used in this sequence to stop the scripts if the wizard dies.) The 'Ghost' AIImpulse is used to enable noclipping mode on an AI. (Used to allow the wizard to float.) The 'Immune' message enables or disables invulnerability for an AI. (Used to make the wizard unable to be injured while behind his shield.) The 'Teleport Follow Me' AIImpulse teleports an AI to the target engine_path, which it then follows. (Used in conjunction with 'Ghost' to make the wizard hover in midair.) Misc Effects Leaf
Dripper
(Used to make leaves spawn and fall to the ground) ![]() Leafdrippers act as a particle system, creating leaves which fall to the ground and then vanish. These are mainly used around trees in the Jasindra level. Sharks (Shark like the ones used in Ark Amar) ![]() Sharks in Ark Amar are engine_paths with the '/Shark' model specified. The paths are then animated to give the appearance of them swimming through the water. Flee Zones (Used to end the mission following a countdown if the player wanders too far) ![]() Fleezones are used to set boundaries to the mission area. When a player enters one, the message 'Leaving mission in 5 seconds' appears and a countdown begins. If the player does not exit the fleezone before the countdown completes, the mission ends. Ending Missions (End a mission in either failure or success and give rewards) ![]() Ending a mission is done by sending an 'EndRound' message with a 'Target' of $game. You are able to set a condition (Lose, Win, Flee, Restart), and a message that will be displayed on the mission end screen. (These messages are set in the StringTable file found in ..\Enclave\Sbz1\registry. Parenting & Attaching (Make objects inherit movement from one another) ![]() Parenting and attaching are two ways to make objects inherit movement from one another, useful for creating more complex effects and for disabling or enabling triggers. Multiple objects can be connected together in a chain through parenting and attaching so that each inherits the others movement. The most common of these methods is parenting, where the name of the object you wish something to follow simply goes in the 'Parent' field. Many objects do not have a parent field listed, and in these cases just click the 'New Key' button in the properties and add a key called 'Parent'. Note that to parent a trigger to a path, the path must have the 'GamePhysics' flag checked. (Also note that standard parenting does not work for making one engine_path inherit movement from another. For these, use the 'Attach' field instead.) Attaching is generally a more precise version of parenting but can be limited to specific cases. A good use for attaching is when needing one engine_path to follow another. In these cases, there is an x,y,z value of the origin followed by the name of the object to attach to. (In this example that looks like '360,-352,28,startstoppath') Note that the engine path which is set to follow another must have at least two keyframes and will only follow while a sequence is active. When activated, the path will update or jump to the current position of the path that it's attached to and then follow it. If the sequence is stopped the path will stop following the path that it's attached to. In the example, there is an engine_path which has both a model and trigger_damage parented to it, while another engine_path is attached to it. When triggered, all the objects will move together as they inherit the first engine_paths movement. Bushes (A rustling bush like those used in the game) ![]() The bush itself is just an object, but it is accompanied by a repeatable trigger_ext with a delay which makes rustling sounds when the player passes through. This is commonly used effect in the games levels. Hanging Skeleton & Spawner (Animated hanging skeleton that spawns an AI when shot, like in Ark Moor) ![]() This is a re-creation of the hanging skeletons in Ark Moor which spawn AI characters when damaged. The hanging skeleton is an engine_path with the '/WorldObjSkel' model which has been animated to swing back and forth. There's a trigger_destroy that sends an impulse to an engine_script when damaged, and this script completes the rest of the sequence. The skeleton AI character is spawned and the engine_path with the swinging skeleton is sent a destroy message. Two emitters are triggered which spawn 'test_dustcloud's to help cover this swap. (You'll also notice that the trigger_destroy is removed by having a 'Destroy' message sent to it. This is due to trigger_destroys absorbing any damage caused within their volume. If the trigger_destroy was left, the skeleton AI could not be injured until moving outside of that space.) Butterflies (Fly around a level, seen commonly in Divided City) ![]() The butterfly object spawns a randomly textured butterfly which will move around the level and land on world geometry. These are common to see in the Divided City level. Ladders (Climbable ladders) ![]() Ladders are made by creating a brush with the *PHYSLADDER material applied to the climbable surface. As in the example, this brush should end around 48 units below the top of the actual ladder. Toggling Sounds & Models (Changing or muting / hiding sounds and models) ![]() Sometimes you may want to activate, deactivate, or change an ambient sound. In these cases, the 'SetSound' message can be used to modify the sound path. (Setting the 'Sound' field to blank will silence it, while placing the name of a sound will activate it.) Models can also be changed similarly by using the 'SetModel' message. (This was used in the Jasindra mission to hide and unhide tree models for optimization purposes.) Rats (Animated rat like those in Iellon Dungeon) ![]() Rats are engine_paths with the '/SewerRat' model specified. The paths are then animated to give the appearance of movement. You'll notice that Timedsounds have also been added so the rat emits squeaks as it moves. Changing Characters & AI Die Trigger (Changing the players character) ![]() Characters can be changed using the 'Switch Character' message. The target will take control of the named character. In the example, this is demonstrated by switching the players character to a spawned paladin AI. A trigger_aidie is also included in this example to demonstrate how it works as well. Any AI character (not the player) that enters it will be killed if they do not leave within the number of seconds specified as the 'Activationdelay'. Lightning (Lightning strike like in Kam-Zara) ![]() The lightning is actually an engine_path with a number of splinebrushes grouped to it. (An engine_path must be created first, and the splines grouped to it through the Workspace after. The Workspace window can be found under the View menu in Ogier.) The S_DEBRISTRAIL_ZALE material should be applied to the splines. When the engine_path is triggered, this texture will begin animating. In this example, a Timedsound is played to emit a thunderclap, and after 2 seconds a 'Destroy' message is used to remove the engine_path (if the path is not removed or stopped, the texture will continue animating). With this documentation, a surface file named Surf_LightningAlign.xtx has been included. Placing this file in ..\Enclave\Sbz1\surfaces will give you an additional material to help align the lightning texture to splinebrushes. Moving Ropes (A trick to make a stationary rope appear to move, like in Sanctuary) ![]() This effect works in a similar (but simpler) way as the above lightning example. The rope is made into an engine_path and textured using the DM01_07_35B material (which has a scrolling animation). When the engine_path is triggered, the rope material will begin to move. When the engine_path is stopped, the rope material will stop moving as well. Teleporters (Teleporter and effects) ![]() Teleporters can be created using a few methods, including using a trigger_teleport as shown in this example. (This is the most common used in the game, and comes with a particle and sound effect built-in.) At its core, this teleporter is simply a trigger_teleport which points a named info_teleport_destination object in its 'Target' field. To create a dust particle effect when a character moves through the teleporter, a trigger_ext has also been placed which covers the same area as the trigger_teleport. This trigger sends a message to an engine_script, which uses the 'SetModelFlags' message to enable the dust particle system of the engine_path, and then disable it after one second has passed. An additional engine_path and sound object are also used to add some more ambient effects to the example. Note that if the info_teleport_destination is placed too close to the trigger_teleport, they player may sometimes retain their orientation when passing through the teleporter rather than facing the direction of the info_teleport_destination. To toggle a teleporter on or off, one option is to parent the triggers to an engine_path (see the Parenting & Attaching section) to move them below ground when it's not to be used. This trick was used in Kam-Zara and Ark Moor. Telefragging occurs with a trigger_teleport / info_teleport_destination if a character teleports to a position intersecting with another character. Cutscenes & Player Control (Camera work and controlling the player) ![]() This example covers both creating a cutscene, and controlling the player character during cutscenes. Engine_paths act as cameras, with the viewpoint facing forward, while cuts between paths can be done using the 'Jump' field (this is entered as time in seconds followed by the target engine_path name. e.g. '5,cutscenepath2'). Cutscenes are started from the first path / camera in the sequence using the 'BeginCutscene' message targeting $player and ended with a 'FadeScreen' message targeting $game with a 'Duration(ms)' of '500' followed by an 'EndCutscene' message targeting $player 0.5 seconds later. When controlling the player as an AI (or to animate and move them), you'll want to use the 'AI Control' message targeting $player. (A 'Param' of '1' switches the player character to AI control, while a 'Param' of '0' returns control to the player. When under AI control, a player can be scripted like any other character and even use AI pathfinding.) In the example, the trigger sends an impulse to the first engine_path right above. This engine_path acts as the first camera, and starts the cutscene by sending a 'BeginCutscene' message. As this scene involves animating the player character, the next message is 'AI Control' with a 'Param' of '1' which disables player control. (Notice that this message has a slight delay following the beginning of the cutscene. This avoids 'jerkiness' when the control is switched from the player to AI.) A 'Teleport Object' message is then used to move the player character to a named object, in this case an engine_script being used as a placeholder, and then a 'PlayAnim' message sets the player character to be laying on the ground. At the five second point, the 'Jump' field takes effect and switches the camera to a second engine_path. (Having being set with '5,cutscenepath2'. This automatically starts the second path as well.) You'll notice that there are still two timed messages left on this first path, one that plays the standing up animation at the same time as the camera change, and another that returns control to the player character just before the end of the cutscene. A little while into the second engine_paths sequence, the cutscene is ended. This is done using a 'FadeScreen' message to fade the screen to black, and then an 'EndCutscene' message shortly after. Note: When the player skips a cutscene, the game effectively fast-forwards to the point where the 'EndCutscene' message is called. This means that even if the scene is skipped, everything that was scripted to have taken place will still have completed. Also, if you would like to override the camera rotating around the players character at the beginning of a level with a custom scene, just start a cutscene immediately using either a path with the 'AutoStart' flag, or a trigger located in the same position as the player start. Note: Ambient sounds that the player is within the radius of may stop when a cutscene is skipped. This can be solved by creating a duplicate set of the problematic sounds and setting them to 'Waitspawn'. At the same time as the 'EndCutscene' message is called, a 'Destroy' message can be sent to the original ambient sounds, and a 'Spawn' message sent to the duplicates. This effectively stops the original sound and re-initializes it. Additional tips for setting up cutscenes include selecting an engine_path and then using Paste camera position to match its orientation to the camera's current position in the 3D view (useful for setting a camera's position and angle), and selecting an engine_path and using Preview camera to preview the camera's view and movement from that path. For information on cutscene levels, e.g. those played before or after missions, refer to the Campaign Challenge Settings section. Using Prefabs (Using the included prefabs and creating your own) ![]() Included with the editor are a number of prefabs of complex objects from the game (such as cannons or Mordessa's portal), and also support for creating your own. There is a bug in Ogier which causes a crash when running a world or physics simulation with some of Enclaves built in prefabs, this example is mainly to show a workaround for this. In the example, there is both a prefab_cannon and a model object. The prefab_cannon will spawn a usable cannon once the level is compiled, while the model is simply an empty visual placeholder for use within the editor. In order to prevent the crash, the prefab_cannon has been hidden by flagging the checkbox next to it in the Workspace, and then grouped with the model object. Creating your own prefabs can be very useful when you wish to create instances of an object where all can be modified at once. They're also very useful for complex geometry that you may wish to move and rotate without having to fix texture alignment (such as the Ark Amar boat example). Refer to the Creating Prefabs section for information on creating your own prefabs. External Geometry / Shadow Casting / Collision (Using external XW files to display pre-lit geometry or add additional shadow casting and collision) Anything with a 'Model' field is also able to use external XW files. This can be used to display external geometry with baked lighting (the lighting in the external XW will remain and will not affect or be affected by the level), or to add additional shadow casting or collision geometry. Two additional keys also exist for the latter, the 'Light_shadowmodel' and 'Physmodel' keys. In all of these cases the value should be the name of a XW file local to the ..\Enclave\Sbz1\Worlds directory (e.g. 'WORLD\LIGHTS\S_Candle01.XW'). An example of these fields in-use are the light and tree models in the game; the shadow casting and collision use external XW files which have been linked to these objects in the Templates.xrg file. Custom Targets & Cannon / Ballista Targets (Custom target information shown on the bottom of the screen, and aiming targets for cannons or ballistas) ![]() This example shows a custom NPC Bar (a health bar displayed on screen with custom text), and target for use with objects such as cannons which displays a targeting circle around it. A trigger_ext has been placed on the crate which acts as a damage target for a cannon. This is done by setting the 'Projectile' and 'Destroyable' flags, and also the 'Explosive' flag for damage type. The 'Hitpoints' have also been set a bit higher than their default. A trigger with these settings will automatically display the aiming circle when the player is using a cannon or ballista. The trigger_ext is also set to display a custom health bar on the screen by adding '§Ltarget_l_msb' into the 'Autotargetname' field. This is an entry found in the StringTable text file located in ..\Enclave\Sbz1\registry. To display this on screen, another trigger_ext uses the 'SetNPCBar' message with the 'Target' of $player and the 'NPC' field pointing to the name of the destroyable trigger. Siege Objects (Player controlled objects or weapons) ![]() Siege objects are player controlled objects which are used to create the cannons, ballistas, and catapults found in Enclave. A number of these are available as prefabs which can be inserted into your own levels, but entirely new siege objects can also be created. The required trigger message, keys, and flags for these have been left out of the default Ogier definition file, but can added either manually, or by placing the updated nodetype.txt file included with this documentation into the ...\Enclave\Sbz1\Dev directory. Use a siege object for the main portion of the controllable item (such as a cannon barrel or body of a ballista), and set the 'Attach' field to the point where it should pivot when being aimed by the player. This object acts like a 'base' while any additional components (such as engine_paths, hooks, or emitters) can be attached or parented to the main siege object. (Note that you may want to enable the 'Unreliable' flag for these objects in order to avoid possible issues.) Siege objects work on the principal that they are first 'charged' and then 'released' before triggering / firing. This is portrayed in three different ways in Enclave; cannons where a delay is present while they charge before firing, ballistas which begin charged and then release when the player presses the fire button, and catapults which allow the player to decide how long to charge and when to release. Additional objects which should be triggered to animate along with the charge and release states (engine_paths, hooks, etc) are added to the siege objects 'Engines' field (separated using commas if there is more than one). When paired this way, the objects will receive an impulse and animate forward while the siege object is being charged, and animate in reverse back to their original position when being released. As an example of this, the limbs of a ballista will bend back when the siege object is charged, and then return to their original position when released. Place a hook object to use as a camera, this can be attached to the siege object if you wish for the camera view to move with it. The name of this object should be entered into the siege objects 'Camera' field. Place an emitter if desired, this can be parented to the siege object so that it moves with it. The name can be entered into the siege objects 'Emitter' field, causing it to trigger when the siege object fires (e.g. for spawning a cannon ball or arrow). To trigger player control of the siege object, a Siege Control message (0x100f) must be sent to it. From here, you'll want to further specify how the siege object should function by using the additional keys and flags which are available. Below is a description of what each of these is used for.
The siege object may also trigger other messages at different points of the objects use. Commonly, you may want to set a Msg_mount and Msg_unmount to send a SetFade message to the $player in order to hide them from view while the object is in use (setting the fade to '0' and '255' respectively). Acceleration Pads (Push a player or character in a direction) ![]() The trigger_accpad object can be used to push or launch a player or AI character in a given direction. These are mainly left over from early versions of the game but may still be useful. They were used in Naglagard to force the enemy characters forward from their spawn areas, although similar results can also be accomplished using scripting. This is done by adding a 'Velocity' key to the trigger_accpad and specifying a direction in the format of x,y,z (e.g. '16,0,32' will bounce the player forward on the x axis and upwards). Use negative values for the opposite direction. Skies, Sunlight, & Distance Fog (Adding a sky, creating sunlight or ambient light, and using distance fog) ![]() Adding a sky, sunlight, and distance fog to a level is done using two objects, a sky_indoor and a light_sky. Note that a map file (Atmospheres.xmp) has been included with this documentation which contains preset skies, NH fog, distance fog, and sunlight taken from each level in the game. The name of any skies from ..\Enclave\Sbz1\skies can be entered into the 'Sky name' field found in the sky_indoors properties (alternately, check the list of skies included in this documentation). Any surface textured with the *SKY material will display the chosen sky and emit sunlight (if any). Distance fog in the level can also be controlled here, including the distance fog for when the player is underwater (note that if you experience issues with the fog culling geometry, try placing a positive number in the 'XR_FogCullOffset' field to offset the default culling distance). The light_sky object is used to create sunlight in a level, make it easy to quickly light outdoor spaces. The below image can be used as reference for the sunlight's direction. In the 'Direction' field there are three numbers; the first two correspond to the x / y position within the sky, while the third number acts as the sun's angle. ![]() Workspace Layers (Adding a 'group' to the Workspace for more a organized editor workflow) ![]() Placing a layer object in your level will add a new layer group to the Workspace. (The Workspace window can be found under the View menu in Ogier.) Sections of your level can be placed into these layers, making it easier to locate specific geometry / objects, or simple to hide / show entire areas of a map all at once. More information on the Workspace can be found in the official documentation. Note that if you don't see anything listed when you open the Workspace window, try selecting one of the View type radio buttons near the bottom (e.g. Tree View). Submaps (Specifying additional XMP files to be compiled together as one level.) ![]() The Submap field of the worldspawnobject allows listing additional XMP files which will be compiled into the final level. This can be useful for splitting up large levels into multiple files for easier editing and to limit the areas compiled while testing a level. And example of this is how the citadel of Ark Moor is one map, while the surrounding terrain is a submap. Submaps can also be useful as 'skyboxes', or geometry that will be rendered outside of the playable area behind the sky surfaces (again, similar to Ark Moor), or for collaboration such as allowing different artists to work on different areas of a level. Multiple XMP files can be specified separated using semicolons, e.g. 'SubMap1.xmp;SubMap2.xmp'. Once compiled all maps are treated as part of the same level, and scripting (e.g. triggers, messages) work across maps and their submaps. To access this property, select worldspawn from the top of the Workspace window. Submap visiblility can be toggled in Ogier from View > Show submaps. ![]() (In the image above the grey box is the primary map, while the orange and blue geometry are additional XMP files that are included as submaps during compile.) User Portals (Optimize a level by helping control what may be rendered) ![]() An optimization tool to help split a level up into renderable chunks, and also control exactly when certain areas are rendered. These are great to place in doorways between areas. To create one, texture one surface of a brush with the *USERPORTAL material, and then convert the brush into a func_userportal. 'Portalstate' is a value with '0' for closed, and '1' for open. 'Portalcloseddistance' is a value that will automatically close a portal when the player is at a set radius, and open it once they are within. Note that userportals can be linked to engine_doors and engine_paths using the 'Userportal' key (for engine_paths, you'll need to add the 'Userportal' key using the 'New key' button). When one of these doors opens, the linked userportal will also open and, when closed, the linked userportal will also close. Sending an impulse to a userportal can also open it with an impulse of '1' or close it with an impulse of '0'. Structure (Structure helps block visibility, improving the performance of levels) ![]() Structure brushes are an important element of optimization, but must be used carefully as they can be taxing on the CPU. There is a good section describing these further in the official Ogier Documentation which I recommend reading (also note, although the official documentation states that a level will need to be encased in structure brushes to compile, this is not the case). At least one structure brush must be present in a level for it to load in-game. To create a structure brush all that's needed is to set the 'Structure' flag in its properties. Commonly, the *NOOVERLAP material is applied on all sides as well, but this is not a requirement. ![]() (Pictured is an example of how a structure brush can be used to block visibility. In the left image, no structure brush is used, and it can be seen that the engine is rendering excess geometry and objects behind the wall. In the right image, a structure brush has been added inside the wall, blocking the visibility and hiding the excess geometry and objects. Use the console commands 'xr_drawmode 1' and 'xr_drawmode 0' to enable and disable wireframe view in-game, this is useful to see what the engine is drawing at any given time.) Structure brushes can also occupy the same space as the level geometry. ![]() (In the above image the structure brush occupies the same space as the visible geometry. In this case you may wish to group and hide your structure brushes to avoid z-fighting and difficulty selecting the bush that makes up the wall in the editor.) Brushes with a Sky texture applied are special in that they can be used as stucture brushes while still remaining visible in-game. ![]() (In the above image the brushes that make up the sky may be used as structure brushes.) Structure brushes with the *AIR material applied to all surfaces can also be used to further hint at areas that might not always be visible to the player. In these cases, the structure brush can be placed surrounding the area or geometry that should be hidden when out of view. Using these is often unnecessary, but they might still come in useful. ![]() (Pictured is a situation where an *AIR structure brush might be used to further hint at an area that should be hidden when out of view, in this case the area behind a low wall and gate. Also note that a func_userportal was also placed in the position where the gate would be, further ensuring that visibility is blocked when the gate is closed.) Particle Control (Turning particle systems on and off) ![]() As listed in examples above, the 'SetModelFlags' message can be used to enable or disable a particle system. A running particle system can be stopped with a 'Flags' of '0', and started with a 'Flags' of '1'. Intermission Cameras (Camera used when at the character select screen) ![]() The info_intermission object is a camera whose viewpoint is displayed when loading a level using the 'map' console command. This camera can be parented to an engine_path using the 'parent' field in order to animate it. Note that the info_intermission is only able to inherent the movement of the first path it is parented to (an exception is if it is parented to another object which is then itself parented to the path - this however may result in jerky movement). Orbs (Orb models used for magical shields) ![]() Orbs can be created using an engine_path or model object, with the string 'sphere' typed into the 'Model' field. (Similar to particle systems, there are lots of options to modify these.) These are used for the magic users' shields, breakable orbs in levels such as The Guardian, and the shields that must be destroyed in the Vatar level. Gold & Special Awards (Gold and special award items such as maps) ![]() The gold is simply a pickup_coin object, while the reward map is made using a pickup object along with an engine_script and narrator. The reward map is added by placing a pickup object with its 'Rpgobject' set to 'mapscroll'. When picked up, it sends an impulse to the engine_script above via its 'OnPickup' message. The engine_script then uses a 'Speak' message to have the narrator print text on the screen from a dialog file, a 'PlaySound' message to emit the pickup sound, and a 'SpecialAward' message with a target of $game to activate award '0'. (Once activated, the award(s) specified in the Campaign.xrg will be given upon completion of the mission.) Refer to the Campaigns & Rewards section for information on how to link this to unlocking a special reward during a campaign, and also information about increasing a campaign's maximum gold if adding gold to a campaign level. Sounds (Ambient and random sounds) ![]() In a sound object, the sound fields are for single or looping sounds, while the RS (random sound) fields are for randomized sounds. If there should be a delay before the sound plays, place the number before the sound name, e.g. '1.3, door_mt03mv1' Sound objects can be used to place ambient or random sounds in a level. Placing an ambient sound is as simple as filling in the 'Sound0' and / or 'Sound1' fields. If you wish to have a sound play at random intervals, you can instead use the 'RS0 Sound' through 'RS2 Sound' fields. Adding min and max times for each will act as a range of when the sounds should be played. (E.g. A min time of '2' and max time of '5' means the random sound will be played every two to five seconds. Ambient sounds can be toggled off and on using the 'SetSound' message. Refer to the Toggling Sounds & Models section. Also see the Sound Browser section for more information on sound names. Fire (Flames to use with sconces, etc.) ![]() Fire can be placed in a level by using the cm_fire object. The most commonly used fields are 'Thick/Height' (the first number changes the flame's horizontal size, while the second changes the height of the flames) and the 'Flames' field (determines how many flame sprites are used). The 'Length/Width' fields can be used to control the area that flame sprites are distributed within. For example, a value of '48' could be used to cover a fireplace sized square. Cm_fire objects can be parented by adding a 'Parent' key, and the flame color can be tweaked by using the three values at the bottom of the object properties. CM_Smoke (Preset smoke emitter used in limited cases) ![]() A preset smoke object that is used in some instances such as for the lava and chimney effects in Kam-Zara. In many cases, you'll probably wish to use a particle system instead. The 'Max/Min Particles' field limits the range of how many smoke particles can exist at one time. 'Size/Distortion' affects the scale of the individual particles, as well as how far from the center they should move outwards from after being spawned. 'Height/Pressure' controls the lifespan of the particles as the height, and how hard (if at all) to push the particles in the direction the cm_smoke object is facing (these values also affect the speed of the smoke). The 'Speed' field affects the overall speed of the particles. The smoke color can also be changed. Player Starts (Player starts and challenge mission spawns) ![]() Every level needs a start point for the player, and this is placed using an info_player_start object. There are also info_start_dark and info_start_light objects which are used as spawning locations for enemies in challenge levels. Level of Detail (Objects which vanish when at a set distance from the player) ![]() The func_lod object is used to make specific geometry stop being rendered at a certain distance from the player. Simply set the 'MinDistance' and 'MaxDistance' fields for the range when you wish the geometry to be visible. Splines (Curved surfaces) ![]() Splines are created by holding down shift and pressing the number keys, and can be used to create a variety of smooth curved surfaces. Below are a few tips to keep in mind when working with these:
By default, splines tessellate based on the Curved Surfaces LOD setting in the game's Graphics options (xr_splinetesslevel),
and the size of the spline. If you would like to override this with a
specific number of subdivisions (e.g. the spline should always be set
to a specific detail level), select the edges and then use the + / - numpad buttons.
![]() (Example showing a spline at different xr_splinetesslevel settings, with a default spline in the top row and one with a custom number of subdivisions set in the bottom row. Note how the tessellation changes on the default spline but always remains the same on the one that was manually set.) If you ever need to line two splines up with one another, the Edge Tool can be used. Generally you'll need to bring two (or more) of the edge points together to do this. Below are a few examples with the original shapes and edge points to be moved selected (in yellow) on the left, and the same shapes after moving the points together on the right. (Note that if splines appear to be aligned with one another in the 2D editor views, but still don't line up in-game, try changing their subdivisions from the default using the + / - on the keypad.) ![]() Server Flags / Spawn Flags
(Setting what objects appear in which game modes, e.g. Easy, Medium, and Hard) ![]() Server flags are used to set which game mode(s) an object will appear in, for example if it will be in Easy, Medium, or Hard difficulty. An example in Enclave are the checkpoints which only appear on Easy and Medium difficulties, but this can also be used to include enemies or gameplay challenges in one difficulty but not the others. Only the Main 1 and Main 2 flags have been observed in Enclave. The others may be left unused form earlier stages of development (these may have been for challenge or multiplayer game modes).The following flags can be set:
If an object doesn't have a space for server flags, you can add a new key for 'serverflags' with a value for the corresponding flags, e.g. 's2' or 's0+s2'. Another option is to use something such as an engine_script and have it only appear and trigger in certain game modes, spawning or destroying the desired objects. Light & Shadow Dark
Zones
(Zone where staffs give off light, seen in Mansion of Dreams) ![]() The darkzone is a volume that causes a players staff to glow with dynamic light when inside. This was used during the Mansion of Dreams sewer section in the game. Statics & Smoothing (Object that can help with optimization and lighting effects) ![]() Turning geometry into a static object can sometimes help with optimization if you wish to be sure something won't cut up brushwork around it, or won't cast a shadow. (Setting 'light_flags' to '0' will disable shadows being cast from the object, and '1' will enable shadows.) Another use of statics is being able to set the light shading type on an object, including 'Gourard' to help smooth lighting across a surface. (Great for barrels, etc. Note that some other objects such as paths and dynamics can have the shading type changed similarly.) (Statics can also be spawned by using the 'Waitspawn' flag. If you wish to simply make a piece of geometry or collision appear, this can be used for such situations.) Lanterns like those that cast light in Ark Amar can be recreated using statics with shadows disabled. This allows a light object to be placed inside, and helps create the detailed shadow effects seen. This is demonstrated in a couple of included examples. You'll also note that one of these uses brushes with the *LIGHTBLOCK material applied to create more interesting shadows. Additionally light_flare objects are used which produce a flare effect. Flares (Flares for light sources) ![]() Many light sources in Enclave use a flare effect, these are normally only displayed when running the game in OpenGL with XR_FLARES enabled. Flares are added using the light_flare object. A number of keys and flags are available for flares.
While flares can be parented to paths, their position doesn't update smoothly causing them to 'jerk' along. Parenting was used in a couple levels in Enclave to have flares follow along with a moving lantern. Light Preview Mode (Preview a level's lighting in Ogier) ![]() Selecting Preview lighting from Ogier's View menu will render lights and give an idea of how a level will look on compile. Choosing Preview lighting while nothing is selected will render lights for the entire level, while doing so with a selection will only render lights for those objects. (Rendering lights for only a few desired objects is much faster than rendering a preview for the entire level.) Light previews are rendered to LIGHT.XSC in the ..\Enclave\Sbz1\Worlds directory and do not affect the compiled XW file. Lighting Modes for Dynamics & Paths (Tweaking lighting on dynamic objects and engine_paths) ![]() Sometimes engine_paths and dynamics will need to have their lighting mode tweaked in order to improve their visuals in-game. The three lighting modes which can be set and 'Light minlevel' are described below.
Works
well
for objects that should match
neighboring geometry
or have more detailed lighting to begin with, but which also require
the lighting to change as they move. This is the default &
most commonly used mode and works well for objects such as breakable
bricks where some surfaces which would not normally receive light in
'Lightmap'
mode must be
visible. In order to reduce 'pop' when an
object switches between lighting modes, the 'Light minlevel'
field can
be used.
Good
for objects
that should match neighboring geometry
or have more detailed lighting, but which do not need any further
visual changes to their
lighting as they move (surfaces obscured by shadow will stay this
way!). This mode is good for objects such as common doors.
Works
for objects that do
not need to match neighboring
geometry or have detailed lighting. This mode could work well for a
crank or moving rope such
as
those in
Kam-Zara.
Can
be used to help hide an object's transition between
modes by
lessening the brightness and color difference. A tip for finding a
minlevel value is to place a small brush at the origin or attach point
of the object, texture it using the Z_WHITE
material from the DM1
surface
file, and finally make it into a static
class with the 'Gouraud'
'LightingMode'
selected. If you compile and run the map, you'll now be able to take a
screenshot of this brush and sample it for an idea of the color to use
as your minlevel. (Note that the three darkest sides of this brush will
use one color, while the three lightest another. I've found that one of
the two will be correct but it can vary.) Once you have the color, you
can then adjust the luminosity until it helps mask the transition as
much as possible.
![]() Compiler Light Settings
(XWC settings relating to lighting quality) ![]() The option to adjust the Lightmap and Lightgrid resolutions and samples are available in XWC. While default or lower settings are great for testing a level, during the final compile you will want to increase these values.
Standard compile settings for Starbreeze's levels use Lightmap Resolution 32 and Multisample 4x4. The Lightgrid Resolution is often a value between 64 and 256. ![]() (Example showing different Resolution and Multisample values. Notice how an increased Resolution results in sharper shadows (left to right), while an increased Multisample value (bottom row) results in softer smoother shadows.) Additional Path, Script, & Etc. Information Starting,
Stopping, Resetting,
Reversing, & Moving to the End Position of Paths
(Start, stop, and resume paths, and use negative impulses to reset, reverse, and move to the end position of paths) Engine_paths can be paused, re-started, reset, reversed, and moved to the path's end. Note that if a path is stopped using a Waitimpulse, these will have no effect until it has been resumed. Starting / Stopping a Path
- Starting paths is done by sending a positive impulse
value
to
them (the
impulse matches the sequence you want to begin), while an impulse of '0'
will stop them (they can then be resumed again with a positive impulse).
Sending a stop impulse to a path also allows you to start it on a
different sequence. If an engine_path has the
'NeverInterrupt'
flag set, it will only stop once it has completed its sequence (rather
than stopping immediately). The same
starting and stopping logic also applies to other objects such as engine_rotate.
While paths can be reset, reversed, or moved to their end position, this often causes issues if the path needs to be able to be re-triggered. A solution for each situation has been provided below. Resetting a Path -
Sending an impulse of '-1'
to a path resets it to the beginning position regardless of where it is
in its sequence. When resetting a path
which has timed messages that
you would like to trigger again, ensure that the path has the AutoReset
flag checked so that the timed messages are repeatable.
Unless
the path being reset reaches the end of its sequence or timed messages
(whichever is longer), any
messages that had occurred before being reset will not function the
next time the path is triggered (i.e. the timed messages will only
continue from where they left off). A solution which allows the timed
messages to be properly reset is to send the '-1' impulse to the
path, followed by an impulse for a non-existent sequence (e.g. '2'
if the second sequence is not in use),
and then another '-1'
impulse. When doing this you should not have any timed messages at time
0 on the path otherwise they will trigger when resetting it. If you do
have a message at time 0, add a slight delay such as 0.001 or similar.
Reversing a Path - An impulse of '-2' reverses a path but only if it has not yet reached the end of its sequence or timed messages (whichever is longer). Ensure that the AutoReset flag is checked otherwise the path will not stop at its beginning frame when reversing and will continue traveling along that axis. When reversing a path that has timed messages, no messages will be triggered while the path reverses. If a
path is reversed while at the beginning or end of its sequence or timed
messages, the next impulse of '1' to the path will
cause it to 'jitter',
starting and then immediately reversing and stopping again. A solution
to this is to send two '-2' impulses when
reversing the path, one after the other.
Moving to the End of a Path - An impulse of '-3' jumps the path to the end of its current sequence or timed messages (whichever is longer). When jumping to the end position of a path that has timed messages no messages will be triggered during the jump. Similar
to resetting a
path, any timed messages that had occurred before moving to the end of
the path will not function the next time the path is triggered. A
solution to this is when triggering the path to send
it an impulse for a non-existent sequence (e.g. '2'
if the second sequence is not in use),
followed by a '-1'
impulse to reset the path, and then the impulse to start the path.
Starting, Stopping, & Resetting Scripts (Start, stop, and resume scripts, and use negative impulses to reset scripts) Engine_scripts can be paused, re-started, and reset. Note that if a script is stopped using a Waitimpulse, these will have no effect until it has been resumed. Starting / Stopping a Script
-
Similar to paths, engine_script
objects can also be stopped, resumed, and reset. Starting
scripts is done by sending an impulse value
of '1'
to
them, while an impulse of '0'
will stop them (they can then be resumed again by once more sending an
impulse of '1').
Resetting a Script - Scripts can be reset using an impulse of '-1'. When resetting a script which has timed messages that you would like to trigger again, ensure that the script has the AutoReset flag checked so that the timed messages are repeatable. Unless
the script being reset reaches
the end of its timed messages, any
messages that had occurred before being reset will not function the
next time the script is triggered (i.e. the timed messages will only
continue from where they left off). A solution which allows the timed
messages to be properly reset is to send the '-1' impulse to the
script, followed by an impulse of '2', and then another '-1'
impulse. When doing this you should not have any timed messages at time
0 on the script otherwise they will trigger when resetting it. If you
do
have a message at time 0, add a slight delay such as 0.001 or similar.
Averaging Speed / Time of Paths (Average the time of a path between its keyframes) ![]() Ogier includes a feature to average the speed / time of a whole path (a very useful feature), however, access to this seems to have been left out of the GDK. To fix this, you can place the updated nodetype.txt file included with this documentation into the ...\Enclave\Sbz1\Dev directory. Alternatively, this feature can also be added manually by opening the existing nodetype.txt file located in ...\Enclave\Sbz1\Dev. Find the line "DESC" "Scale time". Add the following below the closing curly bracket ( } ): {
"CLASSNAME" "AVERAGESPEED" "TYPE" "Button" "DESC" "Average speed" } Either of these methods will add a button to average the speed of a path in Ogier, allowing the feature to be used. Minimum First Keyframe Time (Minimum length of the first keyframe of a path) Note that the first keyframe of an engine_path must be greater than 0.001. If 0.001 or less is used as the first keyframe time, the path will skip to the next keyframe. Wait Impulses (Pausing a path or script and waiting for a specific impulse) Wait impulses pause an engine_path or engine_script until the specified impulse is received. While paused, all others impulses are ignored (so, for example, a path or script cannot be reset or have its sequence changed while paused with a Waitimpulse). Wait impulses can only be applied to the same object which is sending the Waitimpulse message (i.e. '$this'). The Waitimpulse message is commonly used to create counters (see the Counters section for more information) and can also stop a path or script until a certain sequence of impulses are received (such as with the door puzzle in Deserted Temple). Message
Pipes
(Triggering targets sequentially or randomly) ![]() Messagepipes can forward messages sequentially, or at random to a list of targets within their Target field. These are entered separated by commas, such as: 'target1, target2, target3'. Selecting Sequential will alternate through this list one at a time each time the messagepipe is triggered (note that the first target in the list is not necessarily the first that will be triggered!), while Random will select one target at random each time the messagepipe is triggered. A Setstate message can be added to an object to prevent a pipe from triggering it (instead causing the pipe to skip to the next item in its sequence or select a new random choice). To do this, add a message to the object with the triggering pipe's Name in the Target field and set the State to 'Blocked' to stop the object from being triggered, or to 'Open' to re-enable it. This can be useful to either temporarily or permanently stop the object from being triggered by the pipe. In both cases the pipe will skip over the object and move on to the next one while the state is 'Blocked' and resume triggering the object when the state is set back to 'Open'. Note that if all targets of a pipe have their state set to 'Blocked' and no target has a queued 'Open' message, the last object that was triggered will continue to activate (i.e. a pipe will always trigger at least one target). An example of Setstate messages in use is in Highvalley where messagepipes are used to randomly select where enemies will appear next, and then Setstate messages temporarily disable that selection from being chosen again in order to prevent the same spawns being triggered back to back. Message Branches (Send different messages depending on the received impulse) ![]() Message branches act similar to switch statements in programming, or as relays. They trigger different message outputs depending on the impulse received (e.g. if an impulse of '1' is received, trigger the message given in the OnImpulse 1 field). Note that sending an impulse of '0' to a messagebranch does not trigger it, so use an impulse of 1 upwards. Objanim Objects ![]() (A object that cycles through a list of actions) The objanim object can be used to cycle through a simple list of scripting actions. The actions begin when the level is loaded and can be made to repeat by using the action reset. Additional actions (e.g. Action5, Action6) can be added using the New Key button. Actions are entered in the form of a text string and may include:
The same functionality and more can be achieved by using an engine_script or engine_path. It's likely that the objanim object is deprecated and it is recommended to use those instead. File Editing File Editing
Introduction
The below sections refer to modifying the game files directly, but for some (such as the String Table and TplPrefab files) you can create your own additional files and then have the game import those on start. When creating these separately, you will want to add them to the Sv.xrg and / or P3.xrg files under their respective headings. Examples of these separate files have been included. A custom String Table would be added to the *STRINGTABLES line in P3.xrg: *STRINGTABLES
"Registry\\StringTable_Sandbox.txt;Registry\\StringTable_Eng.txt"
(Note
that custom tables
must go before the main game
String Table to
load properly. Different StringTables should be separated using a
semicolon.)
A custom TplPrefab file would be added to the *templates section in Sv.xrg: *templates {
*include Templates.xrg *include TplCharacters.xrg *include TplProjectiles.xrg *include TplExplosions.xrg *include TplHitEffects.xrg *include TplAttach.xrg *include TplMagic.xrg // *include TplDamageEffects.xrg *include TplEffects.xrg *include Tpl_AICharacters.xrg *include TplPrefabs.xrg *include TplPrefabsSandbox.xrg //This custom prefab tpl has been added *include TplChallenge.xrg *include TplVatar.xrg } Also note that comments can generally be added to files by prefixing the text with '//', while blocks can be commented using '/*' and '*/'. Dialogs & Subtitles (Add text or subtitles to the screen) ![]() Dialog files have a few main uses in Enclave; adding spoken lines to characters, subtitles, or text messages such as for a locked door. These are contained inside xrg files and can be found within the ..\Enclave\Sbz1\Dialogues directory. There are two ways to display these in-game. When making a character speak, the name of the dialog file being used should be entered into the 'Dialog' field of the character's properties. For anything else, you can use a narrator object and similarly place the dialog file name into the 'Dialog' field in its properties. In either of these cases, you can then send a 'Speak' message to the character or narrator with the 'Dialog' value being the number of a specific line within the specified dialog file. Each dialog entry has an ID number which is used to reference it. At the simplest a dialog entry might only reference a sound, however they can be expanded to include the following properties: '*TEXT' - The text that will be displayed. Using '|' in the text will act as a line break. Text can also include specially named variables such as '§LTUTORIAL_JUMP'. Note that text will only display within a
certain radius of
either the character or narrator object, with the text beginning to fade at 384 units from the camera, and vanishing
entirely at 512 units (if needed this can be worked around by parenting a narrator to an engine_path).
'*SUBTITLEDURATION' - The duration (in seconds) that the text will remain on the screen for. If no duration is given, the default duration of 3 will be used. A duration of 3 is commonly used for most subtitles or game messages. '*PLACEMENT' - Changes the location of the text, '*PLACEMENT 1' will display the text in the centre of the screen, '2' will use the top centre. If no placement is specified, the default of '0' (the bottom center of the screen) will be used. During cutscenes text that is at the bottom or top of the screen will overlap with the black letterbox. '*COLOR' - The color of the text that will be displayed (in hex notation, e.g. '0xa0d0ff'). If no color value is included, the default white color will be used. '*FLAGS' - Sets if this text is a subtitle, game message, or tutorial message. '*FLAGS 2' means that the text will display even if subtitles are disabled (useful for item pickups or tutorial messages), while using '3' seems to indicate that the text is a tutorial message (there may have previously a game option to disable tutorials, this does not appear to be included in the release version). If no flags are specified, the default of '1' (subtitle) is used. Below are some examples of what one might find in dialog files. *29 f4_death
This one is dialog 29, and simply plays a sound when called. This is often used for character sounds which are not subtitled. *100
{ *TEXT "Help!" *SUBTITLEDURATION 3 *SOUND ge_halfling021 } This is dialog 100 in a different file, it prints a subtitle for three seconds while also playing a sound. This is generally used when making a character talk. Characters will automatically lip synch to any sounds specified. *1
{ *TEXT "Welcome to the Sandbox|This is the next line" *SUBTITLEDURATION 3 *PLACEMENT 1 *COLOR 0xa0d0ff *SOUND
*FLAGS 2
}This final example is of dialog 1 and prints a different colored text in the center of the screen which will always be displayed even with subtitles disabled. This style of message is used for gameplay messages, such as with locked doors or item pickups. Note, if using Cyrillic alphabet characters, the text should be converted to Windows-1251 / cp1251 encoding before being entered into files such as dialogs or the string table. Custom Targets (Custom target information shown on the bottom of the screen) ![]() Custom health bars for objects can be added and displayed using the 'SetNPCBar' message. (Refer to the Custom Targets & Cannon / Ballista Targets example above for implementing this in-game.) To add the custom text entry, you may edit the the StringTable file found in ..\Enclave\Sbz1\registry. Find the section under the '// Targets' heading and simply add an entry like below: *TARGET_L_MSB
"Text Target"
If you're looking to have a AI Character with a custom name, you'll need to edit (or more preferably add) an entry from Tpl_AICharacters.xrg instead. Both of these can be done using a separate file as mentioned under the File Editing header as well (rather than editing the base games files). Creating Prefabs (Create new prefabs to use in your levels) ![]() Prefabs are useful when creating instances (many variations of the same object, which all inherit their properties from a single source object), or when applying rotations to complex geometry which would normally require a lot of texture alignment corrections. First you'll want to create your prefab in a new map file. Next, compile the map into an XW (neither lighting nor the navgrid are necessary), and place it into ..\Enclave\Sbz1\Worlds\Prefab. Now, we need to add the prefab to Ogier's object browser. Open the TplPrefabs.xrg file in the ..\Enclave\Sbz1\registry directory and add a new entry as in the following example: *prefab_boat
{ *classname template_prefab *prefab Prefab\boatprefab.xw } This is the simplest form of a prefab. *prefab_boat defines what will appear in the object browser within Ogier (in this case the 'prefab' group will contain the object 'boat'), while *classname specifies what object this prefab should be a subcass of. The *prefab line is the path to the compiled XW file which actually contains the geometry / objects. Once added, the prefab will be available for use in Ogier under 'prefab' within the Create object window. Note that the prefab XW and modified XRG files need to be included when you distribute your level. Prefabs can also have an object defined as a main entity by adding the *mainentity key followed by an object name (e.g. '*mainentity main'). When messages are sent to the prefab they are passed on to this object. This is useful to trigger scripts within a prefab, or to add variations to a prefab based on messages it receives. Examples might be triggering an engine_path or engine_script within a prefab in order to spawn its related objects (this is how Mordessa's and Vatar's teleporters are implemented), or setting up a prefab to have different effects depending on an impulse value that it receives. Prefabs can be added using a separate XRG file as mentioned under the File Editing Introduction section as well (rather than editing the base games files). Changing Prefab Keys & Flags (Modify a prefab's keys or flags from the XRG file) Main entities in prefabs can have their keys and flags further modified in an XRG file. This is another option to create multiple versions of the same prefab that have slight differences. An object within the prefab first needs to be specified by adding *mainentity followed by the object name. After this, a key on that object can be changed using *mainentity_ followed by the key's name and new value, or any flag by using *mainentity_ followed by the flag type and name (separate multiple flags using a + sign). For examples of this in use, look into the siege prefabs which are included in the TplPrefabs.xrg file in the ..\Enclave\Sbz1\registry directory. The names of additional flag types for other game objects can be found in nodetype.txt located in the ..Enclave\Sbz1\Dev directory. Campaigns & Rewards (Define and place a mission on the map or create custom campaigns) ![]() New levels can be added to campaigns, or entirely new campaigns can be created, mainly by editing the Campaign.xrg and StringTable found in ..\Enclave\Sbz1\registry. The campaign file serves to add locations to the map, specify playable characters and rewards, add music to levels, and so on. The StringTable contains all mission related text, such as titles, story, objectives, and reward or failure text. Examples of both files are included showing the Sandbox mission added to the Light Campaign with comments marking where each section has been added (just search for '//This' within the files and you'll find each of these changes). First, let's look at the additions to Campaign.xrg: *Sandbox //This entry has been
added
{ *position 400,100 *iconsurface GUI_Ic2_Challenge } These lines have been added under the *locations heading in Campaign.xrg and set the x / y location of the location on the map, as well as the icon which identifies it. All the possible standard location icons can be found in the GUI surface file but new ones can also be added (see the Importing Custom Textures and Surfaces sections). *l_msb //This entry has been
added
{ *location Sandbox *type mission *music_atmosphere dark_03_a *music_battle dark_03_b *picmips 0,0,0,0,0,0,0,0 *character paladin+archer+druid+boarrider+engineer+wizard+9320+golem { *map Sandbox *award gold:5,item:paladin:weapon_sword_mordessa *specialaward_0 challenge:l_c1_1 } } Further down under the *challenges heading you'll find a set of entries which set the actual XW file to use for the mission as well as the music, usable characters, awards for completion, etc. In this example, *location Sandbox matches with the above defined Sandbox map location, *type mission specifies that it is a regular mission map rather than a survival challenge or cutscene, and the *character line defines which characters can be selected during the equip screen. Within the { } section below, *map specifies the WX file for the mission, *award lists the different bonuses given for completing the mission, and *specialaward unlocks bonuses if the related event has been triggered in the level (e.g. finding a map to an unlockable challenge level). For a complete list of the different settings that can be used for a level in the Campaign.xrg, see the below Campaign Challenge Settings section. *award
challenge:l_c1_2,challenge:l_msb,gold:100 //This was added to
show a mission being unlocked as a reward
Next you'll find a modification to the Forbidden Atgard level's awards showing how to unlock one mission from another. In this case, 'challenge:l_msb' has been added which corresponds to the Sandbox level's name under the *challenges heading. *l_msb //This has been added to
enable the sandbox mission from a new
campaign start
Finally is a line added to the *newgame_light section, showing how to add a new level to be already unlocked when the player begins a campaign. Next we'll look in the StringTable file to see how to add mission related text: *LOCATION_SANDBOX
"Mission Location" //This has been added
This has been added under the Locations header and corresponds to the *Sandbox map location entry in Campaign.xrg. This is the name of the selectable location on the map. *CHALLENGE_L_MSB
"Mission Title"
//This set of entries has been added
*BRIEFING_L_MSB "Text Story" *STORY_L_MSB "Text Objectives" *AWARD_GOLD_L_MSB "Text Reward" *GAME_CAMP_SANDBOX "Mission Loss" This set of lines has been added under the Challenges header and contains all other text information related to the mission. It corresponds to the l_msb entry in Campaign.xrg. *CHALLENGE is the name of the actual mission, *BRIEFING and *STORY are the story text and objectives listed on the loading screen, and *AWARD_GOLD is text which is displayed alongside any gold reward when the mission is completed. *GAME_CAMP_SANDBOX would normally be placed under the Campaign header, but it was put here to keep the entries together. This adds a line which can be set to display on mission failure. (Note that the name and location of the award and loss entries in the StringTable file don't matter as they are chosen from within the Editor.) Using '|' in any of these will act as a linebreak. Campaign Challenge Settings (Settings that can be applied to a level through Campaign.xrg) A number of settings can be used for each level specified in the *challenges section of the Campaign.xrg file. Main Settings (Settings that are applied for most levels.)
Other Optional Settings (Additional settings which may only be applied for some levels.)
Cutscene Specific Settings (Settings which may be applied for entries with a mission type of 'cutscene'.)
Cutscene Tip: When making an in-game cutscene level, the cutscene can be made to be skippable or non-skippable.
To make a skippable cutscene, use '*cutscene_spawncharacter 1' and an engine_path with a BeginCutscene message in the level. Start the engine_path using either the AutoStart flag or a trigger placed in the same location as the player's position. This format is how the cutscenes in Enclave were set up. To make an unskippable cutscene, use '*cutscene_cameratarget' and no BeginCutscene message. Also do not use '*cutscene_spawncharacter'. With this setup the cutscene will only end when the length is met. Other Optional Map Block Settings (Settings that may be used within the 'map block' of the entry.)
Challenge Map Spawns (Additional information about challenge level spawns) Challenge levels can spawn a preset list of enemy waves at info_start_dark and info_start_light objects in a level. These enemies are spawned out of sight of the player (if possible), and can be based on any defined AI types from the XRG files. Within the Campaign.xrg entry for a challenge level *type Survival should be set. Following this, *survival_enemies can be specified, with each enemy separated using + and each group of enemies separated using a comma. *survival_enemies
Ai_engineer_L1+Ai_boarrider_L1,Ai_huntress_L2+Ai_huntress_L2
In the above example, two waves will be spawned. The first will consist of Ai_engineer_L1 and Ai_boarrider_L1, while the second will be Ai_huntress_L2 and Ai_huntress_L2. The game will wait for all enemies from one wave to be defeated before spawning the next. *survival_timelimit can be added but is optional, this key may be left over from an earlier version of Enclave. For more reference on how a survival map can be set up, look at one of the official entires in Campaign.xrg. Message List Below
is a list of the
various messages that can be sent, and the map
file values representing each. These are useful for deconstructing how
elements of the official levels were scripted, see the two examples
below.
'0.5;0x31;;0;door_wd02opcl' '0.5' is the delay, meaning this is a timed message, '0x31' is the message type which represents 'Play Sound'. There is no target entry which would normally be between ';;', meaning that this message is using the default of $this as its target. In this case the '0' has no function, and 'door_wd02opcl' is the sound to be played. (This entry plays a door sound from the object 0.5 seconds after being activated.) '0x111;gob_4_ch;0' '0x111' represents an AI message with the target being 'gob_4_ch'. The '0' references the 'Release' state. (This entry releases a goblin AI character when triggered.) 0x110; - Impulse
0x111; - AIImpulse (See list Below) 0x1008; - Begin Cutscene 0x1009; - End Cutscene 0x100b; - Spawn 0x100c; - Speak 0x128; - End Round 0x12a; - Fade Screen 0x129; - Special Award 0x1; - Wait Impulse 0x31; - Play Sound 0x33; - Set Sound 0x35; - Set Model 0x1017; - PlayAnim 0x30; - Destroy 0x100d; - Immune 0x100e; - AI Control 0x100f; - Siege Control 0x1010; - Switch Character 0x1011; - Shake Camera 0x101a; - Rumble 0x1012; - Set Model Flags 0x1013; - Air Craft 0x1014; - Add Gold 0x1015; - Add Health 0x1018; - Set Fade (Range between 0 and 255) 0x1019; - Set NPC Bar 0x5000; - Set State 0x1016; - Destroy Item 0x5001; - Teleport Object AI Impulse List
Sky Listing & Atmospheres Below
is a list of all
available skies included
in
the game. Some skies may display visual glitches when paired with
certain depth fog settings (causing flickering). If you see this, try
tweaking the depth fog in your level, or by using one of the presets
included in Atmospheres.xmp. Sky_ELM8 and Sky_ELM8b are useful when
creating endless fog as they inherit the depth fog's color
(this
is used in Ark Amar).
Atmospheres.xmp which is included with this documentation contains presets from Enclaves official levels. Each levels sky, depthfog, sunlight, and NH fog values are included. (Note that the NH fog density might not match those of the official maps, you may need to tweak this.) ![]() ![]() Importing Brushes (Importing
shapes from
other applications)
![]() Convex shapes can be imported into Ogier from 3D modeling software as brushes using MAP format (note that Ogier is able to load and save files in MAP format even though it's not listed in the Open dialog). You may need to select all surfaces on the imported brushes and use the Reset button in the Texture tool to fix any stretched textures (note that tools generally support the export or conversion of UV information, but Ogier does not support the v220 MAP format meaning cases such as sheared textures will not import correctly). It may be best to merge geometry exported using some methods to get cleaner brushes once in MAP format (using Selection > Merge in Ogier, or Edit > CSG > Convex Merge in TrenchBroom). Some options include:
Surfaces, Textures, Models, Sounds, & Animations XTX files are text based files that can be used for a variety of
purposes including defining surface information or compiling textures
and models. These files can also contain multiple sections, this is done
by beginning the file using *MULTIXTX and then specifying a section for each item to compile, e.g. *SURFACES, *TEXTURES, *XMD (models). XTX files can be opened in Ogier, or a text editor such as Notepad may also be used to modify them.
There are a couple different ways of formatting an XTX file, either with the key name in quotations followed by its value, or using the key name prefixed with a * followed by its value. The value can be with or without quotations (if using quotations around a file path, use '\' as an escape character, e.g. to enter a backslash use '\\'). Flags can also be defined either by name or by a numeric value (e.g. 'Lighting' and '2' both refer to the Lighting flag). (Modifying textures and adding effects)
![]() Ogier includes a full surface (material) editor which can be used to modify the surfaces defined in XTX files. This won't be documented in detail as there's a lot to cover, but it's pretty intuitive. Here you can create new surfaces, animate them, add effects, and modify settings. Some effects (such as UV scrolling) require texture operators to be entered. Surfaces are included in levels when they are compiled, so there's no need to include the XTX files in your release. To access the Surface Editor, open a XTX file in Ogier. If the textures don't load (i.e. they show up as grey images), try creating a new map in Ogier first to load the world surfaces, then re-open the XTX file. A text editor such as Notepad can also be used to edit XTX files. When editing surfaces you'll want to have the Workspace open which will allow you to set additional properties in the Nodebar. To give a surface package an in-editor name and order (i.e. the order that the surface package will appear in Ogier's Surface browser), select the topmost level group in the Workspace and provide an 'Ogr_name' and 'Ogr_order' key. (Note that if the name is left blank the surface will use the name of the XTX file, if the order if left blank the package will be shown following any ordered ones.) You can also add an 'Xr_parse' key with a value of '0', setting this will exclude a surface package from being included in a compiled XSU file. Generally, any surfaces that will be compiled into a level or model can have a 'Xr_parse' value of '0', while surfaces that are not (such as GUI textures) would have a value of '1' (this is the default). To give a specific surface an in-editor name, select the surface in the Workspace and then fill in the 'Name' key. (The 'Name' key will be located towards the bottom of the Nodebar, not the object name found below Class.) ![]() Surface operators can be added by selecting a 'tlayer' in the Workspace, then clicking 'New Key' and adding the fields 'Operator00', 'Operator01', etc. Some operators are shown below. (Only the first four have been properly tested.) Scroll Operator (x
velocity, y velocity) - Used to
scroll a texture:
Example: 'scroll u+v, 0, 0.05' Scale Operator (x scale, y scale) - Sets how many times a texture should repeat, larger numbers mean smaller scale: Example: 'scale u+v, 1, 2' Offset Operator (x offset, y offset) - Sets an x / y offset for the texture: Example: 'offset u+v, 0, 0.6' Wave Operator (amplitude, speed, x, y, z) - Used to make pulsing surfaces like those in Vatar: Example: 'Wave x+y+z, 12, 0.18, -33, -197, 20' (Last three numbers seem to affect the flexibility of the surface. Numbers close to 0 make it ripple, while numbers further away from 0 make the movement more stiff) 'textureanim attrib, 64, -1.6' - Used with some surfaces which animate through frames such as water. 'nv20_genenv x+y+z, 1.0' - Both this and below operator are used for many water surfaces, possibly nv20 cards. 'nv20_fresnel x+y+z, 1, 0.30' - Assume this has to do with a Fresnel effect, possibly for nv20 cards. 'genreflection u+v+w' - May have something to do with cubemaps or reflective surfaces. 'GenColorViewN r+g+b' - Found only on Trail_Sword01 in effects. Animations can also be
added to layers, for example the changing alpha used to make symbols
glow in levels like Outland Wastes or Kam-Zara.
One option that isn't available in the surface editor is the flag used for bump mapping. To enable this on a texture, add 'bump' as one of the flags in the XTX file. Note that under the Direct3D8 renderer, textures using bump maps have issues with dynamic lighting (e.g. torchs and equipped staves within a darkzone). Only the sewer textures in Iellon Dungeon use this bump map flag. There are a number of flags which can be set either in the surface editor or in the XTX file. BRUSHFLAGS can be set per surface file (all surfaces will be affected), while BRUSHFLAGS, MEDIUM_FLAGS, and FLAGS can be set per surface. Each surface layer has its own FLAGS. Simplified versions of surfaces can also be included by giving them the same name as the primary surface and adding the option 'simple0' in the XTX file (e.g. "OPTIONS" "simple0"). These alternate surfaces will be shown in-game if Complex Surfaces are disabled in the Graphics options (xr_surfoptions) and are commonly used to define simplified materials (e.g. ones without reflections). Ogier's Surface Browser will display the normal version of the texture and not the simple version (the simple version will remain hidden). Simple surfaces can be previewed in Ogier using the View > Simple surfaces option while XW or Preview lighting view modes are enabled, or tested in-game with the xr_surfoptions command. In-game, surfaces that are compiled into files (e.g. levels, models, XSU packages) take precedence over any XTX files. Note that if two or more surfaces are created using the same name but follow each other directly in a surface file, only the first surface will be displayed in Ogier's Surface browser. If two or more surfaces are created using the same name but are specified in different parts of a file, or different files, the last surface loaded is the one that will display in Ogier, while the first surface loaded is the one that will be displayed in-game (with the special case being simple surfaces, see above). It is best to give all surfaces a unique name (outside of simple surfaces) to avoid issues. More information can be found under the Surface Editor section in the official documentation. (Simulating reflective surfaces)
![]() Environment maps (also called cube maps) are used to simulate reflective surfaces such as metals or water. The cl_envboxsnapshot console command will generate a set of six images from the game camera's current position which can be used as an environment map or cube map. It's recommended to do this while in noclip mode as doing so will prevent the player character from appearing in the images. An engine_path can also be used as a camera which allows for pre-set locations in a level where environment maps can be generated from (useful if generating environment maps multiple times during a level's creation). Images will be saved in TGA format under ..\Enclave\ScreenShots, each suffixed with '_0' through '_5'. The resolution the environment maps are generated at is based on your game's resolution (a higher game resolution will result in higher resolution environment maps). Note that environment / cube maps are not generated in the correct order or orientation for use with surfaces in-game. To align the images correctly the following changes need to be made:
![]() (Pictured above is an example of environment map images generated using the cl_envboxsnapshot console command, followed by the same images after orientation changes have been made so that they will display correctly in-game.) The images can then be compiled into an XTC file (ensure that the Cubemapchain flag is enabled on the first '_0' texture so that the game loads all six images) and the environment map specified as part of a surface. You might also find that there are artifacts created along the edges of the environment map textures, this is caused by items that don't remain still, such as skies or other animated surfaces. This can be fixed with some image touch up afterwards, or you can enable 'pause 1' from the console while capturing the environment box. Enclave's environment / cube maps were greatly reduced in resolution, often with each panel being between 32 x 32 (usually for water) and 128 x 128 (usually for reflective surfaces). This results in less detailed 'reflections' which in part hides the problem of them not lining up with the world geometry fully, but also lessens the need for unique environment maps and surfaces. You'll also find that many reflective surfaces in Enclave exist as both an environment mapped version as well as one which uses a generic Env material, the second version is not used from what I've found but may have originally been included for specific graphics renderers or detail settings. There will generally be a simple version with no reflection as well which is used if Complex Surfaces are disabled in the Graphics options (see more information in the Surfaces section). Environment / cube maps can be previewed in Ogier while XW or Preview lighting view modes are enabled. Texture Mapping Types (Different types of texture mapping available for brushes and splines) ![]() Different texture mapping styles are avialable for both brush and spline surfaces. When using the Texture tool a selected object's surfaces will be tinted a different color in the 3D view for each mapping type, while the currently active mapping type will be displayed in the bottom left corner of Ogier. Brushes
Brushes have two texture mapping types. The majority of brushes will use the default Box-Mapping, however Plane-Mapping is important for some special situations.
![]() (Example showing a rotated cube using Box-Mapping, followed by the same cube using Plane-Mapping. Note how Box-Mapping results in inaccurate texture projection in this situation while Plane-Mapping allows for correctly alligned textures.) Splines Splines have three texture mapping types. All are useful in different situations. Note that flipping a texture on a spline may sometimes involve unorthodox procedures, and shifting may need to be done using the Texture tool in certain instances.
![]() (Example showing Box-Mapping and ST-Mapping on the outside and interior faces of a curve. Note how with ST-Mapping the texture follows the shape of the spline and doesn't stretch as the interior face curves onto a different axis.) (Importing
image files as
textures)
![]() Textures
for Enclave come
in two parts, compiled XTC packages which contain the actual images /
textures, and XTX (or XSU) files which include information about the
textures
(such as the texture name and properties). When a level is compiled the
information from the XTX file is included in the XW file, this means
that XTX files are not required when distributing a map (unless you
want others to be able to load and use the textures in Ogier).
Similarly, when compiling models, the XTX information can be included
within the model file.
Opening an XTC in Ogier will load the relating XTX (providing the path of the XTX file is the same as when the XTC was compiled, or has been updated to the new location by changing the 'Path' key). Making changes and then saving will update the XTX file (which must then be recompiled to see the changes take effect). When working with textures it's important to remember that the Workspace and Node bar can be used. The Workspace will display individual textures in a package, and the Node bar will display additional options that can be set. Automated / Simple Method to Create an XTC The first way to create an XTC package is simply doing it through Ogier. First, place any images you plan to import into a single directory, then open Ogier and select New texturecontainer under the File menu. This will bring up a dialog where you can select the desired images. From here, you can select any of your individual textures and set a number of properties. Once done, type a name into the Destination field near the bottom, followed by '.xtc' (example: 'test.xtc'), and click the 'Compile XTC' button to the right (looks like a stack with an arrow pointing downwards). This will compile and place the resulting XTC file in ..\Enclave\Sbz1. Note that you can save your texture container as a XTX file and reopen or modify it later. Manual / Advanced Method to Create an XTC The second method is a bit more hands on, but offers more control, especially if you plan to tweak and recompile the texture package often. This involves creating your own XTX file, an example of which is included with this documentation (TextureExample.xtx). (You can also use the New texturecontainer option mentioned above and then save it as a XTX to have something basic to start with.) Below is an explanation of the example XTX: *DESTINATION
"Example.xtc"
*NAME Example These first lines specify the output destination, file name, and internal name of the XTC. By default, the compiled file will be placed in ..\Enclave\Sbz1, but a more specific directory can be pointed to instead. Example: 'Textures\\Example.xtc'. The option '*THUMBNAILS 1' can also be set is this section, this will generate a low resolution T_ version of the XTC when compiled which is specifically used as a thumbnail in Ogier (for when the Thumbs tickbox is selected). Without a thumbnail version, the first layer of a texture will be used as the thumbnail when Thumbs are enabled. This can be useful if you want custom reference thumbnails for your materials when using Ogier. *TEXTURE
{ *PATH "texture01.tga" *PICMIP 1 *FLAGS clampu } *TEXTURE { *PATH "moretextures\\texture02.tga" } From here we get into the actual textures. The first is for 'texture01.tga' in the same directory as the XTX file and has a couple options set, including a picmip value and a flag. The second entry is for 'texture02.tga' which is located in the 'moretextures' directory and has no additional settings. Values for PICMIP, PICMIPOFFSET, and MIPMAPLODBIAS can be set, as well as any additional FLAGS. These can also be set from within Ogier. At any time an XTX can be opened in Ogier, modified, and re-saved. The PICMIP option sets what picmip group a texture will be included in (0 to 15 with each representing a different group, e.g. World or Character textures). This is used by the game to allow control over texture detail for each category type (e.g. changing the sliders for World Textures and Character Textures in the game options will result in a change of quality for any textures in the associated groups). Picmip categories and quality can be previewed in Ogier using View > Set Picmips, or in-game using the 'r_picmip' console command (picmpips use a value between 0 and 10, with '0' being high detail and '10' being the lowest detail). The PICMIPOFFSET option for textures was also added in KotT. The MIPMAPLODBIAS option (also called LodBias in Ogier) is an offset for the level of detail for mipmaps. Mipmapping utilizes smaller versions of textures which are in-part rendered on objects further away from the camera. A value from 0 to 255 can be used, and although presumably this is intended to decrease the distance where mipmaps are swapped out, it hasn't been observed to result in a difference in-game. FLAGS can be any associated texture flags. A list of available options can be seen within Ogier. At this point, the texture package can be compiled in three different ways; by opening the XTX in Ogier and clicking the 'Compile XTC' button next to the Destination field, by simply dragging the XTX file into the XWC window, or by dragging the entire directory into the XWC window. Dragging the entire directory will actually generate two more files; a texture file, and a basic surface file. The texture file can be dragged into the XWC window to create the XTC. Note that if two or more textures are created using the same name, the last texture will take precedence. This can be useful as it means creating an XTC that's loaded later (i.e. with a alphabetized name that comes after the game's compiled textures) will actually act as a replacement texture package. The Surface Editor Above we touched generating or creating an XTX file using the New texturecontainer option in Ogier or creating one manually using a text editor. Ogier also includes a visual surface editor which allows XTX files to be opened and a number of options to be set before re-saving the XTX. This is a great tool and you may find it easiest to generate a basic XTX using the New texturecontainer method, then applying further options through the surface editor. See the Surfaces section for more information on the surface editor. (Importing
your own models)
![]() This section is still incomplete, but referring to the information on custom surfaces and textures above, the notes below, and having the model example files should provide the basics. Much like surfaces and textures, models are compiled using a XTX file. The difference here is that a model XTX file will often contain the surfaces, mesh, and textures all in one (this is done by defining the XTX as a *MULTIXTX). Compiling a model using an XTX in this way allows surfaces to be compiled into models much like with levels. Some useful information for custom models include:
Examples can be downloaded separately as Ogier_ModelExample.zip (this contains the model examples installed with the Knights of the Temple GDK). ![]() One issue exists with editing for Enclave using Ogier, the lack of support for Enclave's XWC sound files. Luckily, a set of fixed audio files are available to solve this. The sound fix includes a set of recompiled XWC files which can be read by the released versions of Ogier. Note that these files will crash Enclave if left in its directory. For this reason, it's recommended that you either create a copy of the Enclave directory to use with the editor, or temporarily remove the fixed XWC files before launching the game. (Bug: Sounds that are set to objects, such as fire sounds for torches or the wraith's ambient sound, play at 0,0,0 in the editor instead of their respective locations.) If using the sound fix, download Enclave_SoundBrowser_Fix.zip and place the updated XWC files into ..\Enclave\Sbz1\Waves. If not using the sound fix, there are still at least three other workarounds that can be used to locate sound names from the game to use:
Sound Prefixes & Suffixes Sounds in Enclave exist as a large collection of 'complex sound' presets, each raw sound file can have entries with different volumes, pitches, and radii. For example, while 'lock_40.ogg' might be the name of the physical sound file, 'lock_40a' is the name of the basic sound in-game, and 'lock_40c' is another version with a decreased pitch. This complex sound information is stored within the games XWC files. The Below are common prefixes and suffixes added to the raw sound name. Common prefix Changes
Suffix Changes There will often be sounds suffixed with 'a', 'b', 'c', etc. with different pitches, volumes, or radii. (E.g. 'lock_40.ogg' can be played as 'lock_40a'. 'lock_40c' is another version with a decreased pitch.) Not all sounds will follow this naming scheme, an example is the randomized bush rustling sound using ft_ rather than rn_ as a prefix. Sound Tricks With Dynamics Detailed dynamic sounds can be a bit more challenging to set up as they might consist of sounds at a number of points along their path. There are a couple tricks which can be used to make this easier.
Complex
Sounds & Waves
Sounds can be specified in two different forms, as a 'complex' sound which already has a set of attributes applied, or as a 'wave' sound where some of these attributes can be managed directly following the sound name. Note that only complex sounds seem to work in Enclave, so the option to call sounds as waves may have been added after the games release. While complex sounds are specified within a XWC, wave sounds instead simply point to an audio files name. Wave sounds must be preceded with a $, and can be followed by up to four additional values specifiying volume, pitch, and range. Below are two examples of wave sounds. Commas are used to separate values. (Default values for waves are 100, 100, 32, 512.) '$v_demon1_atks02:150,200,64,128' Volume of 150, pitch of 200, range near of 64, range far of 128. '$v_demon1_atks02:,200' Pitch of 200. (Importing
your own sounds)
![]() Sounds
are stored in XWC
files, which contain both the raw audio, and also preset 'complex'
sounds which have attributes (such
as pitch,
volume, or radius) applied.
In order to create a XWC file, you must have the audio files you
wish to include (in wav format), and a MMP file containing all written
sound
information. An example MMP file is included with this documentation (SoundExample.mmp).
Inside a MMP file will be two main sections. These are described below. The first where the actual audio files are imported: XWC_AddWave("guidark",
"WAVE\\guidark.wav");
The first quotations contain the name that will be
used to
refer to
this wave from the game or any complex sounds, while the second
quotations contain the path from the MMP to the WAV file being
imported. In this example, the WAV 'guidark.wav'
is being imported as 'guidark'.'XWC_AddWave' can be used for most sounds, however if you would like a character to lip sync to the audio then 'XWC_AddWaveStream' should be used instead. Lip sync in Enclave is based on the waveform of the sound file with higher peaks meaning that the character's mouth is opened wider. The second is where 'complex' sounds are specified: XWC_AddSFXDesc("guidarksound",
"guidark", 0, 100, 0.0, 1.0, 0.0, 1024, 64);
Now that a WAV has been set to be imported, a 'complex' sound can be specified which uses it. The first quotations contain the name the complex sound can be called by in-game. The second quotations contain the name of any waves this 'complex' sound references. Following this is a string of values separated by commas, each which affects the playback of this sound (explained below). In this example, a 'complex' sound called 'guidarksound' is created and will play the wave 'guidark'. Another example of a 'complex' sound, this time one which plays a random wave: XWC_AddSFXDesc("gui_random",
"guidark;guilight", 0, 80, 0.0, 0.8, 0.0, 512, 32);
Sounds can also reference a number of waves separated by semicolons to play by random selection. In this example, the 'complex' sound called 'gui_random' will play either 'guidark' or 'guilight' with a 50% chance. A blank wav named 'SILENCE' can be used if you wish to have a random sound with a chance not to play at all, such as was done with a number of AI characters in the game. The following are the values that can follow a 'complex' sound: 'Prior'
- Currently uncertain what
this affects. Maximum value is 255.
'Pitch' - The pitch of a sound. 'RndAmp(Pitch)' - Applies a random pitch modifier to the sound. Total between Pitch and RndAmp(Pitch) should not exceed a value of 790. 'Volume' - The volume of a sound. Value between 0.0 and 1.0. 'RndAmp(Volume)' - Applies a random volume modifier to the sound. Total between Volume and RndAmp(Volume) should add up to a maximum value of 1.0. 'Max/Min Distance' - The maximum distance of which the sound can be heard, and the minimum distance where sound falloff should begin. (Value in units.) Finally, near the bottom of the file is the line 'XWC_End("Waves_example.xwc");'. This denotes what the compiled file should be saved as. It will be created in the same directory as the MMP by default. To compile a MMP into a XWC file, just drag it to the XWC window. Custom XWC files should be placed into ..Enclave\sbz1\Waves. Note that due to a compatibility issue, audio files compiled using Enclave's version of XWC will not load in the editor if more than one 'complex' sound is present. (However, the sounds still work fine in-game.) If custom sounds are needed to work in-editor, it is recommended that a second version is compiled using the Knights of the Temple version of XWC as well. (These files will work with the editor, but not Enclave.) (Preview
and select
animations)
![]() Ogier 102 contains a working model and animation browser for Enclave. To open it, simply press the folder icon next to any animation property field. ![]() Animations can be specified as 'path\ + animation file name: + animation number', or in the above example, as 'Gameplay\elm_5:11'. The value following the animation number in the browser is the animations length in seconds (in this case 2.22 seconds). This is helpful for setting up timing in scripted sequences.
Exporting Custom Animations
(Exporting custom animations) ![]() The Ogier editor contains an animation tool which can be used for importing, modifying, saving, and exporting custom animations. To access this tool go to File > New animation. To be used in-game, animations must first be exported to a XSA file. This can be done using File > Export animation or File > Export animation uncompressed. Animations which have been saved in an uncompressed format can also be compressed by dragging the XSA file to the XWC window (the file will be compressed in place, i.e. no copy will be made). Note that animations which ship with Enclave utilize an earlier format of CompressedAnimationSet, while the publicly released versions of Ogier export to the CompressedAnimationSet2 and newer uncompressed formats used in Knights of the Temple and Riddick games. Due to this there is currently no known way to export an animation for use with Enclave. It is recommended to examine the contents of the ..\Enclave\Sbz1\Anim directory for further reference of how animations are prepared. Importing Custom Fonts (Importing your own fonts) ![]() Fonts are stored as XFC files in the ..\Enclave\Sbz1\Fonts folder and are compiled using XWC. To compile a XFC the following are required:
An example set of files are included with this documentation (Gothic.ttf, FontExample.cfg, & FontExample.mpp). Knights of
the Temple
Editing Introduction
Knights of the Temple was released by Starbreeze in 2004 using a variation of the engine employed for Enclave. As these two games were developed so closely together, much of the information in this document can also be applied to KotT, although a number of objects and messages have been added or removed (including some very handy new features). Some issues have come up when editing for KotT on certain systems, the following are workarounds for common problems. An error resulting in a broken 3D
view is
received when simulating the world within the editor:
This can be solved by unchecking Show animation within Ogier's View menu, or by renaming the Anim folder in ..\Knights Of The Temple\Sbz1. (The error seems to be related to the editor loading certain animations.) Some models have invisible surfaces (or are completely invisible!) in Ogier: This issue seems to be related to an alpha surface rendering problem. To temporarily fix this, open the models .xmd in Ogier (found in \Knights Of The Temple\Sbz1\Models), select the model in the Workspace, and delete the 'Readonly' key. Close the model without saving changes. As long as Ogier is open, the model will now display in the 3D view (minus alpha). Not all objects show in the 'Create object' window: Some objects will not show in the object browser when using the Insert key (most notably, engine_paths and engine_scripts). This appears to be due to the objects being classed as 'solid' rather than 'entity' in the games nodetype file. These objects still show up in the browser when a brush is selected to be made into an object, and can also be placed on their own by entering their name into the 'Classname' field, and then clicking 'Create'. (I plan to include a corrected nodetype file with this documentation in the future.) The error 'Unknown version of engine-path data' comes up when opening the sample levels in Ogier: These files can be opened using Ogier 102 instead. Alternatively, you can keep pressing 'ok' and the map will load, minus the keyframe data for objects like engine_paths and dynamics. Templar Camera System One of the biggest changes in Knights of the Temple is the introduction of a camera system where the view of each scene is pre-defined by the level designer. The intention of including this section is to provide a more comprehensive and up to date description of the different camera options available. Each camera is represented by a camerapos object in Ogier. To activate a camera, a message with a value of '1' should be sent to it. That camera will then remain active until another camera is triggered. Most commonly, trigger_ext objects are used to trigger camera changes. In cases where the triggers for two cameras overlap, the new camera will not activate until the currently active camera's trigger has been completely exited. ![]() (Pictured is an example of how triggers might be used to switch between cameras. When the player walks through a trigger, the related camera will be activated.) Often, cameras will come paired with a rail (also represented by a camerapos object in Ogier). Rails allow greater control over a cameras movement, defining the exact area or a vector where the camera will move along its own spline. Every
level must have a camera named 'StartCam',
this is the camera that is active when the level completes loading. It
is
also good practice to set up a trigger which activates the starting
camera and place it at the players start position.
For a better understanding of the how cameras are used in a level, I would recommend looking at the two example levels included with the Knights of the Temple GDK (the_watermill_a & holycity_b), and comparing the camera / trigger setups with how the camera acts when played in-game. (Note, if you receive an pathing error when opening these sample levels, try loading them using Ogier 102 instead.) Camera Types (There are three main types of cameras that can be used.) Point Camera (No mapping)
The most basic type of camera, this is a camera with no keyframes or spline. By default, point cameras are fixed in place and will keep focus on the player. If given a 'SafeRadius' value, the camera will shift out of the way when the player enters that radius. This can be useful in situations where the player may be able to get close to, or move underneath the point camera. (See the below section on camera attributes for more information about using a safe radius.) ![]() (An example of a point camera. This camera has a safe radius set, causing it to shift out of the way when the player enters the orange area.) Spline Camera (Camera Mapping) A camera that has a spline, but no rail. This type of camera will follow the spline as the player moves, always attempting to be a point on the spline closest to the player. When transitioned to, the camera will start in a position along the spline which is nearest to the player. A value can be entered into the cameras 'Rail. Distance Max' field, this will make the camera tolerant up to that distance. This is distance in units that the player can move away from the camera before it starts moving along its spline. (It will be like a string where the player pulls the camera along its spline, with the camera only moving when the string is stretched.) ![]() (An example of a camera moving along its spline to follow the player. This camera has a rail distance set, causing it to to be 'pulled' along the spline only when the player has moved a certain distance away from it. The orange area represents the camera spline.) Rail Cameras Cameras with rails offer more control over the cameras movement, and are the most used camera type in Knights of the Temple. Rails are represented in Ogier by a camerapos object, and a rail can be linked to a camera by placing the corresponding rail name into the camera's 'Rail' field. Cameras can move independently from their rail, allowing (for example) a camera to be moved one direction, while the player is moving another. Rail cameras can be broken down further into three main types. Rail Camera (Rail Mapping)
When both the camera and the rail have a spline, the cameras position along its spline is based on the players position in relation to the rail splines start and end points. With this style of rail, the camera will be mapped to the same percentage of the camera spline as the player is along the rail spline. When the player is closest to the start of the rail spline, the camera will be at the start of the camera spline. When the player is closest to the end of the rail spline, the camera will be at the end of the camera spline. (Moving perpendicular from the rail will not affect the cameras position.) ![]() ![]() (Examples of cameras moving along their spline based on the players position in relation to a rail. The orange areas represent the rail splines.) Rail Dimension (Camera Mapping With Dimension) If a rail has the 'Rail. Dimension' option checked, the camera will act similarly to a regular spline camera, but with the players movement only translating to camera movement when they're traveling in the direction defined by the rail. (Moving perpendicular to the rail will not affect the cameras position.) In these cases the rail spline defines the vector the player should be moving along (the rail only needs a short spline to define the vector, e.g. 32 units). Using a rail with dimension can be useful to prevent undesired camera movement when you have cameras with curved splines (one example of this is shown below). ![]() ![]() (In the above example, if the player moves away from the cameras spline, the camera will attempt to move to a point on the spline closest to the player and may overshoot the desired position. This issue can be corrected by using a rail with dimension, causing the camera to only take into account the players movement in the rails direction when calculating its position.) The cameras 'Rail. Distance Max' can also be set to a higher value to achieve the drag effect as with a regular spline camera. Circular Mapping & Rail Distance Mapping If a rail does not have a spline, it will act as a radius where the camera will be at the start of its spline when the player is within the 'Rail. Distance Min' distance from the rail, and at the end of the spline when the player is at the 'Rail. Distance Max' or further from the rail. (Note, the official documentation states that this relationship can be reversed by entering a negative distance, however this does not appear to be functional.) ![]() ![]() (In the above example, the camera moves along its spline when the player enters the orange radius.) In the situation that a rail does have a spline and uses the rail distance fields, the camera will act similarly to the above circular mapping example, only the 'Rail. Distance Min' and 'Rail. Distance Max' will be applied to the entire length of the rails spline. ![]() By default, these mapping types will act as a cylinder along the rail with an indefinite top and bottom. Checking the 'Rail. Heightmap' option will change this to spherical mapping, which allows it to also take into account players vertical distance above or below it. Transition Types (There are three types of transitions between cameras that can be used. Note that all of the transition types can be made 'one way'. For example, two cameras can have an interpolation transition in one direction, and a snap transition in the other.) Interpolation
Interpolation is the default and most widely used transition type between cameras. This causes the view to dynamically move between the previous camera and the next camera. If something is in the way of the interpolation, the camera will perform a snap instead. When 'InterpolateAll' is checked on a camera, any transition to or from that camera will be preformed as an interpolation (this is the default setting). If unchecked, any transition to or from the camera will be preformed as a snap. In either of these cases, the type of transition can be overrode be entering names of other cameras into the 'Interpolation' field (e.g. 'cam001, cam002'). If this camera has 'InterpolateAll' checked, this list cancels interpolations to the entered cameras and uses a snap transition instead. If this camera does not have 'InterpolateAll' checked, this list enables interpolations to the entered cameras. The time it takes for the interpolation, and the sensitivity (how quickly the camera focuses on the player during the interpolation) can be set with the 'InterpolTime' and 'InterpolSens' fields. In both cases, the transition will use the greater of the values between the previous camera and the new camera. The sensitivity can also be set manually if the destination camera has been entered into the 'Interpolation' field. This can be done by following the camera name with a semicolon and a number value. For example, 'cam001;70' will make the interpolation to cam001 have a sensitivity of 70. ![]() (An interpolation between two cameras.) Snap If an interpolation is not used, a snap will be performed. The camera will be instantly transported to the new position, and aligned toward the player. This type of transition is preferred in narrow passages where there is no room for the camera to move around. ![]() (A snap between two cameras.) Transition Spline If two cameras share a common transition spline (entered in the 'Trans. Spline' field), that spline will be used to make the transition. Having a transition spline will override the use of an interpolation or snap. (Note that transitions splines were never actually used in the games levels. I'm including this transition type as it could still be useful in custom maps.) A transition spline is represented by a camerapos object and defines the path that must be taken between two cameras. The part of the transition that is not defined by the spline is performed like an interpolation, which means that you don't need to and generally should not make the spline go all the way to the cameras unless they are fixed in place. If you expect the angle between the transition spline and the interpolation to be somewhat large, you can check the 'Trans. Smooth' option on the transition spline to smooth the way the camera enters and leaves the spline. Transition splines can also be made one way by checking the 'Trans. OneWay' option. When this option is enabled, the transition spline will only be used from the camera closest to the start of the spline, while transitions in the other direction will instead interpolate or snap. The time it takes for the transition to complete will either be equal to the 'Trans. Time' value of the transition spline (if it is not zero), otherwise it will be the total length of the spline (the time of the last keyframe) plus the time for the interpolations to and from the spline (the length of these interpolations will vary depending on the distance, but will have the same velocity as the spline at its ends). If basing the transition time off the length of the spline, note that the transition speed will match the keyframe times of the spline. For this reason, it may be best to average the time of all keyframes on the transition spline. The sensitivity (speed that the camera focuses on the player) during the interpolation will be the 'Sensitivity' value entered on the transition spline. A pair of cameras can also share multiple transition splines between them (by default, the transition spline used will be the one in the first 'Trans .Spline' field). To indicate which one of the transitions will be used, send an Impulse with a value of '0' to the desired transition spline first (this activates it), followed by an impulse with a value of '1' to the destination camera. ![]() (A transition spline being used between two cameras.) Camera / Rail Attributes (This is a list of all options that can be changed on camerapos objects which are used for cameras and rails. Unless otherwise mentioned, these values should be set on the camera.)
Knights of the Temple Sky Listing (Below is a list of all available skies included in Knights of the Temple.) ![]() |
||