/*
  SillyMUD Distribution V1.1b             (c) 1993 SillyMUD Developement
 
  See license.doc for distribution terms.   SillyMUD is based on DIKUMUD
*/

#include <stdio.h>
#include <string.h>

#include "protos.h"

extern struct char_data *character_list;
extern struct index_data *mob_index;
#if HASH
extern struct hash_header room_db;
#else
extern struct room_data *room_db;
#endif
extern struct str_app_type str_app[];
extern struct index_data *mob_index;

int top_of_comp = 0;

void mobile_guardian(struct char_data *ch)
{
  struct char_data *targ;
  int i, found=FALSE;
  
  if (ch->in_room > -1) {
    if ((!ch->master) || (!IS_AFFECTED(ch, AFF_CHARM)))
      return;
    if (ch->master->specials.fighting) { /**/
      for(i=0;i<10&&!found;i++) {
	targ = FindAnAttacker(ch->master);
	if (targ)
	  found=TRUE;
      }
      
      if (!found) return;
      
      if (!SameRace(targ, ch)) {
	if (IsHumanoid(ch)) {
	  act("$n screams 'I must protect my master!'", 
	      FALSE, ch, 0, 0, TO_ROOM);
	} else {
	  act("$n growls angrily!", 
	      FALSE, ch, 0, 0, TO_ROOM);
	}
	if (CAN_SEE(ch, targ))
	  hit(ch, targ,0);	  
      }
    }
  }
}

void mobile_wander(struct char_data *ch)
{
  int	door, or;
  struct room_direction_data	*exitp;
  struct room_data	*rp;
  char buf[100];

  if (GET_POS(ch) != POSITION_STANDING)
    return;

  or = ch->in_room;

  while(1) {

    door = number(0,8);
    if (door > 5) return;

    if (door = ch->specials.last_direction)
      continue;

    exitp = EXIT(ch, door);

    if (!exit_ok(exitp, &rp)) continue;

    if (IS_SET(rp->room_flags, NO_MOB|DEATH))
      continue;

    if (GET_RACE(ch) == RACE_FISH) {
      rp = real_roomp(EXIT(ch, door)->to_room);

      if (rp->sector_type == SECT_UNDERWATER ||
	  rp->sector_type == SECT_WATER_NOSWIM ||
	  rp->sector_type == SECT_WATER_SWIM) {
	/* then it is ok for the fish to wander there */
      } else {
	return;
      }
    }

    if (IsHumanoid(ch) ? CAN_GO_HUMAN(ch, door) : CAN_GO(ch, door)) {
      if (!IS_SET(ch->specials.act, ACT_STAY_ZONE) ||
	  (rp->zone == real_roomp(ch->in_room)->zone)) {
	ch->specials.last_direction = door;
	go_direction(ch, door);
	if (ch->in_room == 0) {
	  if (or != 0) {
	    sprintf(buf, "%s just entered void from %d", GET_NAME(ch), or);
	    log_sev(buf,5);
	  }
	}
	return;
      }
    }
  }
}

