diff -u -F regexp -N src/stkoas/act.informative.c src/act.informative.c
--- src/stkoas/act.informative.c	Wed Oct 29 00:16:22 1997
+++ src/act.informative.c	Mon May 04 08:49:52 1998
@@ -107,12 +107,36 @@
 void list_obj_to_char(struct obj_data * list, struct char_data * ch, int mode,
 		           int show)
 {
-  struct obj_data *i;
+	struct obj_data *i, *j;
+	char buf[10];
   bool found;
+  int num;
 
   found = FALSE;
   for (i = list; i; i = i->next_content) {
+         num = 0;
+ 
+       for (j = list; j != i; j = j->next_content)
+ 	if (j->item_number==NOTHING) {
+ 	  if(strcmp(j->short_description,i->short_description)==0) break;
+ 	} else 
+ 	  if (j->item_number==i->item_number) break;
+ 
+       if ((GET_OBJ_TYPE(i) != ITEM_CONTAINER) && (j!=i))
+         continue;
+ 
+       for (j = i; j; j = j->next_content)
+ 	if (j->item_number==NOTHING) {
+ 	  if(strcmp(j->short_description,i->short_description)==0) num++;
+ 	} else 
+ 	  if (j->item_number==i->item_number) num++;
+ 
     if (CAN_SEE_OBJ(ch, i)) {
+			if ((GET_OBJ_TYPE(i) != ITEM_CONTAINER) && (num!=1)) 
+			{
+				sprintf(buf,"(%2i) ", num);
+				send_to_char(buf, ch);
+			}
       show_obj_to_char(i, ch, mode);
       found = TRUE;
     }
@@ -394,10 +418,63 @@
   send_to_char(CCNRM(ch, C_NRM), ch);
 }
 
+ void list_scanned_chars(struct char_data * list, struct char_data * ch, 
+                         int distance, int door) 
+ {
+   const char *how_far[] = {
+     "close by",
+     "a ways off",
+     "far off to the"
+   };
+ 
+   struct char_data *i;
+   int count = 0;
+   *buf = '\0';
+ 
+ /* this loop is a quick, easy way to help make a grammatical sentence
+    (i.e., "You see x, x, y, and z." with commas, "and", etc.) */
+ 
+   for (i = list; i; i = i->next_in_room)
+ 
+ /* put any other conditions for scanning someone in this if statement -
+    i.e., if (CAN_SEE(ch, i) && condition2 && condition3) or whatever */
+ 
+     if (CAN_SEE(ch, i))
+       count++;
+ 
+   if (!count)
+     return;
+ 
+   for (i = list; i; i = i->next_in_room) {
+ 
+ /* make sure to add changes to the if statement above to this one also, using
+    or's to join them.. i.e., 
+    if (!CAN_SEE(ch, i) || !condition2 || !condition3) */
+ 
+     if (!CAN_SEE(ch, i))
+       continue; 
+     if (!*buf)
+       sprintf(buf, "You see %s", GET_NAME(i));
+     else 
+       sprintf(buf, "%s%s", buf, GET_NAME(i));
+     if (--count > 1)
+       strcat(buf, ", ");
+     else if (count == 1)
+       strcat(buf, " and ");
+     else {
+       sprintf(buf2, " %s %s.\r\n", how_far[distance], dirs[door]);
+       strcat(buf, buf2);      
+     }
+   }
+   send_to_char(buf, ch);
+ 
+ }
 
-
 void look_in_direction(struct char_data * ch, int dir)
 {
+	int room, nextroom, orig_room = ch->in_room;
+	int distance;
+
   if (EXIT(ch, dir)) {
     if (EXIT(ch, dir)->general_description)
       send_to_char(EXIT(ch, dir)->general_description, ch);
@@ -411,6 +488,25 @@
       sprintf(buf, "The %s is open.\r\n", fname(EXIT(ch, dir)->keyword));
       send_to_char(buf, ch);
     }
+     
+     if CAN_GO2(orig_room, dir)
+       nextroom = EXIT2(orig_room, dir)->to_room;
+     else
+       nextroom = NOWHERE;
+ 
+     for (distance = 0; ((nextroom != NOWHERE) && (distance < 3)); distance++) {
+ 
+       if (world[nextroom].people)
+ 	list_scanned_chars(world[nextroom].people, ch, distance, dir);
+ 
+       room = nextroom;
+       if CAN_GO2(room, dir)
+         nextroom = EXIT2(room, dir)->to_room;
+       else
+         nextroom = NOWHERE;
+ 
+     }
+
   } else
     send_to_char("Nothing special there...\r\n", ch);
 }
diff -u -F regexp -N src/stkoas/act.item.c src/act.item.c
--- src/stkoas/act.item.c	Wed Oct 29 00:16:22 1997
+++ src/act.item.c	Mon May 04 13:19:10 1998
@@ -1349,3 +1349,29 @@
       perform_remove(ch, i);
   }
 }
