===========================================================================
The Unofficial Specs for
Duke Nukem 3D
V1.1
By Vincent Nguyen Quang Do
E-Mail : 101366.1734@
Compuserve: 101366,1734
===========================================================================
What's new in this version:
- Simply the list of all the keywords and their use. I hadn't the time to
finish this part when I uploaded the first version.
===========================================================================
These specs are highly preliminary, and are far from complete. It requires
a certain programming knowledge to understand what I have written, but
fortunately, not much.
It is not a complete documentation with every aspect of the script
language. You have to examine the .CON files for yourself using what you
have learned from reading this text.
First, with the usual stuff: as stated in the .CON files, Apogee and 3D
Realms do not support experiments with these files. To be more precise,
here is the official policy :
" 3D Realms encourages you to experiment freely with the parameters
contained in this file, and to share your discoveries with the rest of the
world. However, BE ADVISED that 3D Realms does NOT offer any technical
support on how to use this file or other user-modifiable features of this
game. Do NOT call 3D Realms or Apogee Software for advice or help with
this subject. "
Next thing : I cannot be held responsible for any damage to your softwares,
hard-drive, computer and anything related to you modifying the .CON files.
The bottom line is : MAKE BACKUP COPIES FIRST. Although I don't think it
can be damaging to your hard drive to modify these files, who knows ?
At last, you can distribute this file around you, unless someone from 3D
Realms or Apogee tells you you can't anymore (they didn't tell me I was
violating some kind of copyrights, so I assume I can write this specs).
Finally, I am french, so please forgive me for any bad written english.
No let's start with the fun part.
===========================================================================
PART I : The Basics
As many of you probably noticed, when you start Duke Nukem 3D, the game
starts a compiler that takes as paramater the GAME.CON file in the game
directory.
The very beginning of this GAME.CON file is the following :
include defs.con
include user.con
These files are processed first. The defs.con contains all the " define "
for the game. The user.con contains all the parameters that can be changed
in the game (damage for each weapon, hitpoints for each monster and so
on...).
So, we're going to start with the DEFS.CON file. This file is simply a
bunch of define. Five types of objects are defined in this manner : the
sprites (more on this later), the basic actions, the weapons, the different
player actions, the inventory action and the sound effects.
Ex :
define FIRSTGUNSPRITE 21
define CHAINGUNSPRITE 22
define RPGSPRITE 23
define FLAMETHROWERSPRITE 24 <= The sprite for the flamethrower
.
.
.
define face_player 1 <= The basic actions used in the AI code
define geth 2
define getv 4
.
.
.
define KNEE_WEAPON 0 <= Weapon definition
define PISTOL_WEAPON 1
define SHOTGUN_WEAPON 2
define CHAINGUN_WEAPON 3
define RPG_WEAPON 4
define HANDBOMB_WEAPON 5
define SHRINKER_WEAPON 6
define FLAMETHROWER_WEAPON 7
define TRIPBOMB_WEAPON 8
define pstanding 1 <= Stands for Player Standing
define pwalking 2
define prunning 4
define pducking 8
define pfalling 16
.
.
.
define GET_STEROIDS 0 <= Inventory Actions
define GET_SHIELD 1
define GET_SCUBA 2
define GET_HOLODUKE 3
.
.
.
define KICK_HIT 0 <= Sound Effects
define PISTOL_RICOCHET 1
define PISTOL_BODYHIT 2
define PISTOL_FIRE 3
define EJECT_CLIP 4
define INSERT_CLIP 5
The USER.CON file for itself contains all the user modifiable stuff and is
not very interesting in itself (unless someone tells me he doesn't
understand anything in the file, I won't write anything more about this
one).
Now for the hard part, and what you've all been waiting for: the GAME.CON
file
This file is primarly used by DN3D for it's monsters' AI. Modifying this
file allows for VERY interesting effects, such as creating new monsters ;
modifying weapons effects, monsters' behavior and so on... Let's start with
the basic notion of the game.con file : the " actor ".
action RUBCANDENT 1 1 1 1 1
action RUBCAN
actor RUBBERCAN WEAK
ifaction RUBCANDENT { ifactioncount 16 { strength 0 action RUBCAN break
} }
else ifhitweapon
{
ifwasweapon THROWFLAME { state rats ifrnd 48 spawn BURNING debris
SCRAP3 4 /* spawn EXPLOSION2 */ killit }
else ifwasweapon RADIUSEXPLOSION { state rats ifrnd 48 spawn
BURNING debris SCRAP3 12 /* spawn EXPLOSION2 */ killit }
else action RUBCANDENT
}
enda
Every object, monster, in short anything Duke can deal with is an actor.
This actor is referenced in the map by a number. This number is related to
the bunch of define in the DEFS.CON file. For example, the basic trooper is
referenced by the LIZTROOP keyword, which in itself is defined as the
integer 1680 (see the DEFS.CON file). Not only is this number used for
identification purpose, but also for display purpose. You'll understand
more about this later.
So, let's suppose you have the actor RUBBERCAN in the map. The above
definition shows that this RUBBERCAN has 5 hitpoints (keyword WEAK). The
code within the " actor " and the " enda " keywords defines how the
RUBBERCAN is handled, in this particular case when it is hit by a weapon.
This code is always running as long as the actor is " alive ", namely it
hasn't been killed with the " killit " keyword. Now, what can we do with
this actor, and how are the sprites displayed ? If you take a look at the
code above, you can see the keyword " ifaction ". Still above, there are
two action definitions. In fact, an " action " in the .CON files is simply
a sequence of sprite. As long as the " actor " is performing an action,
these sprites are displayed in sequence. This speed as well as the
different sprites of this sequence are determined by the numbers after the
action name. I'll explain this later with a more interesting actor.
We have here the basic notions of the GAME.CON file. Every object, monster,
is an ACTOR which is performing a certain ACTION. These ACTION are related
to the sprites displayed. With the " ifaction " and the " action "
keywords, the game knows what action the actor is performing, and can
change this action. On the above example, the script performs the following:
If the RUBBERCAN is performing the RUBBERCANDENT action, then it counts how
many times (" ifactioncount ") this action has already been processed. If
this number is below 16, it does nothing and runs again.
If this number is 16, then it calls the action RUBCAN. The action
RUBBERCANDENT is associated to the sprites showing the RUBBERCAN with a
small dent. The action RUBCAN is the standard RUBBERCAN.
If the action is not RUBBERCANDENT, then the script tests if the RUBBERCAN
was hit by a weapon, and what kind of weapon. If this is an explosion or a
flamethrower, then the RUBBERCAN is destroyed. Else, the scripts performs
the RUBBERCANDENT action.
This the very first example of what can be done with the programming
language. One could for example spawn an ammo if the rubbercan is
destroyed. Or you could generate a particular sound. Or spawn rats. Or
anything else comes to mind (almost...)
Let's take a deeper look into the action keyword (you can find the
following line in the game.con file) :
action ATROOPWALKING 0 4 5 1 12
As stated before, each monster is referenced by a number. For the basic
trooper, this number is 1680, for the PIGCOP it is 2000. The keyword action
allows to define what frames are to be displayed when an actor is
performing a certain action. The first number is the RELATIVE first frame
number. Why relative ? Simply because to obtain the real sprite number, you
have to add the actor number, here 1680. The second number is the number of
frames to be displayed, the third is how many frames you actually skip
between each frame you actually display, the last is a multiplier (allowing
to cycle through the frames backward), and the last is a tempo. Hence, the
above action would display the relative frames 0,5,10 and 15 (add 1680 to
have the absolute frame). Note that this is a 3D Sprite, so if you turn
around the monster, you can see different orientation, without changing
anything in the script.
action ATROOPWALKINGBACK 15 4 5 -1 12
This action would display the frames 15,10,5,0.
The other important keywords are " move ", " ai " and " state ".
move allows to define a speed : " move TROOPWALKVELS 72 "
ai allows to associate an action with a subroutine and a basic action :
ai AITROOPSEEKENEMY ATROOPWALKING TROOPWALKVELS seekplayer
ATROOPWALKING is the action
TROOPWALKVELS is the speed
seekplayer is a basic action, directly performed by the
program, without the help of the script. It allows the actor to "move"
toward the player without having to program everything.
As for the "state" keyword, we have to examine more closely the actor :
actor LIZTROOP TROOPSTRENGTH ATROOPSTAND state troopcode enda
LIZTROOP is the actor number (1680), TROOPSTRENGTH is the hitpoints,
ATROOPSTAND is the first action performed by this actor. The keyword
"state" calls a kind of sub-routine, defined in the scripts between the
"state" and "ends" keywords.
Here is the code for this state :
state troopcode fall <= drop an actor to the floor
ifinwater ifrnd 1 spawn WATERBUBBLE
ifaction ATROOPSTAND { ifrnd 192 ai AITROOPSHOOTING else ai
AITROOPSEEKPLAYER }
If the action is ATROOPSTAND, then there is one 3 chances on 4 (192 out of
256) that the actor will perform the AI subroutine AITROOPSHOOTING.
Otherwise it performs the AI subroutine AITROOPSEEKPLAYER.
ifinwater ifrnd 4 spawn WATERBUBBLE
else ifaction ATROOPPLAYDEAD
{
ifhitweapon
{
ifwasweapon RADIUSEXPLOSION { sound SQUISHED state
troop_body_jibs state standard_jibs state delete_enemy }
break
}
else state checksquished
ifcount PLAYDEADTIME { addkills -1 soundonce PRED_ROAM cstat 257
strength 1 ai AITROOPSHOOTING }
else ifp pfacing resetcount
break
}
If the trooper is playing dead, we still have to check wether the lying
body is destroyed by an explosion or is squished. If the PLAYDEADTIME is
over, then trooper rises again (with a strength of 1) and tries to shoot
the player.
else ifaction ATROOPDEAD
{
strength 0
ifrespawn ifcount RESPAWNTIME { spawn TRANSPORTERSTAR cstat 257
strength TROOPSTRENGTH ai AITROOPSEEKENEMY }
ifhitweapon
{
ifwasweapon RADIUSEXPLOSION { sound SQUISHED state
troop_body_jibs state standard_jibs state delete_enemy }
break
}
else state checksquished
break
}
If the trooper is dead, then it"s strength is zero. The program checks if
the respawn flag is set, and if so let the trooper rise again. If the body
is hit by an explosion, then it is definitely "killed"
else ifaction ATROOPSUFFERDEAD
{
ifactioncount 2
{
ifrnd 64 { resetcount action ATROOPPLAYDEAD }
else { soundonce PRED_DYING action ATROOPDEAD }
}
}
This action is performed when the trooper is shot and is on the ground in
pain. It has 3 chances out of 4 to die, and one chance to play dead (see
above)
else ifaction ATROOPDYING { state troopdying break }
else ifaction ATROOPSUFFERING
{ state troopsufferingstate ifhitweapon state checktroophit break }
else ifaction ATROOPFLINTCH { ifactioncount 4 ai AITROOPSEEKENEMY }
else
{
ifai AITROOPSEEKPLAYER state troopseekstate
else ifai AITROOPJETPACK { state troopjetpackstate soundonce
DUKE_JETPACK_IDLE }
else ifai AITROOPSEEKENEMY state troopseekstate
else ifai AITROOPSHOOTING state troopshootstate
else ifai AITROOPFLEEING state troopfleestate
else ifai AITROOPFLEEINGBACK state troopfleestate
else ifai AITROOPDODGE state troopseekstate
else ifai AITROOPDUCKING state troopduckstate
else ifai AITROOPSHRUNK state troopshrunkstate
else ifai AITROOPHIDE { state troophidestate break }
}
ifhitweapon state checktroophit else state checksquished
ends
The rest is simple and deals with the other action the trooper can perform.
What you must remember :
An action is simply a list of frames. You can make the actor do something
based upon this action, but it doesnt act on itself. You have to
explicitely use the "ifaction" keyword.
On the other hand, an AI seems to allow a certain degree of freedom for the
actor : it does act on it's own... You can however have the actor perform
something more difficult by using the "ifai" keyword. Note that this is
purely an hypothesis.
Now, let's go back to the frames. The following action is performed when
the trooper is effectively dead.
action ATROOPDEAD 54
The relative frame number number 54 (add 1680 for absolute). What happens
if you change this number ? Well, for example, try 320. Instead of a dead
body, you have a standing pigcop. Remember the PIGCOP number (2000) ? And
2000-1680 happens to be 320... So every sprite can be accessed with this
method. In fact, remember that even if a body is lying on the ground, it
still an actor with it's own action and script. I think that the game
deletes old actor when there are too much actor in the level.
You could also replace the above with
action ATROOPDEAD 0 4 5 1 12
You would have a walking corpse !
What I can tell you is now to experiment. As you can see, it isnt a very
hard language. A few comments though : it seems there are no variables, the
"ifpdistl" keyword stands for ifplayerdistancelower, and the "ifpdistg"
stands for iplayerdistancegreater (took a while to figure that one out !)
===========================================================================
Part II : Keywords
Now that you understand the basic concepts of the script language used in
Duke Nukem, here is a list off all the keywords with their associated
effects (at least, those I understood). I hope I won't forget any. If you
find a mistake, do not hesitate to contact me ! This list is the result of
many trials and errors, and as such is prone to mistakes. I do not claim to
have the supreme knowledge. That said, let's go back to our list. When
necessary, I used the <...> and [...] symbols. What's between the first
symbols seem to required, while what's between the second symbols is optional.
action <name> ... Define an action and it's associated sprites
(see above). You can also use this one within a code
to change the actor's current action.
actor <name> <strength> [actioname] [ai ainame] [statename]
If you define more the ai and/or the state performed,
you must end your list with the keyword "enda"
addinventory <object> <quantity> Guess what ? The list of available
objects is in the defs.con file.
addphealth <no> <no> can be negative. This allows to substract health
from the player (used in the Octabrain code)
break Forces the program to exit the current function. This
allows to bypass some code if certain requirements are
met.
cactor <actor_name> Call an actor. In fact, it only calls the actor code
not the actor definition (action, ai, and so on)
This can be used for example when creating multiple
monsters with the same basic design: you create the
actors which in turn call the basic actor. To
understand this better, I suggest you take a look at
the alien trooper definition.
cstat <no> Change the actor status. I don't have all the numbers
but here is what I know:
32768 hides the sprite (not sure)
257 ressurects the actor once more
0 kills it
debris <debris_name> <number> Spawns flying debris. The kind of debris is
defined by debris_name, the number by...
endoflevel <??> This is used when you want the script to end the
level. Usually when you kill a boss. The number
following it is unknown to me however. Maybe a tempo ?
else I think this one is quite clear.
fall Apparently, this instantly drops the actor to the
floor. However, I am not quite sure about this one.
globalsound <sound_name> What's the difference with "sound" and
"soundonce" ? I don't know.
guts <guts_name> <number> Spawns flying guts. The difference with the
above is not obvious.
hitradius <range> <strength1> <strength2> <strength3> <strength4>
This generates an explosion. Damage to monsters and
other players depends of the distance between the
explosion and these actors. Damages range from
strength1 to strength4.
ifai <ai_name> Checks whether the actor's current ai is ai_name
ifaction <action_name> Same thing for the action
ifactioncount <number> When called from within an action, counts the number
of times this action has been processed and then
checks whether it is greater than the number.
If so, it performs the following code.
ifcansee Checks whether the actor can see another actor.
ifcanseetarget Apparently used for inventory items. This checks
whether the player can see the actor.
ifcanshoottarget Checks whether the actor can shoot the player. This
usually used with the "ifcansee" keyword.
ifceilingdistl <no> Stands for "If Ceiling Distance Lower Than"
ifcount <number> This one was quite hard to figure out. Apparently, it
checks whether the time is greater than the number. It
allows to check whether an actor was kept in a certain
action.
Ex:
state genericshrunkcode
ifcount 32 { ifpdistl RETRIEVEDISTANCE pstomp }
...
When a monster is shrunk, it can be squished by the
player if he steps on it. Raising the number allows
the monster to survive longer, as the player must stay
longer within RETRIEVEDDISTANCE to stomp it.
ifdead Checks whether the actor has been killed.
iffloordistl <no> Stands for "If Floor Distance Lower Than"
ifgapzl I wasn't able to figure that one out... I initially
thought it was "if gap in z coordinate is lower than"
but it doesn't fit with the main game.con file.
Any hint would be appreciated...
ifhitspace Checks whether the player hit the spacebar. Allows
to run a special code in some instances. Ex: when
there is a water fountain, Duke can drink and gain 1
health point. This is performed in the game.con file
ifhitweapon If the actor was hit by a weapon, then performs the
following code
ifinwater Checks whether the actor is underwater
ifmove <no> Checks against <no> what is the speed of the current
actor.
ifonwater Checks whether the actor is swimming at the surface
ifp Checks something on the player
ifpdistl <no> Stands for "If PLayer Distance Lower than"
ifpdistg <no> Do you guess that one ?
ifphealthl <no> Stands for "If Player Health Lower Than"
ifrespawn Checks whether the respawn flag is set.
ifrnd <number> Generates a random number and checks whether it is
lower to the following number. If so, it executes
the following action.
Ex: ifrnd 192 ai AILIZGETENEMY
If the random number is lower than 192, then the actor
changes it's ai state to AILIZGETENEMY.
ifspawnedby <actor_name> When you use the "spawn" keyword within an
actor, the spawned actor keeps in mind what
spawned it (!!!). You could use this to set
up traps for players (such as having the ammo
dropped by a trooper detonate if a player
tries to pick it up...)
ifspritepal <no> Checks whether the sprite palette is <no>
ifsquished Apparently, this checks whether the actor is squished.
However, since I don't know what squishing means in
the game...
ifwasweapon <weapon_type> I think you already guessed that one ?
Available weapon_type are:
RPG
THROWFLAME
SHRINKSPARK
RADIUSEXPLOSION
FIREEXT (??)
KNEE
FIRELASER
COOLEXPLOSION1 (Octabrain Shot)
SHOTSPARK1
Maybe some more, but they were not used in the
main script. You could also try the following:
SHOTGUN
FIRSTGUN
???
include As stuff said, includes another file
killit Erase the current actor from the game. The script for
this actor no longer runs.
move <speed> [no] Define a speed. Is mainly used with the "ai" keyword.
However, you can also use it within a state function.
no is a number that defines a special action performed
by the actor.
Ex: move TURRVEL face_player
This moves the actor at speed TURRVEL so that it faces
the player. The list of possible action is in the
defs.con file.
operate I don't know what this one is used for. It probably
allows an actor to operate a switch, a door or an
elevator. However, I've never seen a monster
performs such a thing. Maybe because when they don't
see the player, they are as dumb as a wall.
palfrom I must say I don't know how this one works...
palive Checks whether the player is alive. It must be used in
cunjunction with the "ifp" keyword. The other options
are: pstanding, pwalking, ... See in the defs.con file
pstomp This one is funny. It is used in the genericshrunk
code (see above). It shows the player stomping on
a monster. You can usually use it with very small
monsters, although it can be also done on big ones,
if you can manage to climb on one (g).
resetactioncount Reset to Zero the number of times this action has been
processed.
resetcount Reset to Zero the time check used by "ifcount"
shadeto <no> This in fact dim or brighten the actor, depending on
the value of <no>. -127 renders (temporarly) the actor
black, while 127 renders it white. However, I must
confess I didn't very good results. It seems there is
a palette involved, and I couldn't determine the
relationship. The best example is in the Octabrain
code (JELLYFISH in the script).
shoot <weapon_type> The actor shoots with a weapon. Weapon types include
the following: FIRELASER
RPG
FLAMETHROWER
MORTER
CHAINGUN
SHOTGUN
There might be some others...
sizeto <nx> <ny> This one is fun. It shrinks the actor at nx/256 and
ny/256 it's original size. So, if you take 512, you
would double the size of the actor. However, there
are a few things to keep in mind when using this.
First, the shrinking is not instantaneous. It takes a
while until the corresponding code is performed. If
you want to shrink an actor, you must always use the
"ifaction" keyword in order to wait before it does
anything else. Try it and you'll understand. Second,
it seems you must periodically resize the actor. If
you use this keyword just once, then it will revert
back to it's original size a while after.
sound <sound_name> Generates a sound. The list of available is in the
defs.con file (I think)
soundonce <sound_name> Also generates a sound, but only once (?)
spawn <actor> Spawns an actor. Note that not every sprite is
spawnable. It must somehow have been defined as
spawnable... So you can only spawn existing actor
and cannot define new ones (using a number above 4000
for example, as might be hinted by looking at the
defs.con file)
spritepal <no> Change the palette sprite to the palette no. Usually,
an actor is always referenced by a number. But there
is also a palette that can be used for multiple monster
definition. For example, the trooper captain (with the
teleporter) is a standard trooper with a different
palette. You can test what palette the current actor
has with the "ifspritepal" keyword.
state ... ends Can be used in two manner:
Defining the function and it's code
Calling the function. It must have been defined before
You don't have to use the "ends" keyword when calling
a state.
strength <number> Defines the actor's strength. Note that you must
also change the status of the actor using the "cstat"
keyword if you want to ressurect a monster (see below)
quote <no> This displays the quote number <no>.See in the defs.con
file for more information.
Well, I think that's all. I hope I didn't forget anything. If so, please
forgive me and give me a call so I can correct my mistake. Any information
on any of the missing features would be greatly appreciated.
===========================================================================
Part III : Some Examples
Why not start with some examples ?
Well, you noticed that sometimes a trooper drops a pistol ammo. Here is the
code :
state checktroophit
ifaction ATROOPSUFFERING { stopsound LIZARD_BEG sound PRED_DYING cstat
0 strength 0 action ATROOPSUFFERDEAD break }
ifdead
{
state drop_ammo <= Here. It calls the drop_ammo state
state random_wall_jibs
addkills 1
Well, you could have it drop a TRIPBOMB, no ? Just add the line
"spawn TRIPBOMBSPRITE" and there you go, you can pick up a trip bomb.
Unfortunately, there is no sprite for it in the shareware version, so dont
be surprised if you don't see it, it's normal. Furthermore, you can use it
only as long as you don't switch to another weapon, because I didn't find a
way to reselect it.
You can try all the weapons in this manner (SHRINKERSPRITE and
FLAMETHROWERSPRITE).
You could also have it respawn another monster... such as a PIGCOP, or a
JELLYFISH (Octabrain), or... a BOSS1 (aaaaargh...).
Better still. You can replace all the basic trooper in the game with a
PIGCOP. All you have to do is define the PIGCOP ("define PIGCOP 2000" in
the DEFS.CON file) as number 1680. Of course, you still get the frames for
the trooper, but it would act like a PIGCOP, and shoot with a shotgun... If
you want to have the correct frames, you have to modify the pigcop's
actions and add 320 to each basic frame. But remember that this only deals
with the standard standing trooper. Ducking trooper and flying trooper
would remain the same. Until they hit the ground...
There are tons of things to experiment. If I have the time, I'll upload a
few of our creations (a friend and me).
What I need know is FEEDBACK as well as some information on what I didn't
quite figure out in the language. So if you think you discovered something
that would be of interest, feel free to write me a little E-mail.
If you have any question, I can be reached at the following E-Mail adress :
101366.1734@compuserve.com
Have fun !
Vincent Nguyen Quang Do