void MobHunt(struct char_data *ch)
{
  int res, k;
  
#if NOTRACK     
  return;    /* too much CPU useage for some machines.  */
#endif
  
  if (ch->persist <= 0) {
    res = choose_exit_in_zone(ch->in_room, ch->old_room, 2000);
    if (res > -1) {
      go_direction(ch, res);
    } else {
      if (ch->specials.hunting) {
	if (ch->specials.hunting->in_room == ch->in_room) {
	  if (Hates(ch, ch->specials.hunting) && 
	      (!IS_AFFECTED(ch->specials.hunting, AFF_HIDE))) {
	    if (check_peaceful(ch, "You'd love to tear your quarry to bits, but you just CAN'T\n\r")) {
	      act("$n fumes at $N", TRUE, ch, 0,
		  ch->specials.hunting, TO_ROOM); 
	    } else {
	      if (IsHumanoid(ch)) {
		act("$n screams 'Time to die, $N'", 
		    TRUE, ch, 0, ch->specials.hunting, TO_ROOM); 
	      } else if (IsAnimal(ch)) {
		act("$n growls.", TRUE, ch, 0, 0, TO_ROOM);
	      }
	      MobHit(ch,ch->specials.hunting,0);
	      return;
	    }
	  }
	}
      }
      REMOVE_BIT(ch->specials.act, ACT_HUNTING);
      ch->specials.hunting = 0;
      ch->hunt_dist = 0;
    }
  } else if (ch->specials.hunting) {
    if (ch->hunt_dist <= 50) 
      ch->hunt_dist = 100;
    for (k=1;k<=1 && ch->specials.hunting; k++) {
      ch->persist -= 1;
      res = dir_track(ch, ch->specials.hunting);
      if (res!= -1) {
	go_direction(ch, res);
      } else {
	ch->persist = 0;
	ch->specials.hunting = 0;
	ch->hunt_dist = 0;
      }
    }
  } else {
    ch->persist = 0;
  }	       
}

void MobScavenge(struct char_data *ch)
{
  struct obj_data *best_obj=0, *obj=0;
  int max, cc=0;
  char buf[512];
  
  if ((real_roomp(ch->in_room))->contents && number(0,4)) {
    for (max = 1,best_obj = 0,obj = (real_roomp(ch->in_room))->contents;
	 obj; obj = obj->next_content) {
      if (IS_CORPSE(obj)) {
	cc++;
	if (obj->contains) {
	  if (IsHumanoid(ch) && !number(0,4)) {
	    sprintf(buf, " all %d.corpse", cc);
	    do_get(ch, buf, 0);
	    return;
	  }
	}
      }
      if (CAN_GET_OBJ(ch, obj)) {
	if (obj->obj_flags.cost > max) {
	  best_obj = obj;
	  max = obj->obj_flags.cost;
	}
      }
    } /* for */
    
    if (best_obj) {
      if (!CheckForAnyTrap(ch, best_obj)) {
	obj_from_room(best_obj);
	obj_to_char(best_obj, ch);
	act("$n gets $p.",FALSE,ch,best_obj,0,TO_ROOM);
      }
    }
  } else {
    if (IsHumanoid(ch) && real_roomp(ch->in_room)->contents) {
      if (!number(0,4)) 
	do_get(ch, "all", 0);
    }
  }

#if 0
  if (number(0,3)) {
    for( obj=ch->carrying;obj;obj=obj->next) {
      if (IS_OBJ_STAT(obj, ITEM_NODROP)) {
	do_junk(ch, obj->name, 0);
      }
    }
  }
#endif

  if (!number(0,3)) {
    if (IsHumanoid(ch) && ch->carrying) {
      sprintf(buf, "all");
      do_wear(ch, buf, 0);
    }
  }
}


void check_mobile_activity(int pulse)
{
  register struct char_data *ch; 
  int tick, tm;
  
  tm = pulse % PULSE_MOBILE;    /* this is dependent on P_M = 3*P_T */
  
  if (tm == 0) {
    tick = 0;
  } else if (tm == PULSE_TELEPORT) {
    tick = 1;
  } else if (tm == PULSE_TELEPORT*2) {
    tick = 2;
  }
  
  for (ch = character_list; ch; ch = ch->next) {
    if (IS_MOB(ch)) {
      if (ch->specials.tick == tick) {
	mobile_activity(ch);
      }
    }
  }
}