+
+  ACMD(do_pull)
+ {
+ 
+   one_argument(argument, arg);
+ 
+   if (!*arg) {
+     send_to_char("Pull what?\r\n", ch);
+     return;
+   }
+ /* for now only pull pin will work and must be wielding a grenade */
+   if(!str_cmp(arg,"pin")) {
+     if(GET_EQ(ch, WEAR_WIELD)) {
+       if(GET_OBJ_TYPE(GET_EQ(ch, WEAR_WIELD)) == ITEM_GRENADE) {
+         send_to_char("You pull the pin, the grenade is activated!\r\n", ch);
+         SET_BIT(GET_OBJ_EXTRA(GET_EQ(ch, WEAR_WIELD)), ITEM_LIVE_GRENADE);
+       } else
+         send_to_char("That's NOT a grenade!\r\n", ch);
+     } else
+       send_to_char("You aren't wielding anything!\r\n", ch);
+   }
+ 
+ /* put other 'pull' options here later */
+  return;
+ }
+
diff -u -F regexp -N src/stkoas/act.offensive.c src/act.offensive.c
--- src/stkoas/act.offensive.c	Wed Oct 29 00:16:22 1997
+++ src/act.offensive.c	Mon May 04 18:30:06 1998
@@ -25,11 +25,23 @@
 extern struct descriptor_data *descriptor_list;
 extern struct room_data *world;
 extern int pk_allowed;
+extern char *dirs[];
+extern int rev_dir[];
 
 /* extern functions */
 void raw_kill(struct char_data * ch);
 void check_killer(struct char_data * ch, struct char_data * vict);
+int perform_move(struct char_data *ch, int dir, int specials_check);
 
+/* Daniel Houghton's revised external functions */
+int skill_roll(struct char_data *ch, int skill_num);
+void strike_missile(struct char_data *ch, struct char_data *tch, 
+                   struct obj_data *missile, int dir, int attacktype);
+void miss_missile(struct char_data *ch, struct char_data *tch, 
+                struct obj_data *missile, int dir, int attacktype);
+void mob_reaction(struct char_data *ch, struct char_data *vict, int dir);
+void fire_missile(struct char_data *ch, char arg1[MAX_INPUT_LENGTH],
+                  struct obj_data *missile, int pos, int range, int dir);
 
 ACMD(do_assist)
 {
@@ -412,3 +424,142 @@
     damage(ch, vict, GET_LEVEL(ch) >> 1, SKILL_KICK);
   WAIT_STATE(ch, PULSE_VIOLENCE * 3);
 }
+
+ 
+ 
+ ACMD(do_shoot)
+ { 
+   struct obj_data *missile;
+   char arg2[MAX_INPUT_LENGTH];
+   char arg1[MAX_INPUT_LENGTH];
+   int dir, range;
+ 
+   if (!GET_EQ(ch, WEAR_WIELD)) { 
+     send_to_char("You aren't wielding a shooting weapon!\r\n", ch);
+     return;
+   }
+ 
+   if (!GET_EQ(ch, WEAR_HOLD)) { 
+     send_to_char("You need to be holding a missile!\r\n", ch);
+     return;
+   }
+ 
+   missile = GET_EQ(ch, WEAR_HOLD);
+ 
+   if ((GET_OBJ_TYPE(GET_EQ(ch, WEAR_WIELD)) == ITEM_SLING) &&
+       (GET_OBJ_TYPE(missile) == ITEM_ROCK))
+        range = GET_EQ(ch, WEAR_WIELD)->obj_flags.value[0];
+   else 
+     if ((GET_OBJ_TYPE(missile) == ITEM_ARROW) &&
+         (GET_OBJ_TYPE(GET_EQ(ch, WEAR_WIELD)) == ITEM_BOW))
+          range = GET_EQ(ch, WEAR_WIELD)->obj_flags.value[0];
+   else 
+     if ((GET_OBJ_TYPE(missile) == ITEM_BOLT) &&
+         (GET_OBJ_TYPE(GET_EQ(ch, WEAR_WIELD)) == ITEM_CROSSBOW))
+          range = GET_EQ(ch, WEAR_WIELD)->obj_flags.value[0];
+ 
+   else {
+     send_to_char("You should wield a missile weapon and hold a missile!\r\n", ch);
+     return;
+   }
+ 
+   two_arguments(argument, arg1, arg2);
+ 
+   if (!*arg1 || !*arg2) {
+     send_to_char("You should try: shoot <someone> <direction>\r\n", ch);
+     return;
+   }
+ 
+ /*  if (IS_DARK(ch->in_room)) { 
+     send_to_char("You can't see that far.\r\n", ch);
+     return;
+   } */
+ 
+   if ((dir = search_block(arg2, dirs, FALSE)) < 0) {
+     send_to_char("What direction?\r\n", ch);
+     return;
+   }
+ 
+   if (!CAN_GO(ch, dir)) { 
+     send_to_char("Something blocks the way!\r\n", ch);
+     return;
+   }
+ 
+   if (range > 3) 
+     range = 3;
+   if (range < 1)
+     range = 1;
+ 
+   fire_missile(ch, arg1, missile, WEAR_HOLD, range, dir);
+ 
+ }
+ 
+ 
+ ACMD(do_throw)
+ {
+ 
+ /* sample format: throw monkey east
+    this would throw a throwable or grenade object wielded
+    into the room 1 east of the pc's current room. The chance
+    to hit the monkey would be calculated based on the pc's skill.
+    if the wielded object is a grenade then it does not 'hit' for
+    damage, it is merely dropped into the room. (the timer is set
+    with the 'pull pin' command.) */
+ 
+   struct obj_data *missile;
+   int dir, range = 1;
+   char arg2[MAX_INPUT_LENGTH];
+   char arg1[MAX_INPUT_LENGTH];
+   two_arguments(argument, arg1, arg2);
+ 
+ /* only two types of throwing objects: 
+    ITEM_THROW - knives, stones, etc
+    ITEM_GRENADE - calls tick_grenades.c . */
+ 
+   if (!(GET_EQ(ch, WEAR_WIELD))) { 
+     send_to_char("You should wield something first!\r\n", ch);
+     return;
+   }
+ 
+   missile = GET_EQ(ch, WEAR_WIELD);
+   
+   if (!((GET_OBJ_TYPE(missile) == ITEM_THROW) ||
+      (GET_OBJ_TYPE(missile) == ITEM_GRENADE))) { 
+     send_to_char("You should wield a throwing weapon first!\r\n", ch);
+     return;
+   }
+   
+   if (GET_OBJ_TYPE(missile) == ITEM_GRENADE) {
+     if (!*arg1) {
+       send_to_char("You should try: throw <direction>\r\n", ch);
+       return;
+     }
+     if ((dir = search_block(arg1, dirs, FALSE)) < 0) { 
+       send_to_char("What direction?\r\n", ch);
+       return;
+     }
+   } else {
+ 
+     two_arguments(argument, arg1, arg2);
+ 
+     if (!*arg1 || !*arg2) {
+       send_to_char("You should try: throw <someone> <direction>\r\n", ch);
+       return;
+     }
+ 
+ /* arg2 must be a direction */
+ 
+     if ((dir = search_block(arg2, dirs, FALSE)) < 0) { 
+       send_to_char("What direction?\r\n", ch);
+       return;
+     }
+   }
+ 
+ /* make sure we can go in the direction throwing. */
+   if (!CAN_GO(ch, dir)) { 
+     send_to_char("Something blocks the way!\r\n", ch);
+     return;
+   }
+ 
+   fire_missile(ch, arg1, missile, WEAR_WIELD, range, dir);
+ }   
\ No newline at end of file
diff -u -F regexp -N src/stkoas/act.wizard.c src/act.wizard.c
--- src/stkoas/act.wizard.c	Mon May 04 18:43:06 1998
+++ src/act.wizard.c	Mon May 04 18:35:36 1998
@@ -518,6 +518,22 @@
 	    skill_name(GET_OBJ_VAL(j, 3)), GET_OBJ_VAL(j, 0),
 	    GET_OBJ_VAL(j, 2), GET_OBJ_VAL(j, 1));
     break;
