news about forums links tools tutorials contact

Locational Damage - author: da crack man!
Alright, here's the idea: a sniper rifle that knows what part of the body its hitting. How do we do this? Well to explain I simply subclassed UT's sniper rifle and replaced the ProcessTraceHit() function, which if you've done anything with Weapons yet, you'll know that this is where damage is applied and shells are normally spawned and whatnot.
For clarity's sake, I've omitted everything but the location detection code. Hopefully this will make things easier to understand on your end. Note that there is more than one way to accomplish this goal, probably more efficient and tons smaller, but I've decided to use rotators since I think angles are easier to understand vector dot products. :) Note that this is meant for humanoids, ie the code assumes the head is located above the body and legs, etc etc.

    class BetterSniperRifle extends SniperRifle;

    function ProcessTraceHit(Actor Other, Vector HitLocation, Vector HitNormal, Vector X, Vector Y, Vector Z)
    {
      // We'll use two variables to store some data, not necessary but
      // it definitely helps to keep code clearer and cleaner.
      local int HitHeight, HitAngle;

      // First off, lets make sure its a pawn, cause most rocks aren't
      // worth the trouble to do locational damage (thats a joke...)
      if (Other.IsA('Pawn'))
      {
        // Okay HitHeight is easy to get, we simply take the Z point
        // (z being the vertical axis) where the bullet hit and subtract
        // that from the target's location. (which will be the middle
        // of the model)
        HitHeight = HitLocation.Z - Other.Location.Z;

        // Getting HitAngle is a bit more complicated to understand,
        // but here goes:  Basically we convert where the bullet hit
        // into a direction, and subtract that from the direction the
        // target is facing.  This will let us tell what area the bullet
        // hit, sort of determining what quadrant it is in (remember
        // trig?)
        HitAngle = (Other.Rotation.Yaw - rotator(HitLocation - Other.Location).Yaw) & 65535;

        // BroadcastMessage is your friend.  Use it to send useful
        // debug information in game, just be sure to remove it once
        // you want to release your code :)
        BroadcastMessage("HitHeight: "$HitHeight$", HitAngle: "$HitAngle$", Other.Rotation: "$Other.Rotation);

        // Each actor that has collision has two variables to define
        // its area of collision, CollisionHeight and CollisionRadius.
        // UT uses this info to generate a cylinder of collision, and
        // here we use CollisionHeight to determine what part of the
        // model we hit, as the upper part will most likely be the "head"
        // while the middle the "body" and the bottom the "legs".
        if (HitHeight > 0.62 * Other.CollisionHeight)
          BroadcastMessage("Head hit");
        else if (HitHeight < 0.35 * Other.CollisionHeight)
          BroadcastMessage("Leg hit");
        else BroadcastMessage("Body hit");

        // This is where we classify the angle into our "quadrants",
        // but instead of using right (90 degree) angles to define
        // the quadrants, i used 12000 UUs, or about 70 degrees or so.
        // This will give us 4 offsized quadrants, with 2 big ones
        // for front and rear, and 2 small ones for the sides.
        // The logic here is simple, if the angle is within our bounds
        // then it should be classified in the appropriate "quandrant",
        // otherwise check the next bounds and so on.
        // See the image below for a clearer picture.
        if ( (HitAngle < 12000 && HitAngle > 0) || (HitAngle > 53535 && HitAngle < 65535) )
          BroadcastMessage("Frontal hit");
        else if ( (HitAngle < 44768 && HitAngle > 20768) )
          BroadcastMessage("Rear hit");
        else BroadcastMessage("Side hit");
      }
    }

Now at this point it would be a good idea to do add some damage code, and maybe some effects like slowing the player down when hit in the legs...etc. Make this locational detection code actually useful for something, but alas thats beyond the scope of this tutorial, or some other lame excuse like that... :)