plasm@Posted: Thu Dec 11, 2003 5:18 am :
Tutorials in this place seems to concentrate on how to get a little thing to work. I'll try to write a topic about doom3 scripting in general. More specifically I'll try to explain some of the strange things that's going on in the /def directory. All in all, scripts in this directory are ENTITY definitions. They define behavior for entities, whether it's a gun, yourself, a monster, the world, or whatever.

Scripting in Doom3 is object orientated, so I'll assume you've got some expirience with OO programming like C++, Java, Python or whatever. If you don't understand concepts like object instantiation and inheritance you might not follow what I'm getting at.

I do not claim that anything of the following is true. I'm simply basing it on observations and educated guesses. (I'll try let you know when I'm not 100% sure what I'm talking about). Also, naturally many of the things are probably subject to change when the game finally arrives. And, I'd like to excuse in advance for bad grammar:)

.def files
I'm not entirely sure (good start!) what export clauses do, but I believe they may having something to do with converting source files (from lightwave?) to md5anim.

entitiyDef's defines an entity which can be used in maps. Entity definitions can be inherited; for example(now take a look in monsters.def) both 'zombie_default' and 'demon_pinky' inherits 'monster_default'. 'monster_zombie_morgue' inherits 'zombie_default' which in turn inherits 'monster_default'.

Entities define parameters/variables and gives them values. The parameter name is in quotes followed by its value in quotes. The line "foo" "bar" sets parameter "foo" to the value: "bar". I'll try to describe some of the more important of them.

"inherit" takes a previous entity definition and inherits it.

"editor var ***" defines the "***" variable for the entitiy, so that you can change it inside the editor. The value seems to be its description.

"spawnclass" links the entity to a predefined class inside doom.exe. Think of it as predefined behavior for the entity. For instance, all monsters link to "idMonster" so that doom.exe knows it's a monster, and treats it like a monster. You can't change what this pre-defined behavior does, only choose between the ones doom.exe provides.

"spawnobject" is like "spawnclass", but instead it links the entitiy to a scripted class (called object in .script files). That means you can change it, and provide your own custom behavior for the entitiy.

I believe every entity definition requires a "spawnclass".. but not all entities has a "spawnobject". For instance, the entity "info_player_start" links to the "spawnclass" idPlayerStart which probably causes doom.exe to setup your player so you can play. BUT: it has NO "spawnobject". However, it's perfectly legal to provide a "spawnobject" for it so that you yourself can write some custom code to be executed when you spawn. I'll show you how it's done later.

"anim_states" just ties a .state file to the enitiy.

"use_aas" can have one of two values "aas32" or "aas96". I believe the difference between 32 and 96 is the "size" of the object when dealing with fast collision detection (=walking around the map, not the physics part of the engine). For instance, an Imp monster uses 32, while the physically larger pinky and hellknight uses 96.

"state" - which state to put the entity in upon spawning. Links to a state in a .script file.

There are lots of other parameters, and they're probably tied to the "spawnclass" and/or "spawnobject". E.g. "worldspawn" doesn't need a "melee_range" defined. Look at the .def files - a lot of the parameters are self explanatory.

.state files
I'm not actually sure what they're all about, could somebody fill in? It's possible they tell something about animations and ties them to actions inside script files. They're only defined for animated objects anyway. The action{} clause might define "exits" for a given state - e.g. in monsters.state the Idle state's action clause defines Walk, but not Idle. Likewise, Walk defines Idle, but not Walk.

.script files
Here the fun begins. These files looks a bit like Java or C++, but also contradicts in many ways. They're the ones that contain actual code, and not only definitions (like state and def files)

The keyword "object" is like "class" in C++ and Java. The term 'object' is probably a little misguiding for diehard OO programmers since it's a class definition and not an instantiated object itself. Actual objects are instantiated when an entity which links to it (with "spawnobject" in a .def file) is spawned. You can probably not spawn them yourself (like instance = new Object; in Java or C++).

Objects, like entitiy definitions, can be inherited. E.g. the object "zombie" inherits the object "monster" and overloads the death method (schedule die;) so that zombies can come back to life after you kill them. Nifty, eh? Objects are defined by typing "object 'basename' {}" while inherited objects are defined by typing "object 'derivedname' : 'basename' {}".

Variables and methods are defined inside the {} brackets. There are several types:

"float" and "void" are like the C++/Java counterparts. I've not seen evidence of an "int" type - seems like "float" is prefered, even in for(;;) like statements. Useful types like "string" and "vector" are also defined.

"condition"'s are booleans of some kind. That is, they can be true or false.

You can define a void init(); for an object. It's like a constructor in C++/Java in that it's always called when an object is instantiated. I'm not sure whether there's a deconstructor or not. When a monster die, it just.. "sleeps"...

