Assuming you have followed the instructions in the Build Environment page, you now have a working compilation environment, a version control system, and some directories full of sourcecode.

At this point you're probably looking at it wondering where the hell to begin, and you're probably confused, intimidated, or looking for a stiff drink. Or all three.

This page is not going to make those go away, but I hope it will help to give you a better idea of what is going on. Also note that I'm going to skip a lot of detail here in the hope of making it easier for you to get started; the rest you can pick up over time.

Where to start

Perhaps the first thing to do is make sure that there is no confusion about terminology. The Dark engine is the engine that, in various incarnations, powers Thief 1, System Shock 2, and Thief 2. Levels created to be played through the Dark engine contain a list of OSM files the game should load as part of loading the level. OSM stands for "Object Script Module", and these files are DLLs that contain the implementations of one or more Scripts, and the OSM exposes a well-defined interface to the engine that allows it to load and execute individual scripts. It is important to note that:

  • Scripts are attached to objects in the game via the Scripts property. Scripts can not do anything independently from objects; a script that is not associated with an object will never be called.
  • Every time an object receives a message (either from another object, or from the engine directly), all the scripts associated with it are invoked in turn, each one being given the message so they can process it.

The only time your script is called upon to do anything is when processing messages: Scripts are message handlers, and they exist only to receive messages and act on them (or ignore them as the case may be).


Ignoring the overall structure of the OSM for now, the most important class you need to care about is the cScript class you will find in the pubscript/Script.h and pubscript/Script.cpp files in the twscript source. These files are taken from Telliamed's publicscripts package, so you'll find them there too.

cScript acts as the base class for all scripts; all scripts must be derived from this class. When a script is attached to an object, its constructor is called with the script name as the first argument, and the ID of the object the script is being attached to as the second argument. Your derived script classes should, via initialiser lists, ensure that eventually the cScript constructor is invoked with those arguments.

After that point, the most important function in cScript is ReceiveMessage(). When an object in the game receives a message, the engine goes through each script associated with the object, calling that script's ReceiveMessagE() function, passing it the message and some other values. ReceiveMessage() then needs to do something with the message - generally passing it to other functions in your script to inspect the message and determine whether it is something that needs to be acted upon or ignored.


  • gravatar The Watcher [userbureaucratsysopPHRhYmxlIGNsYXNzPSJ0d3BvcHVwIj48dHI+PHRkIGNsYXNzPSJ0d3BvcHVwLWVudHJ5dGl0bGUiPkdyb3Vwczo8L3RkPjx0ZD51c2VyPGJyIC8+YnVyZWF1Y3JhdDxiciAvPnN5c29wPGJyIC8+PC90ZD48L3RyPjwvdGFibGU+]

Looking for something?

Use the form below to search the wiki:


Still not finding what you are looking for? Contact us so we can take care of it!