+	case ITEM_THROW:
+	case ITEM_ROCK:
+	case ITEM_BOLT:
+	case ITEM_ARROW:
+		sprintf(buf, "Number dam dice: %d Size dam dice: %d",
+			GET_OBJ_VAL(j, 2), GET_OBJ_VAL(j, 3));
+		break;
+	case ITEM_GRENADE:
+		sprintf(buf, "Timer: %d Num dam dice: %d Size dam dice: %d",
+			GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 2));
+		break;
+	case ITEM_BOW:
+	case ITEM_CROSSBOW:
+	case ITEM_SLING:
+		sprintf(buf, "Range: %d", GET_OBJ_VAL(j, 1));
+		break;
   case ITEM_WEAPON:
     sprintf(buf, "Todam: %dd%d, Message type: %d",
 	    GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 2), GET_OBJ_VAL(j, 3));
Common subdirectories: src/stkoas/circle and src/circle
diff -u -F regexp -N src/stkoas/comm.c src/comm.c
--- src/stkoas/comm.c	Mon May 04 18:43:06 1998
+++ src/comm.c	Mon May 04 00:38:40 1998
@@ -117,6 +117,7 @@
 void check_idle_passwords(void);
 void heartbeat(int pulse);
 int set_sendbuf(socket_t s);
+void tick_grenade(void);
 
 
 /* extern fcnts */
@@ -740,7 +741,10 @@
     check_idle_passwords();
 
   if (!(pulse % PULSE_MOBILE))
+  {
     mobile_activity();
+    tick_grenade();
+	}
 
   if (!(pulse % PULSE_VIOLENCE))
     perform_violence();
diff -u -F regexp -N src/stkoas/constants.c src/constants.c
--- src/stkoas/constants.c	Mon May 04 18:43:06 1998
+++ src/constants.c	Mon May 04 00:40:26 1998
@@ -312,6 +312,14 @@
   "PEN",
   "BOAT",
   "FOUNTAIN",
+	"THROW",
+  "GRENADE",
+  "BOW",
+  "SLING",
+  "CROSSBOW",
+  "BOLT",
+  "ARROW",
+  "ROCK",
   "\n"
 };
 
diff -u -F regexp -N src/stkoas/fight.c src/fight.c
--- src/stkoas/fight.c	Wed Oct 29 00:16:24 1997
+++ src/fight.c	Mon May 04 19:18:24 1998
@@ -34,6 +34,12 @@
 extern int max_exp_gain;	/* see config.c */
 extern int max_exp_loss;	/* see config.c */
 