"state"'s and "schedules"'s are a little special, in that you can define many of them, but it seems only one of them can be active at a time. Otherwise than that, they're like methods; they have code assigned to them which seems to be executed when the corresponding state or schedule is active. You can change these states with setState(state 'name'); or setSchedule(schedule 'name);. States seems to be "above" schedules. For instance, state_Combat defines all round combat behavior, while the schedule combat_melee causes the entity to perform its melee attack. States seems to concentrate on events that might change the situation, while schedules seems to carry out actions.

Bits and pieces
(observations and alike)

Imho, the AI is a bit boring - all the monsters are based on the same code. Only monster parameters differ (like health, melee damage, abilities, etc.). In .script files they can perform "advanced" actions by invoking some predefined methods; moveToSound();, moveToEnemy();, moveToCover();, faceEnemy(); are some of them. Pretty self explanatory. They can also perform "simple" actions by calling DoAction(int action); where actions are defined in defs.script - like ST_StrafeLeft or ST_Jump.

You can extract or set external entity variables (defined in .def files) by using getIntKey(string param); getFloatKey(string param); setKey(string param, string value);. Look in monster::init() for details.

There are switch/case kind of statements, which I believe takes a "condition" and only performs the following code if it's true. They're seen mostly in state methods, but also in schedule methods. Look in "state monster::state_Idle" and "schedule monster::idle_waitfortrigger" for details. It picks one, and only one, of the "cases" and performs the code after colon. It picks "default" if none of the other conditions are true.

