From: Sammy <samedi@clark.net>
Subject: Archer spec_proc

I got a couple of requests for an archer spec_proc last week while it
was being discussed here so I'm posting it as promised. It's not too
big but I apologize if it annoys anyone :)

I tried to make it as generic and flexible as possible. I set some
rooms up as an example, so if you use this code unchanged, and assign
the proc to cityguards, then if they stand inside the east or west
gate of midgaard (where you can usually find at least one or two), any
PC within 2 rooms outside the gate will be fired on randomly. You can
easily change the -1 rooms to the rooms 3 away from the guards, and if
you want to fire on more than 3 rooms from a single archer room you'll
have to extend the array.

If you're standing in the same room as the archer, you'll see the
hit/miss messages. This wasn't intended at first, but it could provide
some entertainment for players who hang out with the guards and place
bets on who gets hit next :)

#define NUM_ARCHERS      2              /* # of rooms archers can shoot from */
#define NUM_TARGETS      3              /* # of rooms an archer can shoot at */
#define HIT_CHANCE       30             /* accuracy 30% chance to hit */
#define ARCHER_NUM_DICE  2              /*  archer damage dice */
#define ARCHER_SIZE_DICE 5              /*  archer does 2d5 each hit */

SPECIAL(archer)
{
  struct char_data *targ;
  int i, j, k;
  int damage;

  sh_int to_from_rooms[NUM_ARCHERS][NUM_TARGETS + 1] = {
   /* archer room     target room #1     #2       #3 */
      { 3040,              3052,        6092,     -1},   /* archer room #1 */
      { 3041,              3053,        3503,     -1}    /* room #2 */
  };

  char *mssgs[] = {
    "You feel a sharp pain in your side as an arrow finds its mark!",
    "You hear a dull thud as an arrow pierces $N!",
    "An arrow whistles by your ear, barely missing you!",
    "An arrow narrowly misses $N!"
  };

  if(cmd)
    return FALSE;

  if(GET_POS(ch) != POS_STANDING)
    return FALSE;

  for(i = 0; i < NUM_ARCHERS; i++) {
    if(real_room(to_from_rooms[i][0]) == ch->in_room) {
      for(j = 1; j <= NUM_TARGETS; j++) {
        if((k = real_room(to_from_rooms[i][j])) >= 0) {
          for(targ = world[k].people; targ; targ = targ->next_in_room) {
            if(!IS_NPC(targ) && (GET_LEVEL(targ) < LVL_IMMORT) &&
              (!number(0, 4))) {
              if(number(1, 100) <= HIT_CHANCE) {
                act(mssgs[0], 1, ch, 0, targ, TO_VICT);
                act(mssgs[1], 1, ch, 0, targ, TO_NOTVICT);
                damage = number(5, 50);
                GET_HIT(targ) -= damage + (number(1, 5));
                /*  these above numbers can be changed for different
                 *  damage levels.
                 */
                update_pos(targ);
                return TRUE;
              } else {
                act(mssgs[2], 1, ch, 0, targ, TO_VICT);
                act(mssgs[3], 1, ch, 0, targ, TO_NOTVICT);
                return TRUE;
              }
            }
          }
        }
      }
    }
  }
  return FALSE;
}
