===========================================================================

                         The Unofficial Specs for
                              Duke Nukem 3D

                                 V1.1

                         By Vincent Nguyen Quang Do
                         E-Mail : 101366.1734@compuserve.com
                         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 doesn’t 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 isn’t 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 don’t 
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