void mobile_activity(struct char_data *ch)
{
  struct char_data *tmp_ch;

  int k;
  char buf[80];
  extern int no_specials;
  
  void do_move(struct char_data *ch, char *argument, int cmd);
  void do_get(struct char_data *ch, char *argument, int cmd);
  
  /* Examine call for special procedure */
  
  /* some status checking for errors */
#if HASH
  if ((ch->in_room < 0) || !hash_find(&room_db,ch->in_room)) {
#else
  if ((ch->in_room < 0) || !room_find(&room_db,ch->in_room)) {
#endif
      log("Char not in correct room.  moving to 50 ");
      log(GET_NAME(ch));
      assert(ch->in_room >= 0);  /* if they are in a - room, assume an error */
      char_from_room(ch);
      char_to_room(ch, 50);
  }

  /* Execute a script if there is one */

  if(IS_SET(ch->specials.act, ACT_SCRIPT) && !IS_PC(ch))
    DoScript(ch);

    
  if (((IS_SET(ch->specials.act, ACT_SPEC) || mob_index[ch->nr].func)) && !no_specials) {
    if (!mob_index[ch->nr].func) {
      char buf[180];
      sprintf(buf, "Attempting to call a non-existing mob func on %s", GET_NAME(ch));
      log(buf);
      REMOVE_BIT(ch->specials.act, ACT_SPEC);
    } else {

      if ((*mob_index[ch->nr].func)	(ch, 0, "", ch, PULSE_TICK))
	return;
    }
  }
  
  
  /* check to see if the monster is possessed */
  
  if (AWAKE(ch) && (!ch->specials.fighting) && (!ch->desc) &&
      (!IS_SET(ch->specials.act, ACT_POLYSELF))) {
    
    if (!AssistFriend(ch)) {
      return;
    }
    
    if (IS_SET(ch->specials.act, ACT_SCAVENGER)) {
      MobScavenge(ch);
    } /* Scavenger */
    
    
    if (IS_SET(ch->specials.act, ACT_HUNTING)) {
      MobHunt(ch);
    } else if ((!IS_SET(ch->specials.act, ACT_SENTINEL)))
      mobile_wander(ch);
    
    if (GET_HIT(ch) > (GET_MAX_HIT(ch)/2)) {
      if (IS_SET(ch->specials.act, ACT_HATEFUL)) {
	tmp_ch = FindAHatee(ch);
	if (tmp_ch) {
	  if (check_peaceful(ch, "You ask your mortal enemy to step outside to settle matters.\n\r")) {
	    act("$n growls '$N, would you care to step outside where we can settle this?'", TRUE, ch, 0, tmp_ch, TO_ROOM);
	  } else {
	    if (IsHumanoid(ch)) {
	      act("$n screams 'I'm gonna kill you!'", 
		  TRUE, ch, 0, 0, TO_ROOM); 
	    } else if (IsAnimal(ch)) {
	      act("$n growls", TRUE, ch, 0, 0, TO_ROOM);
	    }
	    MobHit(ch,tmp_ch,0);
	  }
	  if (Hates(ch, tmp_ch) && Fears(ch, tmp_ch)) {
	    RemHated(ch, tmp_ch);
	    RemFeared(ch, tmp_ch);
	  }
	}
      }
      if (!ch->specials.fighting) {
	if (IS_SET(ch->specials.act, ACT_AFRAID)) {
	  if ((tmp_ch = FindAFearee(ch))!= NULL) {
	    do_flee(ch, "", 0);
	  }
	}
      }
    } else {
      if (IS_SET(ch->specials.act, ACT_AFRAID)) {
	if ((tmp_ch = FindAFearee(ch))!= NULL) {
	  do_flee(ch, "", 0);
	} else {
	  if (IS_SET(ch->specials.act, ACT_HATEFUL)) {
	    tmp_ch = FindAHatee(ch);
	    if (tmp_ch) {
	      if (check_peaceful(ch, "You ask your mortal enemy to step outside to settle matters.\n\r")) {
		act("$n growls '$N, would you care to step outside where we can settle this?'", TRUE, ch, 0, tmp_ch, TO_ROOM);
	      } else {
		if (IsHumanoid(ch)) {
		  act("$n screams 'I'm gonna get you!'", 
		      TRUE, ch, 0, 0, TO_ROOM); 
		} else if (IsAnimal(ch)) {
		  act("$n growls", TRUE, ch, 0, 0, TO_ROOM);
		}
		hit(ch,tmp_ch,0);
	      }
	      if (Hates(ch, tmp_ch) && Fears(ch, tmp_ch)) {
		RemHated(ch, tmp_ch);
		RemFeared(ch, tmp_ch);
	      }
	    }
	  }	 		
	}
      }
    }

    if (IS_SET(ch->specials.act,ACT_AGGRESSIVE)) {
      for (k=0;k<=5;k++) {
	tmp_ch = FindVictim(ch);
	if (tmp_ch) {
	  if (check_peaceful(ch, "You can't seem to exercise your violent tendencies.\n\r")) {
	    act("$n growls impotently", TRUE, ch, 0, 0, TO_ROOM);
	    return;
	  }
	  MobHit(ch, tmp_ch, 0);
	  k = 10;
	}
      }
    }
    if (IS_SET(ch->specials.act, ACT_META_AGG)) {
      for (k=0;k<=5;k++) {
	tmp_ch = FindMetaVictim(ch);
	if (tmp_ch) {
	  if (check_peaceful(ch, "You can't seem to exercise your violent tendencies.\n\r")) {
	    act("$n growls impotently", TRUE, ch, 0, 0, TO_ROOM);
	    return;
	  }
	  MobHit(ch, tmp_ch, 0);
	  k = 10;
	}
      }
      
    }
    if (IS_SET(ch->specials.act, ACT_GUARDIAN)) {
      mobile_guardian(ch);
    }    

  } /* If AWAKE(ch)   */
  if (!IS_PC(ch) && ch->specials.fighting) {
    if (IS_AFFECTED(ch->specials.fighting, AFF_FIRESHIELD)) {
      struct char_data *vict;
      vict = FindVictim(ch);
      /* switch to a new target */
      if (vict && vict != ch->specials.fighting) {
	stop_fighting(ch);
	set_fighting(ch, vict);
      }
    }
  }
}
  
  
  
int SameRace( struct char_data *ch1, struct char_data *ch2)
{    
    if ((!ch1) || (!ch2))
      return(FALSE);
    
    if (ch1 == ch2)
      return(TRUE);
    
    if (in_group(ch1,ch2))
      return(TRUE);
    
    if (GET_RACE(ch1) == GET_RACE(ch2)) {
      return(TRUE);
    }
    
    return(FALSE);
}
  
int AssistFriend( struct char_data *ch)
{
  struct char_data *damsel, *targ, *tmp_ch, *next;
  int t, found;
  char buf[256];
  
  damsel = 0;
  targ = 0;
  
  if (check_peaceful(ch, ""))
    return;
#if 0
  assert(ch->in_room >= 0); 
#else
  if (ch->in_room < 0) {
    sprintf(buf, "Mob %sin negative room", ch->player.name);
    log(buf);
    ch->in_room = 0;
    extract_char(ch);
    return(0);
  }
#endif
  if (ch->in_room == 0) 
    return(0);
  
  /*
    find the people who are fighting
    */
  
  for (tmp_ch=(real_roomp(ch->in_room))->people;tmp_ch;
       tmp_ch=next) {
    next = tmp_ch->next_in_room;
    if (CAN_SEE(ch,tmp_ch)) {
      if (!IS_SET(ch->specials.act, ACT_WIMPY)) {
	if (MobFriend(ch, tmp_ch)) {
	  if (tmp_ch->specials.fighting)
	    damsel = tmp_ch;
	}
      }
    }
  }
  
  if (damsel) {
    /*
      check if the people in the room are fighting.
      */
    found = FALSE;
    for (t=1; t<=8 && !found;t++) {
      targ = FindAnAttacker(damsel);
      if (targ) {
	if (targ->specials.fighting)
	    found = TRUE;
      }
    }
    if (targ) {
      if (targ->in_room == ch->in_room) {
	if (!IS_AFFECTED(ch, AFF_CHARM) ||
	    ch->master != targ) {
	  hit(ch,targ,0);
	}
      }
    }
  }
  return(1);
}
  
FindABetterWeapon(struct char_data *mob)
{
  struct obj_data *o, *best;
  /*
    pick up and wield weapons
    Similar code for armor, etc.
    */
  
  /* check whether this mob can wield */
  if (!HasHands(mob)) return(FALSE);
  
  if (!real_roomp(mob->in_room)) return(FALSE);
  
  /* check room */
  best = 0;
  for (o = real_roomp(mob->in_room)->contents; o; o = o->next_content) {
    if (best && IS_WEAPON(o)) {
      if (GetDamage(o,mob) > GetDamage(best,mob)) {
	best = o;
      }
    } else {
      if (IS_WEAPON(o)) {
	best = o;
      }
    }
  }
  /* check inv */
  for (o = mob->carrying; o; o=o->next_content) {
    if (best && IS_WEAPON(o)) {
      if (GetDamage(o,mob) > GetDamage(best,mob)) {
	best = o;
      }
    } else {
      if (IS_WEAPON(o)) {
	best = o;
      }
    }
  }
  
  if (mob->equipment[WIELD]) {
    if (best) {
       if (GetDamage(mob->equipment[WIELD],mob) >= GetDamage(best,mob)) {
          best = mob->equipment[WIELD];
       }
    } else {
      best = mob->equipment[WIELD];
    }
  }

  if (best) {
     if (GetHandDamage(mob) > GetDamage(best, mob)) {
        best = 0;
     }
  } else {
    return(FALSE);  /* nothing to choose from */
  }

  if (best) {
      /*
	out with the old, in with the new
      */
      if (best->carried_by == mob) {
	 if (mob->equipment[WIELD]) {
            do_remove(mob, mob->equipment[WIELD]->name, 0);
	 }
         do_wield(mob, best->name, 0);
      } else if (best->equipped_by == mob) {
	/* do nothing */
	return(TRUE);
      } else {
         do_get(mob, best->name, 0);
      }      
  } else {
    if (mob->equipment[WIELD]) {
      do_remove(mob, mob->equipment[WIELD]->name, 0);
    }
  }
}
      
int GetDamage(struct obj_data *w, struct char_data *ch) 
{
  float ave;
  int iave;
  /*
    return the average damage of the weapon, with plusses.
  */

  ave = w->obj_flags.value[2]/2.0 + 0.5;
    
  ave *=w->obj_flags.value[1];
  
  ave += GetDamBonus(w);
  /*
    check for immunity:
    */
  iave = ave;
  if (ch->specials.fighting) {
    iave = PreProcDam(ch->specials.fighting, ITEM_TYPE(w), iave);
    iave = WeaponCheck(ch, ch->specials.fighting, ITEM_TYPE(w), iave);
  }
  return(iave);
}
      
int GetDamBonus(struct obj_data *w)
{
   int j, tot=0;

    /* return the damage bonus from a weapon */
   for(j=0; j<MAX_OBJ_AFFECT; j++) {
      if (w->affected[j].location == APPLY_DAMROLL || 
	  w->affected[j].location == APPLY_HITNDAM) {
	  tot += w->affected[j].modifier;	
	}
    }
    return(tot);
}
	      
int GetHandDamage(struct char_data *ch) 
{
  float ave;
  int num, size, iave;
  /*
    return the hand damage of the weapon, with plusses.
	dam += dice(ch->specials.damnodice, ch->specials.damsizedice);

    */

  num  = ch->specials.damnodice;
  size = ch->specials.damsizedice;
  
  ave = size/2.0 + 0.5;
    
  ave *= num;  

  /*
    check for immunity:
    */
  iave = ave;
  if (ch->specials.fighting) {
    iave = PreProcDam(ch->specials.fighting, TYPE_HIT, iave);
    iave = WeaponCheck(ch, ch->specials.fighting, TYPE_HIT, iave);
  }
  return(iave);
}

/*
  check to see if a mob is a friend

*/


int MobFriend( struct char_data *ch, struct char_data *f)
{

   if (SameRace(ch, f)) {
     if (IS_GOOD(ch)) {
       if (IS_GOOD(f)) {
          return(TRUE);
	} else {
	  return(FALSE);
	}
     } else {
       if (IS_NPC(f))
          return(TRUE);
     }
   } else {
     return(FALSE);
   }

}

void PulseMobiles(int type)
{
 register struct char_data *ch;

 for(ch = character_list; ch; ch = ch->next)
    if(IS_MOB(ch))
      if(mob_index[ch->nr].func)
        (*mob_index[ch->nr].func)(ch, 0, "", ch, type);
} 
 
void DoScript(struct char_data *ch)
{
 int i, check = 0;
 char buf[255], buf2[255], buf3[255], *s;

 strcpy(buf, script_data[ch->script].script[ch->commandp].line);

 if(buf[strlen(buf) - 1] == '\\') {
    check = 1;
    buf[strlen(buf) - 1] = '\0';
 }

 strcpy(buf2, buf);
 strtok(buf2, " ");
 s = strtok(NULL, " ");
 

 i = CommandSearch(buf2);

 if(i == -1) {
    command_interpreter(ch, buf);
    ch->commandp++;
    return;
  }
 if(s)
   (*comp[i].p)(s, ch);
 else
   (*comp[i].p)("\0", ch);

 if(*script_data[ch->script].script[ch->commandp].line == '_')
   ch->commandp++;

 if(check)
    DoScript(ch);
}

int CommandSearch(char *arg)
{
 int i;

 for(i = 0; i < top_of_comp; i++)
    if(!strcmp(comp[i].arg, arg))
       return(i);

 return(-1);
}

void CommandAssign(char *arg, void (*p))
{
 if(top_of_comp == 0)
    comp = (struct script_com *)malloc(sizeof(struct script_com));
 else
    comp = (struct script_com *) realloc(comp, sizeof(struct script_com) * (top_of_comp + 1));
 comp[top_of_comp].p = p;
 comp[top_of_comp].arg = (char *) malloc(sizeof(char) * (strlen(arg) + 1));
 strcpy(comp[top_of_comp].arg, arg);
 top_of_comp++;
}

void CommandSetup()
{
 CommandAssign("noop", noop);
 CommandAssign("goto", sgoto);
 CommandAssign("end", end2);
 CommandAssign("act", do_act);
 CommandAssign("jsr", do_jsr);
 CommandAssign("jmp", do_jmp);
 CommandAssign("rts", do_rts);
 CommandAssign("stop", end2);
}

void noop(char *arg, struct char_data *ch)
{
 int i;

 if(ch->waitp > 0) {
    if(ch->waitp == 1) {
       ch->waitp = 0;
       ch->commandp++;
       return;
     }

    ch->waitp--;
    return;
  }

 if(*arg) {
   i = atoi(arg);

   if(i <= 0) {
     ch->commandp++;
     return;
   }

   ch->waitp = i - 1;
   return;
 }
 ch->commandp++;
 return; 
}

void end2(char *arg, struct char_data *ch)
{
 ch->commandp = 0;
}  

void sgoto(char *arg, struct char_data *ch)
{
   char *p, buf[255];
   struct char_data *mob;
   int dir, room;

   if(arg) {
     if (*arg == '$') {  /* this is a creature name to follow */
       arg++;
       p = strtok(arg, " ");
       if ((mob = get_char_vis(ch, p)) == NULL) {
	 fprintf(stderr, "%s couldn't find mob by name %s\n", 
		 script_data[ch->script].filename, p);
	 ch->commandp++;
	 return;
       } else {
	 room = mob->in_room;
       }
     }else {
       room = atoi(arg);
     }
   } else {
     char buf3[150];
     sprintf(buf, "Error in script %s, no destination for goto", 
	     script_data[ch->script].filename);
     log(buf);
     ch->commandp++;
     return;
   }
   if (ch->in_room != room) {
     dir = choose_exit_global(ch->in_room, room, MAX_ROOMS);
     if (dir < 0) {
       do_say(ch, "Woah!  How'd i get here??", 0);
       do_emote(ch, "vanishes in a puff of smoke", 0);
       char_from_room(ch);
       char_to_room(ch, room);
       do_emote(ch, "arrives with a Bamf!", 0);
       ch->commandp++;
       return;
     }
     go_direction(ch, dir);
     if (ch->in_room == room)
       ch->commandp++;
     return;
   }
   ch->commandp++;
}

void do_act(char *arg, struct char_data *ch)
{
   int bits;
   if (arg) {
     bits = atoi(arg);
     ch->specials.act = bits;
     if(!IS_SET(ch->specials.act, ACT_SCRIPT))
       SET_BIT(ch->specials.act, ACT_SCRIPT);
     if(!IS_SET(ch->specials.act, ACT_ISNPC))
       SET_BIT(ch->specials.act, ACT_ISNPC);
   }
   ch->commandp++;
   return;
 }

void do_jmp(char *arg, struct char_data *ch)
{
 int i;
 char buf[255];

 for(i = 0; strcmp(script_data[ch->script].script[i].line, "end\n"); i++) {
    strcpy(buf,script_data[ch->script].script[i].line);
    if(buf[strlen(buf) - 1] == '\n')
       buf[strlen(buf) - 1] = '\0';

    if(!strncmp(buf, arg, strlen(arg))) {
       ch->commandp = i;
       return;
     }
  }

 sprintf(buf, "Label %s undefined in script assigned to %s.  Ignoring.", arg, GET_NAME(ch));
 log(buf);

 ch->commandp++;
}

void do_jsr(char *arg, struct char_data *ch)
{
 int i;
 char buf[255];

 for(i = 0; strcmp(script_data[ch->script].script[i].line, "end\n"); i++) {
    strcpy(buf,script_data[ch->script].script[i].line);
    if(buf[strlen(buf) - 1] == '\n')
       buf[strlen(buf) - 1] = '\0';

    if(!strncmp(buf, arg, strlen(arg))) {
       ch->commandp2 = ch->commandp + 1;
       ch->commandp = i;
       return;
     }
  }

 sprintf(buf, "Label %s undefined in script assigned to %s.  Ignoring.", arg, GET_NAME(ch));
 log(buf);

 ch->commandp++;
}

void do_rts(char *arg, struct char_data *ch)
{
 ch->commandp = ch->commandp2;
 ch->commandp2 = 0;
}

void MobHit(struct char_data *ch, struct char_data *v, int type)
{
  int base, percent, learned;
  struct obj_data *o;

  if (type != 0) {
    hit(ch,v,type);
  }

  /* backstab thing */
  if (ch->equipment[WIELD]) {
    o = ch->equipment[WIELD];
    if (o->obj_flags.value[3] != 11 && o->obj_flags.value[3] != 1 &&
	o->obj_flags.value[3] != 10) {
      hit(ch,v,0);
    } else {
      if (ch->specials.fighting) {
	return;
      }

      if (v->specials.fighting) {
	base = 0;
      } else {
	base = 4;
      }

      learned = 50 + GetMaxLevel(ch);
      percent = number(1,100);
      if (percent > learned) {
	if (AWAKE(v)) {
	  damage(ch, v, 0, SKILL_BACKSTAB);
	  AddHated(v, ch);
	} else {
	  base += 2;
	  GET_HITROLL(ch) += base;
	  hit(ch,v,SKILL_BACKSTAB);
	  GET_HITROLL(ch) -= base;
	  AddHated(v, ch);
	}
      } else {
	GET_HITROLL(ch) += base;
	hit(ch,v,SKILL_BACKSTAB);
	GET_HITROLL(ch) -= base;
	AddHated(v, ch);
      }
    }
  } else {
    hit(ch,v,0);
  }
}
