MCS' Coding Tips

Controlling the weapon behaviour

   Written by MCS
   Tested by Nescio

Main Page


Wolfenstein 3D
Texture Library

MCS' Coding
Tips - "Success"!





Original Wolf 3D


Other Stuff


Email us!
One of the most frequently asked questions here at How do I change the behaviour of the different weapons?
As a matter of fact, the properties of the weapons are controlled by just a few lines in

Let's have a look at these lines:

struct atkinf
char tics,attack,frame;  // attack is 1 for gun, 2 for knife
} attackinfo[4][14] =

{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },    //knife
{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },    //pistol
{ {6,0,1},{6,2,2},{6,3,3},{6,-1,4} },    //machinegun
{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },    //chaingun

This is the definition of the attackinfo structure.
Each line deals with the information of one weapon (the base of adding extra weapons lies in adding an extra line to this structure)
Now let's examine the line concerning the knife:

{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },

You'll see this line is divided in 4 groups. The last digit of each group (1, 2, 3 and 4 respectively) tells the engine which images to display when an attack is made. By adding more "groups" to the line you can expand the number of images used in an attack sequence.
Each group starts with a 6. This represents the amount of time that each frame (image) is displayed, measured in "tics" which is 1/70th of a second.
The digit in the middle of each group contains the value passed to the
T_Attack function found at the end of WL_AGENT.C

switch (cur->attack)
  case -1:
   ob->state = &s_player;
   if (!gamestate.ammo)
    gamestate.weapon = wp_knife;
    DrawWeapon ();
    if (gamestate.weapon != gamestate.chosenweapon)
     gamestate.weapon = gamestate.chosenweapon;
     DrawWeapon ();
   gamestate.attackframe = gamestate.weaponframe = 0;

  case 4:
   if (!gamestate.ammo)
   if (buttonstate[bt_attack])
    gamestate.attackframe -= 2;
  case 1:
   if (!gamestate.ammo)
   { // can only happen with chain gun
   GunAttack (ob);
   DrawAmmo ();

  case 2:
   KnifeAttack (ob);

  case 3:
   if (gamestate.ammo && buttonstate[bt_attack])
    gamestate.attackframe -= 2;

Study this function carefully, and you'll learn that a "
case 0" (zero) means "do nothing, just display the image", a "case 2" means "perform a knife attack" and a "case -1" (minus 1) means "go back into non-attack mode"

All of this may sound a bit confusing, so I'd suggest that you'll just play around a bit with those figures.
Try to expand the frame display duration for instance, and make the chaingun act like a knife by replacing the "1" in the middle (gun attack) by a "2" (knife attack).
You will see, it's not that difficult, once you'll get the hang of it.

Now let's have a look at the "damage done" control. Check this line in the
KnifeAttack() function:

DamageActor (closest,US_RndT() >> 4);

US_RndT() is a built-in function that generates a random value between 0 and 255 ( so the damage done varies with every attack, which is more realistic).
The " >> 4" means: "divide by 16"
So let's say
US_RndT() generates 160.. then you'll deal 160/16 = 10 hitpoints damage with one knife stab (now you'll understand why it's virtually impossible to kill those bosses with a knife :-)
Changing ">> 4" into ">> 3" will divide by only 8, so by doing this you will double the damage done by the knife.
Assuming you're having 3 different "knife-alike" weapons, you could write something like this:

switch (gamestate.weapon)
case wp_knife:
  DamageActor (closest,US_RndT() >> 4);
case wp_machinegun:
  DamageActor (closest,US_RndT() >> 3);
case wp_chaingun:
  DamageActor (closest,US_RndT() >> 2);

For more precise control, you might want to use a modulus instead of the bitshifting operator that ID used.

Same goes for the damage dealt by "gun like" weapons. The significant lines to manipulate this can be found in the
GunAttack() function:

if (dist<2)
  damage = US_RndT() / 4;
else if (dist<4)
  damage = US_RndT() / 6;
  if ( (US_RndT() / 12) < dist)  // missed
  damage = US_RndT() / 6;

DamageActor (closest,damage);

Again, take your time to play around with these lines, and you might end up with some original results.