+/* Daniel Houghton's revision */
+extern char *dirs[];
+extern int rev_dir[];
+extern struct index_data *obj_index;
+extern struct room_data *world;
+  
 /* External procedures */
 char *fread_action(FILE * fl, int nr);
 char *fread_string(FILE * fl, char *error);
@@ -410,6 +416,9 @@
   } else
     send_to_char("You receive one lousy experience point.\r\n", ch);
 
+/* error C2065: 'missile' : undeclared identifier */
+    /*	if (!missile)  */
+
   gain_exp(ch, exp);
   change_alignment(ch, victim);
 }
@@ -614,11 +623,18 @@
 void damage(struct char_data * ch, struct char_data * victim, int dam,
 	    int attacktype)
 {
+	/* Daniel Houghton's missile modification */
+	bool missile = FALSE;
+	
   if (GET_POS(victim) <= POS_DEAD) {
     log("SYSERR: Attempt to damage a corpse.");
     die(victim);
     return;			/* -je, 7/7/92 */
   }
+  
+	/* Daniel Houghton's missile modification */
+	if (ch->in_room != victim->in_room)
+		missile = TRUE;
 
   /* peaceful rooms */
   if (ch != victim && ROOM_FLAGGED(ch->in_room, ROOM_PEACEFUL)) {
@@ -633,8 +649,9 @@
   /* You can't damage an immortal! */
   if (!IS_NPC(victim) && (GET_LEVEL(victim) >= LVL_IMMORT))
     dam = 0;
-
-  if (victim != ch) {
+    
+	/* Daniel Houghton's missile modification */
+	if ((victim != ch) && (!missile)) {
     /* Start the attacker fighting the victim */
     if (GET_POS(ch) > POS_STUNNED && (FIGHTING(ch) == NULL))
       set_fighting(ch, victim);
@@ -662,8 +679,11 @@
   /* Check for PK if this is not a PK MUD */
   if (!pk_allowed) {
     check_killer(ch, victim);
+	/* Daniel Houghton's modification:  Let the PK flag be enough! */
+	/*
     if (PLR_FLAGGED(ch, PLR_KILLER) && (ch != victim))
       dam = 0;
+	*/
   }
 
   /* Set the maximum damage per round and subtract the hit points */
@@ -671,7 +691,7 @@
   GET_HIT(victim) -= dam;
 
   /* Gain exp for the hit */
-  if (ch != victim)
+	if ((ch != victim) && (!missile))
     gain_exp(ch, GET_LEVEL(victim) * dam);
 
   update_pos(victim);
@@ -687,7 +707,7 @@
    * death blow, send a skill_message if one exists; if not, default to a
    * dam_message. Otherwise, always send a dam_message.
    */
-  if (!IS_WEAPON(attacktype))
+	if ((!IS_WEAPON(attacktype)) || missile)
     skill_message(dam, ch, victim, attacktype);
   else {
     if (GET_POS(victim) == POS_DEAD || dam == 0) {
@@ -755,6 +775,7 @@
   if (GET_POS(victim) == POS_DEAD) {
     if ((ch != victim) && (IS_NPC(victim) || victim->desc)) {
       if (IS_AFFECTED(ch, AFF_GROUP))
+      	if (!missile)
 	group_gain(ch, victim);
       else
         solo_gain(ch, victim);
@@ -913,3 +934,295 @@
       (mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, "");
   }
 }
+
+ 
+ 
+ int skill_roll(struct char_data *ch, int skill_num) 
+ {
+   if (number(0, 101) > GET_SKILL(ch, skill_num))
+     return FALSE;
+   else
+     return TRUE;
+ }
+ 
+ 
+ void strike_missile(struct char_data *ch, struct char_data *tch, 
+                    struct obj_data *missile, int dir, int attacktype)
+ {
+   int dam;
+   extern struct str_app_type str_app[];
+ 
+   dam = str_app[STRENGTH_APPLY_INDEX(ch)].todam;
+   dam += dice(missile->obj_flags.value[1],
+               missile->obj_flags.value[2]); 
+   dam += GET_DAMROLL(ch);
+              
+   damage(ch, tch, dam, attacktype);
+              
+   send_to_char("You hit!\r\n", ch);
+   sprintf(buf, "$P flies in from the %s and strikes %s.", 
+           dirs[rev_dir[dir]], GET_NAME(tch));
+   act(buf, FALSE, tch, 0, missile, TO_ROOM);
+   sprintf(buf, "$P flies in from the %s and hits YOU!",
+                 dirs[rev_dir[dir]]);
+   act(buf, FALSE, tch, 0, missile, TO_CHAR);
+   return;
+ } 
+ 
+ 
+ void miss_missile(struct char_data *ch, struct char_data *tch, 
+                 struct obj_data *missile, int dir, int attacktype)
+ {
+   sprintf(buf, "$P flies in from the %s and hits the ground!",
+                 dirs[rev_dir[dir]]);
+   act(buf, FALSE, tch, 0, missile, TO_ROOM);
+   act(buf, FALSE, tch, 0, missile, TO_CHAR);
+   send_to_char("You missed!\r\n", ch);
+ }
+ 
+ 
+ void mob_reaction(struct char_data *ch, struct char_data *vict, int dir)
+ {
+   if (IS_NPC(vict) && !FIGHTING(vict) && GET_POS(vict) > POS_STUNNED)
+ 
+      /* can remember so charge! */
+     if (IS_SET(MOB_FLAGS(vict), MOB_MEMORY)) {
+       remember(vict, ch);
+       sprintf(buf, "$n bellows in pain!");
+       act(buf, FALSE, vict, 0, 0, TO_ROOM); 
+       if (GET_POS(vict) == POS_STANDING) {
+         if (!do_simple_move(vict, rev_dir[dir], 1))
+           act("$n stumbles while trying to run!", FALSE, vict, 0, 0, TO_ROOM);
+       } else
+       GET_POS(vict) = POS_STANDING;
+       
+     /* can't remember so try to run away */
+     } else {
+       do_flee(vict, "", 0, 0);
+     }
+ }
+ 
+ 
+ void fire_missile(struct char_data *ch, char arg1[MAX_INPUT_LENGTH],
+                   struct obj_data *missile, int pos, int range, int dir)
+ {
+   bool shot = FALSE, found = FALSE;
+   int attacktype;
+   int room, nextroom, distance;
+   struct char_data *vict;
+     
+   if (ROOM_FLAGGED(ch->in_room, ROOM_PEACEFUL)) {
+     send_to_char("This room just has such a peaceful, easy feeling...\r\n", ch);
+     return;
+   }
+ 
+   room = ch->in_room;
+ 
+   if CAN_GO2(room, dir)
+     nextroom = EXIT2(room, dir)->to_room;
+   else
+     nextroom = NOWHERE;
+   
+   if (GET_OBJ_TYPE(missile) == ITEM_GRENADE) {
+     send_to_char("You throw it!\r\n", ch);
+     sprintf(buf, "$n throws %s %s.", 
+       GET_EQ(ch,WEAR_WIELD)->short_description, dirs[dir]);
+     act(buf, FALSE, ch, 0, 0, TO_ROOM);
+     sprintf(buf, "%s flies in from the %s.\r\n",
+             missile->short_description, dirs[rev_dir[dir]]);
+     send_to_room(buf, nextroom);
+     obj_to_room(unequip_char(ch, pos), nextroom);
+     return;
+   }
+ 
+   for (distance = 1; ((nextroom != NOWHERE) && (distance <= range)); distance++) {
+ 
+     for (vict = world[nextroom].people; vict ; vict= vict->next_in_room) {
+       if ((isname(arg1, GET_NAME(vict))) && (CAN_SEE(ch, vict))) {
+         found = TRUE;
+         break;
+       }
+     }
+ 
+     if (found == 1) {
+ 
+       /* Daniel Houghton's missile modification */
+       if (missile && ROOM_FLAGGED(vict->in_room, ROOM_PEACEFUL)) {
+         send_to_char("Nah.  Leave them in peace.\r\n", ch);
+         return;
+       }
+ 
+       switch(GET_OBJ_TYPE(missile)) {
+         case ITEM_THROW:
+           send_to_char("You throw it!\r\n", ch);
+           sprintf(buf, "$n throws %s %s.", GET_EQ(ch,WEAR_WIELD)->short_description,
+                        dirs[dir]);
+           attacktype = SKILL_THROW;
+           break;
+         case ITEM_ARROW:
+           act("$n aims and fires!", TRUE, ch, 0, 0, TO_ROOM);
+           send_to_char("You aim and fire!\r\n", ch);
+           attacktype = SKILL_BOW;
+           break;
+         case ITEM_ROCK:
+           act("$n aims and fires!", TRUE, ch, 0, 0, TO_ROOM);
+           send_to_char("You aim and fire!\r\n", ch);
+           attacktype = SKILL_SLING;
+           break;
+         case ITEM_BOLT:
+           act("$n aims and fires!", TRUE, ch, 0, 0, TO_ROOM);
+           send_to_char("You aim and fire!\r\n", ch);
+           attacktype = SKILL_CROSSBOW;
+           break;
+         default:
+           attacktype = TYPE_UNDEFINED;
+         break;
+       }
+ 
+       if (attacktype != TYPE_UNDEFINED)
+         shot = skill_roll(ch, attacktype);
+       else
+         shot = FALSE;
+ 
+       if (shot == TRUE) {
+         strike_missile(ch, vict, missile, dir, attacktype);
+         if ((number(0, 1)) || (attacktype == SKILL_THROW))
+           obj_to_char(unequip_char(ch, pos), vict);
+         else
+           extract_obj(unequip_char(ch, pos));
+       } else {
+       /* ok missed so move missile into new room */
+         miss_missile(ch, vict, missile, dir, attacktype);
+         if ((!number(0, 2)) || (attacktype == SKILL_THROW))
+           obj_to_room(unequip_char(ch, pos), vict->in_room);
+         else
+           extract_obj(unequip_char(ch, pos));
+       }
+ 
+       /* either way mob remembers */
+       mob_reaction(ch, vict, dir);
+       WAIT_STATE(ch, PULSE_VIOLENCE);
+       return; 
+ 
+     } 
+ 
+     room = nextroom;
+     if CAN_GO2(room, dir)
+       nextroom = EXIT2(room, dir)->to_room;
+     else
+       nextroom = NOWHERE;
+   }
+ 
+   send_to_char("Can't find your target!\r\n", ch);
+   return;
+ 
+ }
+ 
+ 
+ void tick_grenade(void)
+ {
+   struct obj_data *i, *tobj;
+   struct char_data *tch, *next_tch;
+   int s, t, dam, door;
+   /* grenades are activated by pulling the pin - ie, setting the
+      one of the extra flag bits. After the pin is pulled the grenade
+      starts counting down. once it reaches zero, it explodes. */
+ 
+   for (i = object_list; i; i = i->next) { 
+ 
+     if (IS_SET(GET_OBJ_EXTRA(i), ITEM_LIVE_GRENADE)) {
+       /* update ticks */
+       if (i->obj_flags.value[0] >0)
+         i->obj_flags.value[0] -=1;
+       else { 
+         t = 0;
+ 
+         /* blow it up */
+         /* checks to see if inside containers */
+         /* to avoid possible infinite loop add a counter variable */
+         s = 0; /* we'll jump out after 5 containers deep and just delete
+                        the grenade */
+ 
+         for (tobj = i; tobj; tobj = tobj->in_obj) {
+           s++;
+           if (tobj->in_room != NOWHERE) { 
+             t = tobj->in_room;
+             break;
+           } else
+             if ((tch = tobj->carried_by)) { 
+               t = tch->in_room;
+               break;
+             } else 
+               if ((tch = tobj->worn_by)) { 
+                 t = tch->in_room;
+                 break;
+               }
+           if (s == 5)
+             break;
+         }
+ 
+         /* then truly this grenade is nowhere?!? */
+         if (t <= 0) {
+           sprintf(buf, "serious problem, grenade truly in nowhere\r\n");
+           log(buf);
+           extract_obj(i);
+         } else { /* ok we have a room to blow up */
+ 
+         /* peaceful rooms */
+           if (ROOM_FLAGGED(t, ROOM_PEACEFUL)) {
+             sprintf(buf, "You hear %s explode harmlessly, with a loud POP!\n\r", 
+               i->short_description);
+             send_to_room(buf, t);
+             extract_obj(i);
+             return;
+           }
+ 
+           dam = dice(i->obj_flags.value[1], i->obj_flags.value[2]);
+ 
+           sprintf(buf, "Oh no - %s explodes!  KABOOOOOOOOOM!!!\r\n", 
+             i->short_description);
+           send_to_room(buf, t);
+ 
+           for (door = 0; door < NUM_OF_DIRS; door++)
+             if (CAN_GO2(t, door)) 
+               send_to_room("You hear a loud explosion!\r\n", 
+               world[t].dir_option[door]->to_room);
+ 
+           for (tch = world[t].people; tch; tch = next_tch) {
+             next_tch= tch->next_in_room;
+ 
+             if (GET_POS(tch) <= POS_DEAD) {
+               log("SYSERR: Attempt to damage a corpse.");
+               return;			/* -je, 7/7/92 */
+             }
+ 
+             /* You can't damage an immortal! */
+             if (IS_NPC(tch) || (GET_LEVEL(tch) < LVL_IMMORT)) {
+ 
+               GET_HIT(tch) -= dam;
+               act("$n is blasted!", TRUE, tch, 0, 0, TO_ROOM);
+               act("You are caught in the blast!", TRUE, tch, 0, 0, TO_CHAR);
+               update_pos(tch);
+ 
+               if (GET_POS(tch) <= POS_DEAD) { 
+                 make_corpse(tch);
+                 death_cry(tch);
+                 extract_char(tch);
+               }
+             }
+ 
+           }
+                /* ok hit all the people now get rid of the grenade and 
+                   any container it might have been in */
+ 
+           extract_obj(i);
+ 
+         }
+       } /* end else stmt that took care of explosions */    
+     } /* end if stmt that took care of live grenades */
+   } /* end loop that searches the mud for objects. */
+ 
+   return;
+ 
+ }
+ 
\ No newline at end of file
diff -u -F regexp -N src/stkoas/interpreter.c src/interpreter.c
--- src/stkoas/interpreter.c	Mon May 04 18:43:06 1998
+++ src/interpreter.c	Mon May 04 01:06:46 1998
@@ -144,6 +144,7 @@
 ACMD(do_send);
 ACMD(do_set);
 ACMD(do_show);
+ACMD(do_shoot);
 ACMD(do_shutdown);
 ACMD(do_sit);
 ACMD(do_skillset);
@@ -158,6 +159,8 @@
 ACMD(do_switch);
 ACMD(do_syslog);
 ACMD(do_teleport);
+ACMD(do_throw);
+ACMD(do_pull);
 ACMD(do_tell);
 ACMD(do_time);
 ACMD(do_title);
@@ -399,6 +402,7 @@
   { "practice" , POS_RESTING , do_practice , 1, 0 },
   { "pray"     , POS_SITTING , do_action   , 0, 0 },
   { "puke"     , POS_RESTING , do_action   , 0, 0 },
+  { "pull"     , POS_STANDING, do_pull     , 0, 0 },
   { "punch"    , POS_RESTING , do_action   , 0, 0 },
   { "purr"     , POS_RESTING , do_action   , 0, 0 },
   { "purge"    , POS_DEAD    , do_purge    , LVL_GOD, 0 },
@@ -441,6 +445,7 @@
   { "shake"    , POS_RESTING , do_action   , 0, 0 },
   { "shiver"   , POS_RESTING , do_action   , 0, 0 },
   { "show"     , POS_DEAD    , do_show     , LVL_IMMORT, 0 },
+  { "shoot"    , POS_STANDING, do_shoot    , 0, 0},
   { "shrug"    , POS_RESTING , do_action   , 0, 0 },
   { "shutdow"  , POS_DEAD    , do_shutdown , LVL_IMPL, 0 },
   { "shutdown" , POS_DEAD    , do_shutdown , LVL_IMPL, SCMD_SHUTDOWN },
@@ -490,6 +495,7 @@
   { "thank"    , POS_RESTING , do_action   , 0, 0 },
   { "think"    , POS_RESTING , do_action   , 0, 0 },
   { "thaw"     , POS_DEAD    , do_wizutil  , LVL_FREEZE, SCMD_THAW },
+  { "throw"     , POS_STANDING, do_throw , 0 , 0 },
   { "title"    , POS_DEAD    , do_title    , 0, 0 },
   { "tickle"   , POS_RESTING , do_action   , 0, 0 },
   { "time"     , POS_DEAD    , do_time     , 0, 0 },
Common subdirectories: src/stkoas/oasis and src/oasis
diff -u -F regexp -N src/stkoas/oedit.c src/oedit.c
--- src/stkoas/oedit.c	Mon May 04 18:43:06 1998
+++ src/oedit.c	Mon May 04 01:23:54 1998
@@ -596,6 +596,17 @@
      */
     oedit_disp_val3_menu(d);
     break;
+		case ITEM_BOW:
+    case ITEM_CROSSBOW:
+    case ITEM_SLING:
+      send_to_char("Range (1 - 3) = ", d->character);
+      break;
+    case ITEM_ROCK:
+    case ITEM_BOLT:
+    case ITEM_ARROW:
+    case ITEM_THROW:
+      oedit_disp_val2_menu(d);
+      break;
   case ITEM_SCROLL:
   case ITEM_WAND:
   case ITEM_STAFF:
@@ -629,6 +640,9 @@
      * This is supposed to be language, but it's unused.
      */
     break;
+	case ITEM_GRENADE:
+		send_to_char("Ticks to countdown to explosion : ", d->character);
+		break;
   default:
     oedit_disp_menu(d);
   }
@@ -649,6 +663,11 @@
   case ITEM_STAFF:
     send_to_char("Max number of charges : ", d->character);
     break;
+  case ITEM_ROCK:
+  case ITEM_BOLT:
+  case ITEM_ARROW:
+  case ITEM_THROW:
+	case ITEM_GRENADE:
   case ITEM_WEAPON:
     send_to_char("Number of damage dice : ", d->character);
     break;
@@ -691,6 +710,11 @@
   case ITEM_STAFF:
     send_to_char("Number of charges remaining : ", d->character);
     break;
+	case ITEM_ROCK:
+	case ITEM_BOLT:
+	case ITEM_ARROW:
+	case ITEM_THROW:
+	case ITEM_GRENADE:
   case ITEM_WEAPON:
     send_to_char("Size of damage dice : ", d->character);
     break;
@@ -930,7 +954,10 @@
       OLC_MODE(d) = OEDIT_LONGDESC;
       break;
     case '4':
+			/* let's go out to modify.c */
+			send_to_char("Enter action desc :-\r\n", d->character);
       OLC_MODE(d) = OEDIT_ACTDESC;
+      /*
       SEND_TO_Q("Enter action description: (/s saves /h for help)\r\n\r\n", d);
       d->backstr = NULL;
       if (OLC_OBJ(d)->action_description) {
@@ -939,6 +966,12 @@
       }
       d->str = &OLC_OBJ(d)->action_description;
       d->max_str = MAX_MESSAGE_LENGTH;
+      */
+			d->str = (char **) malloc(sizeof(char *));
+			
+			*(d->str) = NULL;
+			d->max_str = MAX_OBJ_DESC;
+			
       d->mail_to = 0;
       OLC_VAL(d) = 1;
       break;
@@ -1251,6 +1284,7 @@
 
     case 2:
       OLC_MODE(d) = OEDIT_EXTRADESC_DESCRIPTION;
+      /*
       SEND_TO_Q("Enter the extra description: (/s saves /h for help)\r\n\r\n", d);
       d->backstr = NULL;
       if (OLC_DESC(d)->description) {
@@ -1259,6 +1293,14 @@
       }
       d->str = &OLC_DESC(d)->description;
       d->max_str = MAX_MESSAGE_LENGTH;
+      */
+			send_to_char("Enter description :-\r\n", d->character);
+			/* send out to modify.c */
+			d->str = (char **) malloc(sizeof(char *));
+
+			*(d->str) = NULL;
+			d->max_str = MAX_OBJ_DESC;
+			
       d->mail_to = 0;
       OLC_VAL(d) = 1;
       return;
diff -u -F regexp -N src/stkoas/olc.h src/olc.h
--- src/stkoas/olc.h	Mon May 04 18:43:08 1998
+++ src/olc.h	Mon May 04 01:28:18 1998
@@ -37,7 +37,7 @@
 #define NUM_AFF_FLAGS		22
 #define NUM_ATTACK_TYPES	15
 
-#define NUM_ITEM_TYPES		24
+#define NUM_ITEM_TYPES		31
 #define NUM_ITEM_FLAGS		17
 #define NUM_ITEM_WEARS 		15
 #define NUM_APPLIES		25
Common subdirectories: src/stkoas/range and src/range
diff -u -F regexp -N src/stkoas/spell_parser.c src/spell_parser.c
--- src/stkoas/spell_parser.c	Wed Oct 29 00:16:30 1997
+++ src/spell_parser.c	Mon May 04 01:32:26 1998
@@ -127,7 +127,11 @@
   "sneak",
   "steal",
   "track",			/* 140 */
-  "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!",	/* 145 */
+	"throw", 
+	"disarm", 
+	"bow", 
+	"sling", 
+	"crossbow",		/* 145 */	
   "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!",	/* 150 */
   "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!",	/* 155 */
   "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!", "!UNUSED!",	/* 160 */
@@ -1022,5 +1026,9 @@
   skillo(SKILL_SNEAK);
   skillo(SKILL_STEAL);
   skillo(SKILL_TRACK);
+	skillo(SKILL_BOW);
+	skillo(SKILL_SLING);
+	skillo(SKILL_CROSSBOW);
+	skillo(SKILL_THROW);
 }
 
diff -u -F regexp -N src/stkoas/spells.h src/spells.h
--- src/stkoas/spells.h	Sat Apr 13 19:56:08 1996
+++ src/spells.h	Mon May 04 01:35:06 1998
@@ -103,6 +103,10 @@
 #define SKILL_TRACK		    140 /* Reserved Skill[] DO NOT CHANGE */
 /* New skills may be added here up to MAX_SKILLS (200) */
 
+#define SKILL_THROW             141 /* new */
+#define SKILL_BOW               142
+#define SKILL_SLING             143
+#define SKILL_CROSSBOW          144
 
 /*
  *  NON-PLAYER AND OBJECT SPELLS AND SKILLS
Common subdirectories: src/stkoas/stk and src/stk
Common subdirectories: src/stkoas/stkoas and src/stkoas
diff -u -F regexp -N src/stkoas/structs.h src/structs.h
--- src/stkoas/structs.h	Mon May 04 18:43:08 1998
+++ src/structs.h	Mon May 04 01:39:22 1998
@@ -283,6 +283,14 @@
 #define ITEM_PEN       21		/* Item is a pen		*/
 #define ITEM_BOAT      22		/* Item is a boat		*/
 #define ITEM_FOUNTAIN  23		/* Item is a fountain		*/
+#define ITEM_THROW     24               /* Item can be thrown as weapon */
+#define ITEM_GRENADE   25               /* Item is a grenade      */
+#define ITEM_BOW       26               /* shoots arrows */
+#define ITEM_SLING     27               /* shoots rocks */
+#define ITEM_CROSSBOW  28               /* shoots bolts */
+#define ITEM_BOLT      29
+#define ITEM_ARROW     30
+#define ITEM_ROCK      31
 
 
 /* Take/Wear flags: used by obj_data.obj_flags.wear_flags */
@@ -321,6 +329,7 @@
 #define ITEM_ANTI_THIEF	   (1 << 14)	/* Not usable by thieves	*/
 #define ITEM_ANTI_WARRIOR  (1 << 15)	/* Not usable by warriors	*/
 #define ITEM_NOSELL	   (1 << 16)	/* Shopkeepers won't touch it	*/
+#define ITEM_LIVE_GRENADE  (1 << 17)    /* grenade's pin has been pulled */
 
 
 /* Modifier constants used with obj affects ('A' fields) */
Common subdirectories: src/stkoas/util and src/util
diff -u -F regexp -N src/stkoas/utils.h src/utils.h
--- src/stkoas/utils.h	Mon May 04 18:43:08 1998
+++ src/utils.h	Mon May 04 01:46:04 1998
@@ -89,6 +89,7 @@
 /* get_filename() */
 #define CRASH_FILE	0
 #define ETEXT_FILE	1
+#define ALIAS_FILE      2
 
 /* breadth-first searching */
 #define BFS_ERROR		-1
@@ -403,6 +404,11 @@
 
 #define EXIT(ch, door)  (world[(ch)->in_room].dir_option[door])
 
+#define EXIT2(roomnum, door) (world[(roomnum)].dir_option[door])
+#define CAN_GO2(roomnum, door) (EXIT2(roomnum, door) && \
+                       (EXIT2(roomnum, door)->to_room != NOWHERE) && \
+                       !IS_SET(EXIT2(roomnum,door)->exit_info, EX_CLOSED))
+  
 #define CAN_GO(ch, door) (EXIT(ch,door) && \
 			 (EXIT(ch,door)->to_room != NOWHERE) && \
 			 !IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