Related to switch/casing: I believe the conditions which are defined in UPPERCASE are somehow impulses. You CAN set them yourself, but most of them seems to come from "out of nowhere" (e.g. scripting that relies on a condition which isn't modfyied elsewhere in the script) and thus I'm guessing that doom.exe is setting them itself; they're ways for the engine to tell your script important things, like "hey monster, you can see something which you'd very much like to kill" or "hey monster, you're not really able to attack right now" etc. Furthermore, .state files seems to use some of them - perhaps for knowing when to play a certain animation.

Following happens when you start a map. (Forgive me, but I havn't bothered to look up the sequence in which they happen.):
-doom_main() in main.script is called.
-the /progs/ script which you can define in a map is called.
-entities in the map are spawned, and objects are instantiated if a "spawnobject" is defined for the entity.

I believe doom_main() is meant to do something very radical. Something you want done no matter what kind of map the user is loading. However, being an OO advocate, I think it's more clean to tie an object to the "worldspawn" entity, and place the code in the constructor, rather than doom_main()..

The map script is of course meant to script map specific stuff - like the machinery in rich is bored's wonderful tutorials :)

Scripts in the /def directory is where you need to start changing stuff if you're doing a TC. Here you define behavior for each entity.

Absolutely worthless example of writing your own entity class and behavior
In misc.def, add the line "spawnobject" "worldspawn" to the worldspawn entity definition. Make a new file called misc.script (can be anything, but misc.script is a good name). Put this code in the file:
object worldspawn {
    void        init();

void worldspawn::init() {
   sys.print( "Hello World.. spawn!\n");

In main.script, add "def/misc.script" to the list of #definitions.

Now load a map. Any map. Bring down the console and scroll up. You should see the text, "Hello World.. spawn!", not far up. Very boring, huh?

But I personally think it holds some interest anyway: You provided your own custom class which upon spawning (construction) executed a piece of code. You could do this for any entity.


A lot of things can be learned from looking at the code. But I'm surprised how little there actually is in .script files. A lot can be done just by making an entity definition and setting its values. For instance, weapons aren't scripted (but you can script them if you want) - they're currently just a bunch of reload times, fire rates and alike in .def files. Only the machinegun comes close by having a GUI (for the ammo counter).

I hope some of this is helpful. I may write a followup once I gather more information.

BNA!@Posted: Thu Dec 11, 2003 6:32 am :
Nice writeup!

I'll stickify it!

plasm@Posted: Thu Dec 11, 2003 2:32 pm :
Ooh, thanks! (guess it could've been a little more structured, but it was late :)

Anyway, something I'd like to add to the above:
I've seen virtually no evidence of anything remotely related to client/server scripting. Most network enabled games have this. For instance, imagine the scripted required for a rocket launcher thingy: when you fire the rocket, every client needs to know about it, so the server announces the rocket. But on impact the rocket might spray out 100+ particles as part of some explosion effect. Since these particles has only visual value (they don't actively interfere with gameplay) you can leave it to the client, and you should do so, because letting the server send the precise positions of every particle would cause massive lag. Maybe Doom3 have some intelligent handling of this (knowing something about what affects gameplay and what dosn't), but still you'd might want to control some of it yourself, and you can't and this time.

What does this mean to you? Well, you might want to wait for the final release before coding 10000 lines for your TC, because the actual scripting implementation seems a little bit prelimary... I believe the concepts are there to stay (how to tie a spawn object to an entity, for instance), but that scripting will still look quite different in the final release.

So for your TC I guess you can design models, draw textures, create maps and sounds. Maybe even make GUI's, particle FX, materials and entitiy definitions. But write scripts to learn and explore.. maybe to sketch out some basic behavior, but don't expect any of it to work in the final game:)

BNA!@Posted: Thu Dec 11, 2003 2:48 pm :
At the time the Alpha found it's way to the net Doom³ was suppposed to be peer to peer networking instead of client / server.

No wonder you didn't find any reference.

plasm@Posted: Thu Dec 11, 2003 3:24 pm :
So Doom3 multiplaying was going to be like the pre-quakeworld era? No movement prediction and such? Seems a little backwards to me, though a few considers it to be more "true" than the current client/server model.

But it sounds like you've heard they changed that? (Personally I'm hoping for the possibility of making 32+ players team mods for the final game)

Qwertys@Posted: Thu Dec 11, 2003 9:38 pm :
sure, you _could_ make a 32 player mod. but no system under 10,000$ would be capable of handling that much computational power.
that is the reason why ID is placing the 4 player limit on multiplayer.
also, with a syncronized start, getting 32 players would be quite a challenge. the syncro'd start has something to do with the way the engine handles events. i dunno, its kinda wierd, and I doubt we'll be able to find a workaround because we'll never have that much control over the engine itself. and JC does these things for good reason.

bullet@Posted: Thu Dec 11, 2003 9:58 pm :
plasm wrote:
I've seen virtually no evidence of anything remotely related to client/server scripting.

I've been looking for that too. Mostly in reference to the weapons, since the only gun that functions in MultiPlayer (until the game is released) is the Pistol. Deathmatches are still pretty sweet, but they'd be even better with the shotgun ;)

So far, though, I haven't found any code that the pistol has that the shotgun and machinegun don't, so I think it might be a missing model or something. Maybe in Single Player it doesn't have to load some models, since you won't see them in the 1st person perspective, but when someone else tries to look at it and it doesn't exist the game crashes. Just a guess, really...

plasm@Posted: Sat Dec 13, 2003 6:35 pm :
but aren't we basing all this on an alpha? maybe some rumours?

-the alpha probably wasnt't "feature complete" so it sure wasn't optimized either. even the alpha performs well on current "standard" hardware, so lets not draw conclusions whether doom3 will be suitable for a 32 player game or not.

-lets say i make a 32 player mod called "attack of the tetrahedrons!" so that every player consists of precisely 4 triangles. even with all 32 players on the screen at once it wouldn't have much impact on the overall framerate. what i'm trying to say here, is that mod makers can choose the level of detail themselves in order to aim for a "performance standard". mod makers already do that, giving maximum "r_speeds" and such.

-seen from a networking pov, 32 players isn't really a problem in other multiplayer games, such as half-life. unless iD reverts to a peer-to-peer model (like going from quakeworld technology back to vanilla quake) 32 players in a game would not be a problem.

-in case everything fails, there's always quake iv. after all, modding it would probably not be very different than modding doom3.

iCouch_Potato@Posted: Wed Mar 03, 2004 2:37 am :
do you think modding quake IV would be the same? i mean, from the sound of things that would be friggen sweet :D

BNA!@Posted: Wed Mar 03, 2004 8:06 am :
Mostly, yes.

Hemebond@Posted: Thu Mar 04, 2004 12:23 am :
plasm wrote:
-seen from a networking pov, 32 players isn't really a problem in other multiplayer games, such as half-life. unless iD reverts to a peer-to-peer model (like going from quakeworld technology back to vanilla quake) 32 players in a game would not be a problem.
I thought id had already made it quite clear they could only support peer-to-peer games. Have they said something about dedicated servers?

Oh, great article btw. I really, really wish I had access to the alpha right now.

Burrito@Posted: Thu Mar 04, 2004 1:02 am :
Hemebond wrote:
plasm wrote:
-seen from a networking pov, 32 players isn't really a problem in other multiplayer games, such as half-life. unless iD reverts to a peer-to-peer model (like going from quakeworld technology back to vanilla quake) 32 players in a game would not be a problem.
I thought id had already made it quite clear they could only support peer-to-peer games. Have they said something about dedicated servers?

Oh, great article btw. I really, really wish I had access to the alpha right now.

It's rumored that the peer-to-peer model was discarded in favor of a client/server mp system.

I posted something about it on D3W with source...who can find it?