MCS' Coding Tips
                 "Success!"



  
Controlling the weapon behaviour

   Written by MCS
   Tested by Nescio


   
Main Page

News

Wolfenstein 3D
Texture Library


MCS' Coding
Tips - "Success"!


Utilities

Spear
Resurrection


Wolfendoom

Wolf
Collection


Original Wolf 3D

Doom/Duke
maps


Other Stuff

Links

Questions?
Email us!
One of the most frequently asked questions here at areyep.com: 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
WL_AGENT.C

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 ();
   }
   else
   {
    if (gamestate.weapon != gamestate.chosenweapon)
    {
     gamestate.weapon = gamestate.chosenweapon;
     DrawWeapon ();
    }
   };
   gamestate.attackframe = gamestate.weaponframe = 0;
   return;

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

  case 2:
   KnifeAttack (ob);
   break;

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


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);
  break;
case wp_machinegun:
  DamageActor (closest,US_RndT() >> 3);
  break;
case wp_chaingun:
  DamageActor (closest,US_RndT() >> 2);
  break;
}


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;
else
{
  if ( (US_RndT() / 12) < dist)  // missed
   return;
  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.

Success,
MCS.