0
- Главная/
- Игры/
- Duke Nukem 3D/
- Читы
Obnoxious but possible important mumbo-jumbo:
This document is perpetually under revision. Please e-mail corrections,
comments, additions, clarifications, etc... to the author! In particular,
I'd love info and WELL COMMENTED example code for AI routines and anything
else you can think of related to .CON file hacking.
All permissions are given to copy and reproduce this document provided
no profit is made from such. The author disclaims all responsibility
for the information contained herein and makes no express or implied
warranty for it's fitness for any particular use. If playing with your
.CON files makes your computer crash, it's not my fault!
-----
INDEX/TABLE OF CONTENTS:
A. What are .CON files?
B. Can I alter .CON files?
C. How do I alter .CON files?
* What is all this strange C-programming language-like junk?
***** DEFS.CON: define
***** USER.CON: definequote, definelevelname, music, definesound
***** GAME.CON: comments, include, primitives
- Listing of primitives + their uses (if known)
D. Examples
* Trampoline trash cans
* Hollow-point pistol bullets (Unfinished)
* Kamikaze enemies (Unfinished)
E. So now what?
F. Appendix
* Where can I get this document?
* Contributors/Thank You's.
-----
A. What are Duke Nukem 3D .CON files?
.CON files are text files that "CON"trol certain aspects of the DOOM-
like game Duke Nukem 3D (DN3D). There are three of them that come with
the Shareware version of DN3D: DEFS.CON, USER.CON, and GAME.CON. (The full
version of DN3D is has not been released as of the writing of this
document, and so I can't say anything about it.) When DN3D starts up,
it loads GAME.CON, checks it for errors, and if there are none keeps the
instructions contained in it for use later on in the game. (GAME.CON is
in charge of loading up any supplemental files, like DEFS.CON and USER.CON,
that it may want to use) The instructions currently known to be usable in
GAME.CON control things as mundane as how much damage each kind of weapon
does to things as exotic as how enemies behave.
B. Can I alter .CON files?
Yes, you most certanly can. This is one of the nicer features of the
Build engine, or at least Duke3D's implementation of the Build Engine.
But, before you start playing with them, you should definitly MAKE A
BACKUP OF ALL YOUR .CON FILES!!!!! This is not only to prevent you from
having to re-install DN3D if you mess up your existing .CON files, but
also so that you can have the original .CON files as reference material
when you start altering them. Once you've got backups made, altering
the .CON files couldn't be easier: just open them up with your favorite
text editor and edit away.
C. How do I alter .CON files?
* What does all this weird, C-like junk in my .CON files mean??
A lot of things, depending on which .CON file you edited. Let's take
the .CON files from least complex to most complex:
***** DEFS.CON:
Most of the lines in DEFS.CON look something like:
define SOMETHING SOMENUMBER
What they do is basically simple substitution: If you have a line
somewhere in your DEFS.CON that said:
define THEANSWER 42
Then any time after that, if the word "THEANSWER" appears, "42" is
substituted in it's place.
By themselves, these lines aren't very interesting. They become helpful
later on, when you're writing actor code and don't want to remember that
an enemy who is TOUGH happens to have a strength of 137. You can just:
define TOUGH 137
And thereafter don't have to remember that TOUGH = 137, you just know
that an enemy is TOUGH.
Defines are ubiquitous; almost everything in the .CON files is really a
number, but is DEFINEd to be a name so it makes more sense. At some point
you can just stop caring whether things are DEFINEd labels or numbers, but
be aware that most of the things you deal with are really numbers.
***** USER.CON:
USER.CON is somewhat like DEFS.CON in that it mostly just defines things.
However, USER.CON usually defines things that might be interesting to the
game player, whereas DEFS.CON usually defines things that a DN3D player
could care less about. USER.CON also contains nice technical notes written
by the 3D Realms .CON programmer, Tod Replogle, that tell you all about how
to modify it. Almost all of the info below is basically a rehash of the notes
you can find in USER.CON
There are 5 major kinds of lines in USER.CON: defines, definequotes,
definelevelnames, musics and definesounds.
"define" lines are no different than they were in DEFS.CON; they define
stuff. Most of the stuff you can define here is emminantly useful, tho.
Examples abound: You can define Duke's starting and maximum health and
armor values here. You can define how much ammo Duke gets per clip picked up,
how much ammo is allowed for each weapon, how much damage each weapon does
per hit, etc, etc...
"definequote" lines define the different things that will pop up on the
screen in response to certain game events. You can define what words
appear on the screen when you get an some ammo or an inventory item, what
words appear on the screen when you use the various cheat codes, what
words will appear when you adjust game options, etc, etc...
"definequote" lines have two arguments: a number and a quote. The number
is what you use to refer to the quote by later on. For example, the line:
definequote 101 NIGHT VISION GOGGLES!
Defines quote number 101 is "NIGHT VISION GOGGLES!" (This is pretty
obvious, isn't it?) One other thing to keep in mind while making quotes;
Todd Replogle, the Duke3D .CON file programmer, cautions:
>// Maximum quote size is 64 characters.
"definelevelname" lines are used to define the episode and level number,
floor-plan file, par and record times, and level names for each level. The
format of a definelevelname line is:
definelevelname #LEVEL #EPSIODE MAPFILE PARTIME RECORDTIME LEVELNAME
For example, Episode 1, Level 5 is "The Abyss." The floor-plan of this
level is in the file E1L5.map. (which is actually contained in DUKE3D.GRP)
The par time is 9 minutes, 10 seconds, and the record time is 5 minutes
flat. It's definelevelname entry looks like this:
definelevelname 0 4 E1L5.map 09:10 05:00 THE ABYSS
As you can see, you must subtract one from the actual episode and level
numbers before you put them on the definelevelname line. We're in Episode 1,
but the #EPISODE is 0. We're in level 5, but the #LEVEL is 4. Notice also
that you should (I don't think it's actually required) pad the par and
record times with a leading 0 if necessary. There are also some comments
from Todd Replogle, taken from USER.CON:
> - Level file names cannot excede 13 characters.
> - Level par cannot excede 5 characters (min:sec)
> - Level titles cannot excede 32 characters.
"music" lines (as far as I can tell) define which .MID files to play for
each level. Beyond that I'm not entirely sure how "music" lines specify
exactally which file to play for which level; if someone can enlighten
me I'd be appreciative.
"definesound" lines define various names that correspond to ways to
play a VOC file. The format of a definesound line is:
definesound SOUNDNAME VOCFILENAME.voc #1 #2 #3 #4 #5
Once again, Todd Replogle has provided .CON file hackers with a helpful
technical note in USER.CON:
> -----------------------------------------------------------------
> ABOUT CHANGING SOUND FX
> The sound fx section follows this explanation.
>
> 1. The program expects to find a .VOC file
> 2. You can either change the VOC name listed below to match your new
> sound, or you can rename your file to match the name here.
> 3. New sound files should be added to the game directory. Though
> all sound files shipped with the game are included inside the
> .GRP file, the program will know if there are sound files outside
> the .GRP file, and will use them instead.
> 4. The numbers that are to the right of the sound file name are
> technical parameters which will not be explained here, except as
> follows...
> - The first 2 numbers define a random pitch variation range.
> They can be positive or negative numbers.
> - The 3rd number is a priority flag.
> - The 4th number is a bit parsed set of technical variables
> that identify the type of sound it is in the game.
> - The 5th number is a volume adjustment flag.
> -----------------------------------------------------------------
The explanation seems pretty self-evident, so I won't go into a detailed
explanation of each field of the definesound line.
***** GAME.CON:
The BIGGIE! Lots of stuff in this one, and most of it rather difficult to
explain... let's start out with the first couple of lines, which are:
/*
-------------------------------------------------------------------
Duke Nukem 3D Script Code.
Todd Replogle.
-------------------------------------------------------------------
*/
If you're a C programmer, this stuff is immediatly obvious: everything
between /* and */ is considered a "comment" and Duke3D will almost always
ignore it when reading in GAME.CON. (I say "almost always" because it appears
that Duke still counts the curly braces, { and }, inside comments. This can
lead to some interesting effects; comment out some bad code that has non-
matching curly braces and the game might refuse to load up, even though the
bad code is inside a comment, and supposedly never even seen.)
There are two kinds of comments: the double-slash or "//" comment and the
"/* */" comment. A "//" comment starts at the double-slash and extends to the
end of the line. A "//" comment ends at the end of the line.
The "/* */" comment can span several lines, but "//" comments only "null
out" one line, at most. Many // and /* */ comments can be found all over
DEFS.CON, USER.CON, and GAME.CON.
Forewarned: you must put a space after "//" before typing the text of
the comment. The comment: "//This is a comment" will cause Duke3D to error
out. Changing the comment to "// This is a comment" will fix the problem.
I assume the same holds for "/* */" comments. Things like: "/*C*/" are
a no-no. Things like "/* C */" are OK.
The next few lines in GAME.CON are "include" lines which basically
cause Duke3D to process the specified file. The line:
include defs.con
Makes DN3D go process DEFS.CON before it moves along to the next line.
And now, the really big, confusing ones: states, actions, and actors.
Apogee hasn't said anything about states, actions, or actors yet, so the
things I'm about to tell you are pure conjecture based on observation and
experimentation:
*****STATEs
As far as I can tell, "states" can be thought of as something like
subroutines. You go into a state, do something, and then come back to
wherever you were. The first state in GAME.CON is the "rats" state, which
randomly makes some rats whenever it's called.
The format of a state is:
state #STATENAME
...
ends
STATENAME is a unique number that is usually DEFINEd to be the name of
the state. No two states should have the same number. "ends," of course,
is short for "End State." Be sure that your states are defined before you
try and use them. If you try and use a state (in an actor, perhaps) that
hasn't been defined earlier in the file, DN3D will error.
*****ACTIONs
As far as I can tell, an "action" specifies a sequence of sprites
(pictures) to draw onto the screen. The format of an action is still
not quite entirely known, but it seems to be something like this:
action #SPRITEGROUP #FIRSTFRAME #LASTFRAME #?? #?? #DELAY
Each action has a set of pictures, or "frames" associated with it.
The number first number, #SPRITEGROUP, defines this bunch of picures, or
a "sprite group." #SPRITEGROUP is usually a DEFINEd number, so you can
type "action BURNING_FRAMES" instead of having to remember that the fire
animation frames are number 327, and typing "action 327." The second and
third numbers of an action specify which sequence of frames from the
specified sprite group group to step through when you're animating this
sprite. (Animation starts from the whatever-th frame in the sprite group,
number #FIRST, and goes until the whatever-th frame in the group, number
#LAST. Then it usually loops back to the first frame or else quits,
depending on the actor code controlling it.)
The #DELAY number determines the delay between frame changes. That is,
how rapidly the frames are animated on-screen. 1 = small delay and fast
animation, bigger numbers = bigger delays and slower animation. (I think?)
The two remaining numbers are a mystery. If anybody knows what they mean
and how they're used, please mail me at cantrick@rintintin.colorado.edu so
I can add them to the guide.
*****ACTORs
As far as I can tell, an "actor" is any (freestanding?) object in the
game that does something. Obviously, Duke and the enemies are actors.
However, the rubber-maid trash cans in the movie-theater lobby are also
actors, because they dent and then bounce back when you shoot them. The
items and weapons and clips are also actors, because they also do something
when you run over them: they give you an item, a weapon, or more ammo.
Walls are not actors, because they don't 'do' anything except sit there.
(Bullet-holes being an exception, I guess. Perhaps the bullets themseves are
some kind of actor that effect the surface they hit.) Doors and lifts are
borderline; I suppose the game might treat them as actors internally, but I
don't know if you can/how you would alter their behavior in the .CON file.
The format of an actor is something like:
actor #ACTORNUMBER #ACTORSTRENGTH #ACTION #SPEED #AI_FUNCTION
...
enda
#ACTORNUMBER is (I think?) a unique number that identifies this actor.
No two actors should have the same number. Usually #ACTORNUMBER is
DEFINEd to be something easier to remember than a number.
#ACTORSTRENGTH is a number that determines how much damage this actor
can take before it breaks, dies, etc... (I think?) Putting a value of 0
for this field makes the object invincible. Usually, #ACTORSTRENGTH is
DEFINEd to be something easy to remember. (See 'define TOUGH' above.)
#ACTION is (I think?) the number of an action (that is, the identifying
number of a series of frames) to cycle through for this actor, if this
actor is animated. Patches of fire actors use this to maintian an image-
loop so they look like they're constantly burning. The HoloDuke recharge
also uses an action to make the shimmer propagate across it's surface.
#SPEED is (I think?) how fast this actor moves, if it moves. I don't know
if "move" is always interpreted in the traditional sense; it appears from
the gun-turret actor code that turrets that spin in place are considered to
be "moving."
#AI_FUNCTION is (I think?) a number, as defined in DEFS.CON, that
specifies what this actor's initial AI is if it has an initial AI. The AI
routines are: face_player (1), geth (2), getv (4), random_angle (8),
face_player_smart (64), fleeenemy (128), seekplayer (512), fleeplayer (1024),
looking (2048) and dodgebullet (4096). As to what these mean or how they
work, I haven't any idea.
The last three parameters of actor seem to be optional. Things that aren't
animated, don't "move" and have no AI don't seem to include those parameters.
You can make a perfectly sensible actor without them; as a matter of fact
the majority of non-enemy actors in Duke3D (ammo and items) do not use them
at all.
* You keep putting "..." inside states and actors as if we already know
what's supposed to go inside there; but we don't!
Well, this is kind of sticky; there are quite a few things inside there,
most of them vaguely reminiscent of the C programming language with a
virtual environment twist. The things that go inside actors and actually
make up the actor "code" are what I'll call "primitives." Primitives are
simple operations that the Build Engine will perform for you. For instance,
one primitive is "ifrnd" which will tell you if a random number between
0 and 256 was less than the number you gave it. For instance, if you
wanted there to be a 1 in 2 chance of something happening, you could put:
ifrnd 128 {
... // 50% chance that this stuff gets done.
}
Since 128 is half of 256, the random number between 0 and 256 will be
less than 128 about half the time. Thusly, the "..." inside that
"ifrnd" block will only be executed about half the times the ifrnd is
run. To take another example: if you wanted a 1/4 chance, you'd
ifrnd 64 { ... }. Since a random number between 1 and 256 will be less
than 64 about 25% of the time.
There are a bunch of other primitives, too. I'll list them each here,
along with their arguments and what they do. After that, I'll give some
(hopefully) illustrative examples on how to use them.
Note: Primitives marked with a "?" instead of a "-" are still mysteries
to me. As usual, mail me (cantrick@rintintin.colorado.edu) if you know how
they work or if I've forgotten any primitives.
Note: Most "add" primitives are subject to some kind of limit. These
limits are usually explained in the explanation of the primitive.
Note: All (?) 'ifXXXXX' primitives can have an (optional) else clause
that gets executed if the condition being tested is false. For instance:
ifphealthl 45 {
quote OK // Print "You're OK."
}
else {
quote BUMMER // Print "Find some health!"
}
*****PRIMITIVES:
addammo #WEAPON #AMT - Adds #AMT ammo to #WEAPON weapon,
Subject to max ammo constraint for
that weapon. Does not give player
#WEAPON, only gives them ammo.
Ex: "addammo PISTOL_WEAPON
PISTOLAMMOAMOUNT"
addinventory #ITEM #AMT - Adds #AMT of #ITEM to player's
inventory, subject to #ITEM's max
amount limit.
addkills #NUM - Adds #NUM to number of kills
player has made.
addphealth #NUM - Adds #NUM points to player's
health. (#NUM may be negative.)
addweapon #WEAPON #INITIALAMT - Gives player weapon #WEAPON that
has #INITIALAMT of ammo in it.
Ex: "addweapon SHOTGUN_WEAPON 10"
ai AINAME #ACTION #SPEED #AITYPE ? Defines an AI routine for enemies
to use. AINAME is any string,
#ACTION is the series of frames
to cycle through when the enemy
is using this AI, #SPEED is how fast
the enemy moves when using this AI
and #AITYPE is what the enemy does
when it's using this AI. (For list
of AITYPEs, see #AI_FUNCTION under
ACTORs.)
break - Stops whatever you're doing and
immediatly exits the currently
running actor or state.
cactor #ACTORNUM ? As far as I can tell, this
primitive "c"alls another "actor"
to do something for you.
cstat #NUM ? Allows setting of the status
flag(s) of the current actor.
For instance, "cstat 32768" makes
an actor invisible. There are other
cstat flags too, but I don't know
what they all are. (Notably 0 may
be "visible," and 4 may be "moving.")
debris #??? #AMT - Causes some debris to fly. (Whose
action or spritegroup is defined
by #??? ?). Larger values of #AMT
make more junk fly. Acceptable
values of #??? seem to be "SCRAP1"
and "SCRAP2."
Ex. "debris SCRAP2 5 // Lots!"
define - Defines various things. See other
definesound sections of document.
definelevelname
fall - Causes the current actor to "fall"
until it hits a surface it can come
to rest on. Good to do right after
you "spawn" something small from
inside something larger.
globalsound #SOUND ? Plays the sound associated with
#SOUND at (which?) Duke's location.
guts #??? #AMT - Like debris, but causes different
kinds of body parts to fly instead
of debris. Acceptable values for
#??? seem to be JIBS1 to JIBS5 (Misc
body parts) as well as HEADJIB1,
LEGJIB1, ARMJIB1 (Trooper parts),
LIZMANARM1 and LIZMANLEG1 (Captain).
Also DUKETORSO, DUKELEG, DUKEGUN.
Ex. "guts JIBS1 1 // A spine."
hitradius #RADIUS #1 #2 #3 #4 ? Defines the effective distance and
strenghts of area-effectors like
explosions and fires. #RADIUS
determines the circle of maximum
effect, (I think?) within which damage
done to objects is given by #4.(?)
Objects farther away (how much
farther?) from the center of effect
suffer damages of #3, objects farther
than that sustain damage #2, objects
farther yet take damage equal to
#1, and objects sufficiently far
away from the area-effector suffer
no damage at all.
Ex: "hitradius 1024 WEAKEST WEAK
MEDIUMSTRENGTH TOUGH"
- Note about 'ifXXXXX' primitives. All (?) if primitives can have
an (optional) else clause that gets executed if the condition is
false. For instance:
ifphealthl 45 {
quote OK // Print "You're OK."
}
else {
quote BUMMER // Print "Find some health!"
}
ifactor #NUM ? Tells you if the currently
executing code was called by
the given actor?
ifactornotstayput ?
ifaction #ACTION { ... } - Tests if the current actor is
executing the given action, and
executes the appropriate code.
ifactioncount #NUM { ... } - Tests if the current actor is
displaying the given frame of an
action, and exectes the appropriate
code.
ifbulletnear ? Checks to see if a bullet has
passed near the current actor?
ifcansee - Returns true if Duke can
see the current actor.
ifcanseetarget ? Enemy AI routine?
ifcanshoottarget ? Enemy AI routine?
ifceilingdistg #NUM - Returns true if the distance to
ifceilingdistl #NUM the ceiling is greater/less than
the given number.
ifcount ? Short for ifactioncount?
ifdead - True if the current actor has
taken as much damage as they can
given their strength and is should
be pushing up daisies.
iffloordistg #NUM - True if the distance from the
iffloordistl #NUM current actor to the floor is
greater/less than #NUM.
ifgapzl #NUM ? True if the distance between the
floor and the ceiling at the actor's
location is less than #NUM.
ifhitweapon ? True if the current actor was
hit with a weapon recently. (How
recently? Since the last call to
ifhitweapon?)
ifinwater - True if the current actor is
ifonwater in/on water.
ifmove #NUM ? True if the value of variable
#NUM is not false?
ifnotmoving ? True if the current actor is
not moving?
ifp #COND ? True if a player (the last one
that affected this actor?) satisfies
#COND, when #COND can be one of
the defined (in DEFS.CON) numbers:
pstanding, pwalking, prunning,
pducking, pfalling, pjumping,
phigher, pwalkingback, prunningback,
pkicking, pshrunk, pjetpack,
ponsteroids, ponground, palive,
pdead, pfacing.
ifpdistg #NUM ? True if a(?) player's distance
ifpdistl #NUM from the current actor is greater/
less than #NUM.
ifphealthg #NUM ? True if (which?) player's health
ifphealthl #NUM is greater/less than #NUM.
ifpinventory #ITEM #AMT ?
ifrespawn - True if monsters should respawn.
ifrnd #NUM - True if #NUM is less than a
randomly selected number between
0 and 256.
ifhitspace ? True if a(?) player hit space.
ifplayersg #NUM ? True if player has greater/less
ifplayersl #NUM thatn #NUM Dukes left.
ifspawnedby #ACTOR - True if the current actor was
SPAWNed by the given type of actor.
ifspritepal ?
ifsquished ? True if the current actor was
hit by the shrink ray and then
stepped on.
ifwasweapon #WEAPON ? True if the current actor was
recently(?) hit by a shot from
#WEAPON.
killit - Removes the current actor from
the map. Seems to need to be the
last instruction executed in an
actor. In particular, don't try
to SPAWN after this.
money #NUM - Spawns #NUM dollar bills.
move #??? [#1 #2 #3 ... ] ? Sets the value of #??? to
#1, and #2, and #3,(?) or if they
are not specified, to 0?
palfrom #1 #2 #3 ? Rotates the palette from #1
to #2, where #1 and 2 may be
bitflags (aka 1, 2, 4, 8, etc...)
where 16 specifies red and 0 or 32
specifies green? #3 is a "delay"
parameter that controls how quickly
the pallete change happens; larger
values = slower changes.(?) Ex.
palfrom 16 16 // Screenflash red.
pstomp ? Causes the player to look down,
and stomp the current actor?
quote #NUM - Prints quote #NUM out on the
screen in the usual fashion.
resetactioncount ? Resets the counter that counts the
number of frames that have been
displayed by the action that the
current actor is executing?
resetcount ? ??? Same as resetactioncount?
shadeto #NUM ? ???
shoot #WEAPON ? Makes an enemy fire it's weapon.
(Seems to be used to trigger blood-
splattering, too)
sizeto #1 #2 ? Scales the sprites associated
with the current actor to 1/#1 (?)
in the X direction and 1/#2 in the
Y direction.
sound #SOUND - Plays the sound associated with
#SOUND by definesound at the current
actor's location.
soundonce #SOUND ? ???
spawn #ACTOR - Spawns a copy of #ACTOR.
spritepal #NUM ? Changes the color of the current
actor. Each value of #NUM corresponds
to a different color scheme, some(?)
of which are: 1 - bright blue, 4 -
dark, 6 - Night vision green, 7 -
"messed up yellow", 8 - green,
10 - somewhat red, 19 - very reddish,
22 - Almost normal.
wackplayer - Boot... TO THE HEAD!
D. Examples
* Trampoline Trash Cans
I love those grey and red rubber-maid trash cans in the movie theater
lobby in level 1. They're simple and static, so they're fun to play with.
Let's make it so that when a player shoots one, it dents, and if they're
stand too "close" when the trash can bounces back, the trash can will hit
them and jar their viewpoint for a second.
First of all, we have to understand the trash can actor code:
action RUBCANDENT 1 1 1 1 1
action RUBCAN
actor RUBBERCAN WEAK
ifaction RUBCANDENT {
ifactioncount 16 {
strength 0
action RUBCAN
break
}
}
else ifhitweapon {
...
}
enda
Well, first of all, we don't care about what will happen to the trash can
if it's hit with a weapon, so forget about the 'else ifhitweapon' part
except to keep in mind that it takes care of denting the trash can for us.
(Which is really just a call to 'action RUBCANDENT')
Now then, before we start modifying things, try and think of what's
happening from the trash can's perspective. This is Zen and the art of
Duke3D: you must "become one" with your actor code. ;]
Thinking this way, the important stuff in this actor could be paraphrased
in english as: "if I'm dented, and if I've been dented for a while, pop back."
We'd like to modify that to: "if I'm dented, and if I've been dented for a
while, pop back. And if the player's "close," then bump them."
So how do we tell if the player's close? We can use the "ifpdistl"
primitive to tell if the player is less than a certain distance away.
Now, how close is "close?" Apogee (in DEFS.CON) defined a certain
distance to be close enough to retrieve an item. This is a good
estimate of "close." Apogee called this distance RETRIEVEDISTANCE.
How do we "bump" the player? Why, we "wackplayer," of course. ;]
Okay, the code is shaping up. We have to modify the actor right
in the part where the trash can bounces back. That's the stuff
inside the 'ifactioncount 16 { ... }' Okay, so we go in there.
What do we want? Well, IF player_close { bump_player }, right?
So:
actor RUBBERCAN WEAK
ifaction RUBCANDENT {
ifactioncount 16 {
strength 0
action RUBCAN
/* We added these three lines below: */
ifpdistl RETRIEVEDISTANCE { // If player's close...
wackplayer // Boot... TO THE HEAD!
}
break
}
}
...
enda
* Hollow-point bullets.
* Kamikaze enemies.
E. So now what?
Now go start playing with the .CON files. The worst that can happen
is that DN3D will refuse to run because you made a mistake. (Forgot a
brace, or something) If so, you'll have to correct the mistake or
restore from your backup .CON file(s). (You DID make a backup, didn't
you? Of course you did.)
Please do not email the author with questions; he probably doesn't know.
Even if he does, he won't help you. If he starts answering requests, where
will it all stop? ("How do I make the sound that Duke makes when he's
ducking in the ooze sound like a fart and have bubbles float around and
etc, etc...?") Also please don't e-mail Apogee or 3D Realms with questions;
they have specifically disavowed all responsibility if you mess with the
.CON files. Instead, do what comes naturally: play around until you figure
out the answer.
F. Appendix
* Where can I get this document?
- The UDN3DCFHG has been HTMLized by Todd Greco (tgreco@ee.net). URL:
http://users1.ee.net/tgreco/confaq.htm
- Joe Siegler of Apogee has put a plain copy of the CFHG on Apogee's
web site. The URL is:
http://www.3drealms.com/confaq.html
* Contributors/Thank You's
- Apogee Software/3D Realms for a truely fun game.
- Todd Greco and Joe Siegler for the HTML versions of the CFHG.
- Chris Gallagher (jazz411@aol.com) for help on the 'globalsound'
and 'spritepal' primitives.
--Ben Cantrick. Email to cantrick@nyx10.nyx.net--
This document is perpetually under revision. Please e-mail corrections,
comments, additions, clarifications, etc... to the author! In particular,
I'd love info and WELL COMMENTED example code for AI routines and anything
else you can think of related to .CON file hacking.
All permissions are given to copy and reproduce this document provided
no profit is made from such. The author disclaims all responsibility
for the information contained herein and makes no express or implied
warranty for it's fitness for any particular use. If playing with your
.CON files makes your computer crash, it's not my fault!
-----
INDEX/TABLE OF CONTENTS:
A. What are .CON files?
B. Can I alter .CON files?
C. How do I alter .CON files?
* What is all this strange C-programming language-like junk?
***** DEFS.CON: define
***** USER.CON: definequote, definelevelname, music, definesound
***** GAME.CON: comments, include, primitives
- Listing of primitives + their uses (if known)
D. Examples
* Trampoline trash cans
* Hollow-point pistol bullets (Unfinished)
* Kamikaze enemies (Unfinished)
E. So now what?
F. Appendix
* Where can I get this document?
* Contributors/Thank You's.
-----
A. What are Duke Nukem 3D .CON files?
.CON files are text files that "CON"trol certain aspects of the DOOM-
like game Duke Nukem 3D (DN3D). There are three of them that come with
the Shareware version of DN3D: DEFS.CON, USER.CON, and GAME.CON. (The full
version of DN3D is has not been released as of the writing of this
document, and so I can't say anything about it.) When DN3D starts up,
it loads GAME.CON, checks it for errors, and if there are none keeps the
instructions contained in it for use later on in the game. (GAME.CON is
in charge of loading up any supplemental files, like DEFS.CON and USER.CON,
that it may want to use) The instructions currently known to be usable in
GAME.CON control things as mundane as how much damage each kind of weapon
does to things as exotic as how enemies behave.
B. Can I alter .CON files?
Yes, you most certanly can. This is one of the nicer features of the
Build engine, or at least Duke3D's implementation of the Build Engine.
But, before you start playing with them, you should definitly MAKE A
BACKUP OF ALL YOUR .CON FILES!!!!! This is not only to prevent you from
having to re-install DN3D if you mess up your existing .CON files, but
also so that you can have the original .CON files as reference material
when you start altering them. Once you've got backups made, altering
the .CON files couldn't be easier: just open them up with your favorite
text editor and edit away.
C. How do I alter .CON files?
* What does all this weird, C-like junk in my .CON files mean??
A lot of things, depending on which .CON file you edited. Let's take
the .CON files from least complex to most complex:
***** DEFS.CON:
Most of the lines in DEFS.CON look something like:
define SOMETHING SOMENUMBER
What they do is basically simple substitution: If you have a line
somewhere in your DEFS.CON that said:
define THEANSWER 42
Then any time after that, if the word "THEANSWER" appears, "42" is
substituted in it's place.
By themselves, these lines aren't very interesting. They become helpful
later on, when you're writing actor code and don't want to remember that
an enemy who is TOUGH happens to have a strength of 137. You can just:
define TOUGH 137
And thereafter don't have to remember that TOUGH = 137, you just know
that an enemy is TOUGH.
Defines are ubiquitous; almost everything in the .CON files is really a
number, but is DEFINEd to be a name so it makes more sense. At some point
you can just stop caring whether things are DEFINEd labels or numbers, but
be aware that most of the things you deal with are really numbers.
***** USER.CON:
USER.CON is somewhat like DEFS.CON in that it mostly just defines things.
However, USER.CON usually defines things that might be interesting to the
game player, whereas DEFS.CON usually defines things that a DN3D player
could care less about. USER.CON also contains nice technical notes written
by the 3D Realms .CON programmer, Tod Replogle, that tell you all about how
to modify it. Almost all of the info below is basically a rehash of the notes
you can find in USER.CON
There are 5 major kinds of lines in USER.CON: defines, definequotes,
definelevelnames, musics and definesounds.
"define" lines are no different than they were in DEFS.CON; they define
stuff. Most of the stuff you can define here is emminantly useful, tho.
Examples abound: You can define Duke's starting and maximum health and
armor values here. You can define how much ammo Duke gets per clip picked up,
how much ammo is allowed for each weapon, how much damage each weapon does
per hit, etc, etc...
"definequote" lines define the different things that will pop up on the
screen in response to certain game events. You can define what words
appear on the screen when you get an some ammo or an inventory item, what
words appear on the screen when you use the various cheat codes, what
words will appear when you adjust game options, etc, etc...
"definequote" lines have two arguments: a number and a quote. The number
is what you use to refer to the quote by later on. For example, the line:
definequote 101 NIGHT VISION GOGGLES!
Defines quote number 101 is "NIGHT VISION GOGGLES!" (This is pretty
obvious, isn't it?) One other thing to keep in mind while making quotes;
Todd Replogle, the Duke3D .CON file programmer, cautions:
>// Maximum quote size is 64 characters.
"definelevelname" lines are used to define the episode and level number,
floor-plan file, par and record times, and level names for each level. The
format of a definelevelname line is:
definelevelname #LEVEL #EPSIODE MAPFILE PARTIME RECORDTIME LEVELNAME
For example, Episode 1, Level 5 is "The Abyss." The floor-plan of this
level is in the file E1L5.map. (which is actually contained in DUKE3D.GRP)
The par time is 9 minutes, 10 seconds, and the record time is 5 minutes
flat. It's definelevelname entry looks like this:
definelevelname 0 4 E1L5.map 09:10 05:00 THE ABYSS
As you can see, you must subtract one from the actual episode and level
numbers before you put them on the definelevelname line. We're in Episode 1,
but the #EPISODE is 0. We're in level 5, but the #LEVEL is 4. Notice also
that you should (I don't think it's actually required) pad the par and
record times with a leading 0 if necessary. There are also some comments
from Todd Replogle, taken from USER.CON:
> - Level file names cannot excede 13 characters.
> - Level par cannot excede 5 characters (min:sec)
> - Level titles cannot excede 32 characters.
"music" lines (as far as I can tell) define which .MID files to play for
each level. Beyond that I'm not entirely sure how "music" lines specify
exactally which file to play for which level; if someone can enlighten
me I'd be appreciative.
"definesound" lines define various names that correspond to ways to
play a VOC file. The format of a definesound line is:
definesound SOUNDNAME VOCFILENAME.voc #1 #2 #3 #4 #5
Once again, Todd Replogle has provided .CON file hackers with a helpful
technical note in USER.CON:
> -----------------------------------------------------------------
> ABOUT CHANGING SOUND FX
> The sound fx section follows this explanation.
>
> 1. The program expects to find a .VOC file
> 2. You can either change the VOC name listed below to match your new
> sound, or you can rename your file to match the name here.
> 3. New sound files should be added to the game directory. Though
> all sound files shipped with the game are included inside the
> .GRP file, the program will know if there are sound files outside
> the .GRP file, and will use them instead.
> 4. The numbers that are to the right of the sound file name are
> technical parameters which will not be explained here, except as
> follows...
> - The first 2 numbers define a random pitch variation range.
> They can be positive or negative numbers.
> - The 3rd number is a priority flag.
> - The 4th number is a bit parsed set of technical variables
> that identify the type of sound it is in the game.
> - The 5th number is a volume adjustment flag.
> -----------------------------------------------------------------
The explanation seems pretty self-evident, so I won't go into a detailed
explanation of each field of the definesound line.
***** GAME.CON:
The BIGGIE! Lots of stuff in this one, and most of it rather difficult to
explain... let's start out with the first couple of lines, which are:
/*
-------------------------------------------------------------------
Duke Nukem 3D Script Code.
Todd Replogle.
-------------------------------------------------------------------
*/
If you're a C programmer, this stuff is immediatly obvious: everything
between /* and */ is considered a "comment" and Duke3D will almost always
ignore it when reading in GAME.CON. (I say "almost always" because it appears
that Duke still counts the curly braces, { and }, inside comments. This can
lead to some interesting effects; comment out some bad code that has non-
matching curly braces and the game might refuse to load up, even though the
bad code is inside a comment, and supposedly never even seen.)
There are two kinds of comments: the double-slash or "//" comment and the
"/* */" comment. A "//" comment starts at the double-slash and extends to the
end of the line. A "//" comment ends at the end of the line.
The "/* */" comment can span several lines, but "//" comments only "null
out" one line, at most. Many // and /* */ comments can be found all over
DEFS.CON, USER.CON, and GAME.CON.
Forewarned: you must put a space after "//" before typing the text of
the comment. The comment: "//This is a comment" will cause Duke3D to error
out. Changing the comment to "// This is a comment" will fix the problem.
I assume the same holds for "/* */" comments. Things like: "/*C*/" are
a no-no. Things like "/* C */" are OK.
The next few lines in GAME.CON are "include" lines which basically
cause Duke3D to process the specified file. The line:
include defs.con
Makes DN3D go process DEFS.CON before it moves along to the next line.
And now, the really big, confusing ones: states, actions, and actors.
Apogee hasn't said anything about states, actions, or actors yet, so the
things I'm about to tell you are pure conjecture based on observation and
experimentation:
*****STATEs
As far as I can tell, "states" can be thought of as something like
subroutines. You go into a state, do something, and then come back to
wherever you were. The first state in GAME.CON is the "rats" state, which
randomly makes some rats whenever it's called.
The format of a state is:
state #STATENAME
...
ends
STATENAME is a unique number that is usually DEFINEd to be the name of
the state. No two states should have the same number. "ends," of course,
is short for "End State." Be sure that your states are defined before you
try and use them. If you try and use a state (in an actor, perhaps) that
hasn't been defined earlier in the file, DN3D will error.
*****ACTIONs
As far as I can tell, an "action" specifies a sequence of sprites
(pictures) to draw onto the screen. The format of an action is still
not quite entirely known, but it seems to be something like this:
action #SPRITEGROUP #FIRSTFRAME #LASTFRAME #?? #?? #DELAY
Each action has a set of pictures, or "frames" associated with it.
The number first number, #SPRITEGROUP, defines this bunch of picures, or
a "sprite group." #SPRITEGROUP is usually a DEFINEd number, so you can
type "action BURNING_FRAMES" instead of having to remember that the fire
animation frames are number 327, and typing "action 327." The second and
third numbers of an action specify which sequence of frames from the
specified sprite group group to step through when you're animating this
sprite. (Animation starts from the whatever-th frame in the sprite group,
number #FIRST, and goes until the whatever-th frame in the group, number
#LAST. Then it usually loops back to the first frame or else quits,
depending on the actor code controlling it.)
The #DELAY number determines the delay between frame changes. That is,
how rapidly the frames are animated on-screen. 1 = small delay and fast
animation, bigger numbers = bigger delays and slower animation. (I think?)
The two remaining numbers are a mystery. If anybody knows what they mean
and how they're used, please mail me at cantrick@rintintin.colorado.edu so
I can add them to the guide.
*****ACTORs
As far as I can tell, an "actor" is any (freestanding?) object in the
game that does something. Obviously, Duke and the enemies are actors.
However, the rubber-maid trash cans in the movie-theater lobby are also
actors, because they dent and then bounce back when you shoot them. The
items and weapons and clips are also actors, because they also do something
when you run over them: they give you an item, a weapon, or more ammo.
Walls are not actors, because they don't 'do' anything except sit there.
(Bullet-holes being an exception, I guess. Perhaps the bullets themseves are
some kind of actor that effect the surface they hit.) Doors and lifts are
borderline; I suppose the game might treat them as actors internally, but I
don't know if you can/how you would alter their behavior in the .CON file.
The format of an actor is something like:
actor #ACTORNUMBER #ACTORSTRENGTH #ACTION #SPEED #AI_FUNCTION
...
enda
#ACTORNUMBER is (I think?) a unique number that identifies this actor.
No two actors should have the same number. Usually #ACTORNUMBER is
DEFINEd to be something easier to remember than a number.
#ACTORSTRENGTH is a number that determines how much damage this actor
can take before it breaks, dies, etc... (I think?) Putting a value of 0
for this field makes the object invincible. Usually, #ACTORSTRENGTH is
DEFINEd to be something easy to remember. (See 'define TOUGH' above.)
#ACTION is (I think?) the number of an action (that is, the identifying
number of a series of frames) to cycle through for this actor, if this
actor is animated. Patches of fire actors use this to maintian an image-
loop so they look like they're constantly burning. The HoloDuke recharge
also uses an action to make the shimmer propagate across it's surface.
#SPEED is (I think?) how fast this actor moves, if it moves. I don't know
if "move" is always interpreted in the traditional sense; it appears from
the gun-turret actor code that turrets that spin in place are considered to
be "moving."
#AI_FUNCTION is (I think?) a number, as defined in DEFS.CON, that
specifies what this actor's initial AI is if it has an initial AI. The AI
routines are: face_player (1), geth (2), getv (4), random_angle (8),
face_player_smart (64), fleeenemy (128), seekplayer (512), fleeplayer (1024),
looking (2048) and dodgebullet (4096). As to what these mean or how they
work, I haven't any idea.
The last three parameters of actor seem to be optional. Things that aren't
animated, don't "move" and have no AI don't seem to include those parameters.
You can make a perfectly sensible actor without them; as a matter of fact
the majority of non-enemy actors in Duke3D (ammo and items) do not use them
at all.
* You keep putting "..." inside states and actors as if we already know
what's supposed to go inside there; but we don't!
Well, this is kind of sticky; there are quite a few things inside there,
most of them vaguely reminiscent of the C programming language with a
virtual environment twist. The things that go inside actors and actually
make up the actor "code" are what I'll call "primitives." Primitives are
simple operations that the Build Engine will perform for you. For instance,
one primitive is "ifrnd" which will tell you if a random number between
0 and 256 was less than the number you gave it. For instance, if you
wanted there to be a 1 in 2 chance of something happening, you could put:
ifrnd 128 {
... // 50% chance that this stuff gets done.
}
Since 128 is half of 256, the random number between 0 and 256 will be
less than 128 about half the time. Thusly, the "..." inside that
"ifrnd" block will only be executed about half the times the ifrnd is
run. To take another example: if you wanted a 1/4 chance, you'd
ifrnd 64 { ... }. Since a random number between 1 and 256 will be less
than 64 about 25% of the time.
There are a bunch of other primitives, too. I'll list them each here,
along with their arguments and what they do. After that, I'll give some
(hopefully) illustrative examples on how to use them.
Note: Primitives marked with a "?" instead of a "-" are still mysteries
to me. As usual, mail me (cantrick@rintintin.colorado.edu) if you know how
they work or if I've forgotten any primitives.
Note: Most "add" primitives are subject to some kind of limit. These
limits are usually explained in the explanation of the primitive.
Note: All (?) 'ifXXXXX' primitives can have an (optional) else clause
that gets executed if the condition being tested is false. For instance:
ifphealthl 45 {
quote OK // Print "You're OK."
}
else {
quote BUMMER // Print "Find some health!"
}
*****PRIMITIVES:
addammo #WEAPON #AMT - Adds #AMT ammo to #WEAPON weapon,
Subject to max ammo constraint for
that weapon. Does not give player
#WEAPON, only gives them ammo.
Ex: "addammo PISTOL_WEAPON
PISTOLAMMOAMOUNT"
addinventory #ITEM #AMT - Adds #AMT of #ITEM to player's
inventory, subject to #ITEM's max
amount limit.
addkills #NUM - Adds #NUM to number of kills
player has made.
addphealth #NUM - Adds #NUM points to player's
health. (#NUM may be negative.)
addweapon #WEAPON #INITIALAMT - Gives player weapon #WEAPON that
has #INITIALAMT of ammo in it.
Ex: "addweapon SHOTGUN_WEAPON 10"
ai AINAME #ACTION #SPEED #AITYPE ? Defines an AI routine for enemies
to use. AINAME is any string,
#ACTION is the series of frames
to cycle through when the enemy
is using this AI, #SPEED is how fast
the enemy moves when using this AI
and #AITYPE is what the enemy does
when it's using this AI. (For list
of AITYPEs, see #AI_FUNCTION under
ACTORs.)
break - Stops whatever you're doing and
immediatly exits the currently
running actor or state.
cactor #ACTORNUM ? As far as I can tell, this
primitive "c"alls another "actor"
to do something for you.
cstat #NUM ? Allows setting of the status
flag(s) of the current actor.
For instance, "cstat 32768" makes
an actor invisible. There are other
cstat flags too, but I don't know
what they all are. (Notably 0 may
be "visible," and 4 may be "moving.")
debris #??? #AMT - Causes some debris to fly. (Whose
action or spritegroup is defined
by #??? ?). Larger values of #AMT
make more junk fly. Acceptable
values of #??? seem to be "SCRAP1"
and "SCRAP2."
Ex. "debris SCRAP2 5 // Lots!"
define - Defines various things. See other
definesound sections of document.
definelevelname
fall - Causes the current actor to "fall"
until it hits a surface it can come
to rest on. Good to do right after
you "spawn" something small from
inside something larger.
globalsound #SOUND ? Plays the sound associated with
#SOUND at (which?) Duke's location.
guts #??? #AMT - Like debris, but causes different
kinds of body parts to fly instead
of debris. Acceptable values for
#??? seem to be JIBS1 to JIBS5 (Misc
body parts) as well as HEADJIB1,
LEGJIB1, ARMJIB1 (Trooper parts),
LIZMANARM1 and LIZMANLEG1 (Captain).
Also DUKETORSO, DUKELEG, DUKEGUN.
Ex. "guts JIBS1 1 // A spine."
hitradius #RADIUS #1 #2 #3 #4 ? Defines the effective distance and
strenghts of area-effectors like
explosions and fires. #RADIUS
determines the circle of maximum
effect, (I think?) within which damage
done to objects is given by #4.(?)
Objects farther away (how much
farther?) from the center of effect
suffer damages of #3, objects farther
than that sustain damage #2, objects
farther yet take damage equal to
#1, and objects sufficiently far
away from the area-effector suffer
no damage at all.
Ex: "hitradius 1024 WEAKEST WEAK
MEDIUMSTRENGTH TOUGH"
- Note about 'ifXXXXX' primitives. All (?) if primitives can have
an (optional) else clause that gets executed if the condition is
false. For instance:
ifphealthl 45 {
quote OK // Print "You're OK."
}
else {
quote BUMMER // Print "Find some health!"
}
ifactor #NUM ? Tells you if the currently
executing code was called by
the given actor?
ifactornotstayput ?
ifaction #ACTION { ... } - Tests if the current actor is
executing the given action, and
executes the appropriate code.
ifactioncount #NUM { ... } - Tests if the current actor is
displaying the given frame of an
action, and exectes the appropriate
code.
ifbulletnear ? Checks to see if a bullet has
passed near the current actor?
ifcansee - Returns true if Duke can
see the current actor.
ifcanseetarget ? Enemy AI routine?
ifcanshoottarget ? Enemy AI routine?
ifceilingdistg #NUM - Returns true if the distance to
ifceilingdistl #NUM the ceiling is greater/less than
the given number.
ifcount ? Short for ifactioncount?
ifdead - True if the current actor has
taken as much damage as they can
given their strength and is should
be pushing up daisies.
iffloordistg #NUM - True if the distance from the
iffloordistl #NUM current actor to the floor is
greater/less than #NUM.
ifgapzl #NUM ? True if the distance between the
floor and the ceiling at the actor's
location is less than #NUM.
ifhitweapon ? True if the current actor was
hit with a weapon recently. (How
recently? Since the last call to
ifhitweapon?)
ifinwater - True if the current actor is
ifonwater in/on water.
ifmove #NUM ? True if the value of variable
#NUM is not false?
ifnotmoving ? True if the current actor is
not moving?
ifp #COND ? True if a player (the last one
that affected this actor?) satisfies
#COND, when #COND can be one of
the defined (in DEFS.CON) numbers:
pstanding, pwalking, prunning,
pducking, pfalling, pjumping,
phigher, pwalkingback, prunningback,
pkicking, pshrunk, pjetpack,
ponsteroids, ponground, palive,
pdead, pfacing.
ifpdistg #NUM ? True if a(?) player's distance
ifpdistl #NUM from the current actor is greater/
less than #NUM.
ifphealthg #NUM ? True if (which?) player's health
ifphealthl #NUM is greater/less than #NUM.
ifpinventory #ITEM #AMT ?
ifrespawn - True if monsters should respawn.
ifrnd #NUM - True if #NUM is less than a
randomly selected number between
0 and 256.
ifhitspace ? True if a(?) player hit space.
ifplayersg #NUM ? True if player has greater/less
ifplayersl #NUM thatn #NUM Dukes left.
ifspawnedby #ACTOR - True if the current actor was
SPAWNed by the given type of actor.
ifspritepal ?
ifsquished ? True if the current actor was
hit by the shrink ray and then
stepped on.
ifwasweapon #WEAPON ? True if the current actor was
recently(?) hit by a shot from
#WEAPON.
killit - Removes the current actor from
the map. Seems to need to be the
last instruction executed in an
actor. In particular, don't try
to SPAWN after this.
money #NUM - Spawns #NUM dollar bills.
move #??? [#1 #2 #3 ... ] ? Sets the value of #??? to
#1, and #2, and #3,(?) or if they
are not specified, to 0?
palfrom #1 #2 #3 ? Rotates the palette from #1
to #2, where #1 and 2 may be
bitflags (aka 1, 2, 4, 8, etc...)
where 16 specifies red and 0 or 32
specifies green? #3 is a "delay"
parameter that controls how quickly
the pallete change happens; larger
values = slower changes.(?) Ex.
palfrom 16 16 // Screenflash red.
pstomp ? Causes the player to look down,
and stomp the current actor?
quote #NUM - Prints quote #NUM out on the
screen in the usual fashion.
resetactioncount ? Resets the counter that counts the
number of frames that have been
displayed by the action that the
current actor is executing?
resetcount ? ??? Same as resetactioncount?
shadeto #NUM ? ???
shoot #WEAPON ? Makes an enemy fire it's weapon.
(Seems to be used to trigger blood-
splattering, too)
sizeto #1 #2 ? Scales the sprites associated
with the current actor to 1/#1 (?)
in the X direction and 1/#2 in the
Y direction.
sound #SOUND - Plays the sound associated with
#SOUND by definesound at the current
actor's location.
soundonce #SOUND ? ???
spawn #ACTOR - Spawns a copy of #ACTOR.
spritepal #NUM ? Changes the color of the current
actor. Each value of #NUM corresponds
to a different color scheme, some(?)
of which are: 1 - bright blue, 4 -
dark, 6 - Night vision green, 7 -
"messed up yellow", 8 - green,
10 - somewhat red, 19 - very reddish,
22 - Almost normal.
wackplayer - Boot... TO THE HEAD!
D. Examples
* Trampoline Trash Cans
I love those grey and red rubber-maid trash cans in the movie theater
lobby in level 1. They're simple and static, so they're fun to play with.
Let's make it so that when a player shoots one, it dents, and if they're
stand too "close" when the trash can bounces back, the trash can will hit
them and jar their viewpoint for a second.
First of all, we have to understand the trash can actor code:
action RUBCANDENT 1 1 1 1 1
action RUBCAN
actor RUBBERCAN WEAK
ifaction RUBCANDENT {
ifactioncount 16 {
strength 0
action RUBCAN
break
}
}
else ifhitweapon {
...
}
enda
Well, first of all, we don't care about what will happen to the trash can
if it's hit with a weapon, so forget about the 'else ifhitweapon' part
except to keep in mind that it takes care of denting the trash can for us.
(Which is really just a call to 'action RUBCANDENT')
Now then, before we start modifying things, try and think of what's
happening from the trash can's perspective. This is Zen and the art of
Duke3D: you must "become one" with your actor code. ;]
Thinking this way, the important stuff in this actor could be paraphrased
in english as: "if I'm dented, and if I've been dented for a while, pop back."
We'd like to modify that to: "if I'm dented, and if I've been dented for a
while, pop back. And if the player's "close," then bump them."
So how do we tell if the player's close? We can use the "ifpdistl"
primitive to tell if the player is less than a certain distance away.
Now, how close is "close?" Apogee (in DEFS.CON) defined a certain
distance to be close enough to retrieve an item. This is a good
estimate of "close." Apogee called this distance RETRIEVEDISTANCE.
How do we "bump" the player? Why, we "wackplayer," of course. ;]
Okay, the code is shaping up. We have to modify the actor right
in the part where the trash can bounces back. That's the stuff
inside the 'ifactioncount 16 { ... }' Okay, so we go in there.
What do we want? Well, IF player_close { bump_player }, right?
So:
actor RUBBERCAN WEAK
ifaction RUBCANDENT {
ifactioncount 16 {
strength 0
action RUBCAN
/* We added these three lines below: */
ifpdistl RETRIEVEDISTANCE { // If player's close...
wackplayer // Boot... TO THE HEAD!
}
break
}
}
...
enda
* Hollow-point bullets.
* Kamikaze enemies.
E. So now what?
Now go start playing with the .CON files. The worst that can happen
is that DN3D will refuse to run because you made a mistake. (Forgot a
brace, or something) If so, you'll have to correct the mistake or
restore from your backup .CON file(s). (You DID make a backup, didn't
you? Of course you did.)
Please do not email the author with questions; he probably doesn't know.
Even if he does, he won't help you. If he starts answering requests, where
will it all stop? ("How do I make the sound that Duke makes when he's
ducking in the ooze sound like a fart and have bubbles float around and
etc, etc...?") Also please don't e-mail Apogee or 3D Realms with questions;
they have specifically disavowed all responsibility if you mess with the
.CON files. Instead, do what comes naturally: play around until you figure
out the answer.
F. Appendix
* Where can I get this document?
- The UDN3DCFHG has been HTMLized by Todd Greco (tgreco@ee.net). URL:
http://users1.ee.net/tgreco/confaq.htm
- Joe Siegler of Apogee has put a plain copy of the CFHG on Apogee's
web site. The URL is:
http://www.3drealms.com/confaq.html
* Contributors/Thank You's
- Apogee Software/3D Realms for a truely fun game.
- Todd Greco and Joe Siegler for the HTML versions of the CFHG.
- Chris Gallagher (jazz411@aol.com) for help on the 'globalsound'
and 'spritepal' primitives.
--Ben Cantrick. Email to cantrick@nyx10.nyx.net--