1. Information
1.1 About the authors
1.2 Legal stuff
1.3 Where to get it?
1.4 Knowledge expected of reader
1.5 Cry for help...
2. CON file overview
2.1 What are CON files?
2.2 How do CON files work?
2.3 Why are there three CON files?
2.4 The DEFS and USER CON file structure
2.5 The GAME.CON file structure
1. General information
This document was written by Joris Weimar (jweimar@casema.nl) and Sidney Linkers (slinkers@casema.nl). Because so many people asked us how to edit the CONs we decided to make a CON tutorial. One was already written by me (Joris), but it was still hard to understand. We've tried to keep this tutorial as simple as possible. If you still have a hard time understanding some of the stuff in here, please let us know what you are having trouble with. Send your comments to the above mentioned e-mail addresses.
You are not allowed to commercially exploit this tutorial in any way without written permission by the authors. We take no responsibility whatsoever for any damage cause by this tutorial.
This document can be found on our very own Duke 3D site '4th Dimension' at http//:huizen.dds.nl/~linkers. If you want to put this tutorial on your own page feel free to do so. Just as long as you leave this document and all its components together and untouched.
1.4 Knowledge expected of reader
Although this document is kept as simple as possible, we do expect you to have some knowledge:
If anybody outhere has some knowledge about CON programming language and knows a way to keep data in memory please contact us (Yes, it's amazing! The SOB-Bot code uses no memory variables in the way you would expect with a real programming language, where you can declare a variable and assign a value to it and use it in expressions).
On our Duke site we published everything we know about CON programming. If you know something about CON programming or related stuff not mentioned there or know how to fix some of the known problems of the SOB-Bot please let us know and send us E-mail.
It depends on the results of the requested information above if the SOB-Bot can stay "alive"!
2. CON file overview
To offer more than just gameplay, most games nowadays include features to edit various settings in the game. The first thing you think of is a map-editor like BUILD. This program allows you to make your own custom maps for Duke Nukem. Okay, with this program you can make maps but what about monsters, ammo and weapons? Those things can not be altered through BUILD. This is where the CONs come in. The CON files are files in which monsters, 'weapons' and items are defined. You can find them in your Duke 3D directory listing by the names of 'GAME.CON', 'USER.CON' and 'DEFS.CON'. By editing the CON files you can alter the way monsters behave, the amount of health duke starts with and other things. What we will teach you in this document, is how to alter the CON files to create your own monsters, items and other cool stuff. You will get to see that CON programming is not like any other programming language. It is very primitive and it doesn't give you much freedom. Other than those disadvantadges the CON files are very fun to edit;)
You might have noticed that when duke starts he says:
Compiling: 'GAME.CON'.
Including: 'DEFS.CON'.
Including: 'USER.CON'.
While you see these lines the game is busy compiling the CON files. That means he is converting the CON files (which are textfiles) to his own format (probably directly exectuble code). While he is doing this he also checks for errors (spelling errors and other things I will get to in a minute). In these CON files ALL the monsters and items you see are defined. Here's a simplified overview of a CON file (GAME.CON):
start of PIGCOP definition
end of PIGCOP definition
start of MEDICALKIT definition
end of MEDICALKIT definition
As you can see, every actor (monster, item) has code attached to it. Let's say we have a usermap with only a pigcop and a medical kit in it. What the game would do is execute the code for the pigcop and the medicalkit about 32 times a second. So the medical kit would check those conditions described above 32 times a second.
2.3 Why are there three CON files?
The only reason that there are three CON files is because it's easier to read that way. If you wanted, you could make one CON files out of those three. But the CON file would get very big that way, thus hard to read. What Duke 3D does is use the GAME.CON file. This file happens to have these lines in them:
include DEFS.CON
include USER.CON
When it encounters such a line in a CON file the game will read in that file too. You can not include a CON file WITHIN an included file. So you can not use the 'include' line in DEFS.CON or USER.CON since those files are already included.
2.4 The DEFS and USER CON file structure
A CON file consists of keywords. Keywords are seperated by spaces, tabs or cr's (new line character, Carriage Return). If you wanted to, you could make the CON file consist of ONE line. This would make it awfully hard to read though ;) Let's begin with the simplest keyword: 'define'. 'define' is a keyword which allows you to associate a number with a piece of text:
define NUMBEROFPLANETS 9
The textstring must begin with 'A-Z' and can be no longer than 32 characters. The string may contain (after the first character) alphabetic characters, an underscore and numeric characters. The keyword 'define' must be in lowercase or else the game won't recognize it. This keyword is very usefull since it lets you bind a number to a string. This way you don't have to remember the number, just the string. Also when a value is used very often, a define can come in handy too. Lets say you have a value that describes how fast EACH monster could walk. If you want to change this value, you have to go through every monster's code to change this value. If you use a define for this...
define MAXMONSTERSPEED 100
... and you use MAXMONSTERSPEED in every monster's code instead of the value, you only have to change the line above to effect all the code. When you look at the DEFS.CON file, you see alot of defines. This can be seen as the define CON file. Most of the defines are made in here. USER.CON also counts alot of defines. The number of ammo each weapon can carry, the maximum player health and other things are defined here. I will now introduce five keywords. These keywords are very similar to 'define' but they define different things:
Examples:
definequote 150 HELLO
THIS IS A TEST
definelevelname 0 0 E1L1.MAP 00:00 00:00 HOLLYWOOD HOLOCAUST
definevolumename 2 SHRAPNEL CITY
defineskillname 3 DAMN I'M GOOD
definesound KICK_HIT kickhit.voc 0 0 4 0 0
The last keyword (definesound) requires that the 'alias' (KICK_HIT in this example) is previously defined with the 'define' keyword:
define KICK_HIT 400
definesound KICK_HIT kickhit.voc 0 0 4 0 0
These defines don't seem to be usefull now, but they will be later on. I'll give you a little preview in how they are used:
definequote
Within an actor's code (the code that gets executed 32 times per second for every actor in the map) you can have a piece of code like this:
quote 150
When the game encouters this line (during gameplay) he will do the following:
This keyword is used, for example, in the Medical Kit actor. Once the medical kit actor gives you the medical kit he uses the quote keyword to display 'PORTABLE MEDKIT' on top of your screen.
definesound
Once a sound is correctly defined it can be played like this:
sound <alias>
So if we have a sound defined that has the name 'KICK_HIT'. You would do this to play the sound:
sound KICK_HIT
I have now explained all the keywords in USER.CON expect for two. I will get to them now:
This will assign a midi file to a certain level in a certain episode. The last thing you will need to know are these 'keywords':
'//' is used to put in comments in your code. Whenever the game encounters such a keyword it will skip the line from there and move on to the next. If you want to use multiple line comments use the /* and */:
/*
this is all comment
this is comment too
*/
This pretty much explains the DEFS and USER.CON ;) You might've seen me use the word 'filename' a few times. When the game wants to play the 'KICK_HIT' sound for example, he will see that the sound is located in 'kickhit.voc' as described above. But hey, you say, there IS no file called kickhit.voc in my duke3d directory. That's right. To keep your duke3d directory as clean as possible, Duke 3d uses group files to store their files in. Whenever the game searches for a file it will first try to locate it in the group file. If it's not there he will look in the duke 3d directory. If on the other hand the file IS in the group file but ALSO in the duk3d directory, he will use the one in the duke3d directory instead.
2.5 The GAME.CON file structure
The code you see in GAME.CON is a whole lot more complex than the code in DEFS and USER.CON. I will try to explain it as good as possible. All of the Duke3D actors are defined in this CON file. A simple 'define' is not going to be enough anymore though. Here are the 5 most important keywords in the GAME.CON file:
I'll explain all of them:
state
A state can be seen as a subroutine. You can put code in a state and if you want to execute the code just call the state. A state if very usefull if you use the same piece of code often. A state must be closed with an 'ends' keyword. I'll give you an example of a state:
state just_a_test //
define a state called 'just_a_test'
quote 150 // display a quote on screen
sound KICK_HIT // make the kicking sound
ends // end of state definition
Later on, when you have created your own actor (which code get executed every 32 times a second) you can the state by typing this:
// other code...
state just_a_test // call the state 'just_a_test' end return when
you
// are done
// the code continues here after state has been executed...
An example of an existing state is 'standard_jibs'. This state spawns (generates) various body parts. This code is needed very often (in almost every monster) so 3DREALMS made it a state (I ripped out some code to make it look easy, for now):
state standard_jibs //
beginning of standard_jibs state
guts JIBS2 1 // spawn some jibs
guts JIBS3 2 // some more
guts JIBS4 3 // more
guts JIBS5 2 // yet another jib
guts JIBS6 3 // ah, what the heck, let's throw in some more ;)
state jib_sounds // call another state called jib_sounds...
// this state plays various sounds
// once the state is executed it will continue in
// here again
ends // end of state (execution continues where this state was
called from)
Don't worry about the 'guts' keyword yet. I'll explain that later on. Now for the next keyword.
action
This is a difficult one to understand. This keyword defines an ACTION group. This action group represents an animation. Duke walking is an action, the atomic health uses an action (the atoms moving around the center). You can see an action as a group sprites bundled. Let's say we have three sprites, the first sprite is a wheel, the second sprite the same wheel but then turned 120 degrees and the third one also the same wheel but then 240 degrees turned. If you see this in an animation you would see the wheel turning. So let's define our wheel-action:
action OUR_WHEEL 50 3 1 1
20
(only the first parameter is required, the rest is optional)
We called our animation sequence OUR_WHEEL. So from now on, we can refer to this animation as OUR_WHEEL. An action is always used with an actor. That means an actor ALWAYS has a animation sequence it shows. This is what you see in the game. For example, when the PIGCOP is shooting he is using his SHOOTING animation. You can find the sprites of this animation in BUILD when you pick a texture (using the key 'V').
The second parameter is the first sprite number in the animation. This number is RELATIVE to the actors number. Every actor has a number, these numbers are defined in DEFS.CON. For example, the PIGCOP is number 2000. When you go to BUILD and check out sprite number 2000 you will see it's the PIGCOP. So the second parameter in the action keyword determines the FIRST sprite number in the animation sequence RELATIVE to the actors number. So if we were to use this action in the PIGCOP actor (we would not ofcourse, because it would like kinda weird if the PIGCOP turned into a wheel all of a sudden) the first sprite number in this action would be 2050 because 50 is our relative number and 2000 is our actor number. 2000 + 50 = 2050 ;)
The third parameter tells the game how many frames the animation has. Well, our wheel has three frames, so we fill in the number three here.
The fourth parameter is a difficult one to understand. You will need some background information to understand it. Duke 3D uses a special technique to simulate 3d-actors while displaying 2d-sprites. To simulate this, duke3d displays a different frame for each angle you can view him in. To limit the number of sprites, duke3d uses (DOOM uses the same technique) 8 angles. So every frame for a monster actually consists of 8 sprites.
The first one will be used for if you look at him frontup, the second one for if you view him in about 45 degrees, the second one in 90 degrees etc. Although DOOM uses 8 sprites Duke3D doesn't. Duke3d uses 5 sprites instead. What it does is make double use of the 2nd and 3rd sprite. It uses them as 6th and 7th sprite too since these sprites are mirror images (he turns the sprite around, in x-direction). This has one downside though, sprites are always simetrical around their x-axes. If you make your own actor this doens't have to be though. You can tell the game you want to use 8 view angles for your sprite. Hell, you can even use 16 view angles for your sprite to make it really smooth (it takes up alot of memory though). To get back to the action sprite, we entered a '1' as the number of viewangles. That means there's only one viewanlge so no matter what angle you look it at, it always looks the same.
The medicalkit for example uses a animation-action with only one viewangle. That's why you see the medicalkit facing you no matter what angle you're viewing it in. This is the value we used too. The fifth parameter indicates the stepsize. This determines which sprite should be next. If you give this a number of '1' the next sprite number will be one heigher. If you, for example, entered a 'numviewangles' of 5 it will actually increase the number by 5 since 5 sprites are used by this frame. The sixth parameter is the delay time between each sprite. How bigger this value is how longer each frame lasts.
move
Move is used to assign a speed to a name. These names will be used in keywords described later on.
move ROCKETSPEED 0 -200
(only the first parameter is required, the rest is optional) This would assign an upwards speed of 200 and a horizonal speed of 0 to a variable called ROCKETSPEED
ai
Like actions, ai's also belong to actors. AI stands for Artificial Intelligence. With this keyword you can define an AI function for an actor. You can make the actor use that AI function. Actually, all an actor does is executing ai-functions (most of them anyways). For example, the PIGCOP uses a shooting ai, seeking ai, dying ai etc.
Let's define our own AI:
ai OUR_OWN_AI OUR_WHEEL ROCKETSPEED faceplayer
(only the first parameter is required, the rest is optional) I'll go through all of the parameters. OUR_OWN_AI is the name we give it. Whenever we want to assign this ai to our actor we just have to type:
ai OUR_OWN_AI
And our actor will use it. When using this AI it will use the OUR_WHEEL animation-sequence and it will move with the speed defined as ROCKETSPEED. Now for the actual movement. How will the actor behave? The last parameter is the movement type. Here are some of the types:
There are a few more but these are the most important ones. You can use multiple movement types at once by listing them.
ai OUR_OWN_AI OUR_WHEEL
ROCKETSPEED
geth
getv
// keep moving in the direction (vertical and horizontal) you are
pointed at
All these movement types do to an actor, is POINT them into a certain direction. The fact that they have a 'velocity' (determined by the third parameter) will cause them to actually MOVE. Okay, now we will discuss the MOST important keyword there is!
actor
Everything in the game that DOES something (elevators, switches and other things controlable in BUILD exluded) is an actor. A monster is an actor, as is an item like the RPG (the ammo sprite), health boxes and other stuff. Let's define our own: (only the first parameter is required, the rest is optional)
actor OUR_OWN_ACTOR
OUR_ACTOR_STRENGTH OUR_WHEEL OUR_OWN_AI
// the actor code comes in here
enda
We've just created our own actor (well, sort of;). The name of the actor is OUR_OWN_ACTOR. There's one bug though. You MUST define the OUR_OWN_ACTOR number before making it an actor so this is the correct version:
define OUR_OWN_ACTOR 3585
actor OUR_OWN_ACTOR OUR_ACTOR_STRENGTH OUR_WHEEL OUR_OWN_AI
// the actor code comes in here
enda
The actor number is now 3585. This means if we put a sprite number 3585 in a map. The code above (which currently does nothing) would be executed 32 times a second.
useractor
The useractor command works 'almost' exactly the same as the actor command with the difference that there's an extra parameter (it has a few other differences but these are very technical).
useractor enemy OUR_OWN_ACTOR OUR_ACTOR_STRENGTH OUR_WHEEL OUR_OWN_AI
The second parameter (enemy) tells the game what kind of actor it is. There are three types:
Okay, let's do something 'practicle'. Let's make a quick actor that does nothing else then putting a quote on your screen:
--- CUT ---
define OURACTOR 105
definequote 150 THIS IS A TEST
useractor notenemy OURACTOR
quote 150
enda
--- CUT ---
Put this code at the end of your GAME.CON. Then place a sprite '105' in a map (just a simple one sectored map) and run the map with duke. A few seconds after the map starts you will see our quote on your screen. The quote will stay on your screen until you quit. Usually a quote dissapears after a while but because our quote gets called over and over again (32 times a second), the quote stays on your screen. Try it out!
The reason I did not define an action and ai is because this actor does not need it. So, if he doesn't need it, you can just leave it out.
Have fun!