/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

mobact.c				See below... 

		Believe it or not, the old mobact.c from circle2.2 was
		scrapped for about 5 months, everything was put into a
		file called activity.c, and mobact.c was no more...
		But, then I started adding OLCable room procs and it
		got too long, so I have split up that file into two
		called mobact.c and roomact.c...note: sooner or later
		there will be zoneact.c as well to perform zone procs such
		as zone specific weather and what not...

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
**********************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "affect.h"
#include "magic.h"
#include "mudlimits.h"
#include "nature.h"
#include "fight.h"
#include "lists.h"
#include "global.h"

/* external structures */
extern chdata *combat_list;
extern struct str_app_type str_app[];
extern struct arena_data arena_info;

/* internal functions */
BOOL has_bad_affects(obdata *obj);
void hunt_victim(chdata *ch);
void do_mob_random(chdata *mob);  /* for random mobs */

/* external functions */
extern void do_mob_mobproc(chdata *mob);
extern void perform_remove(chdata *ch, int pos);
extern BOOL perform_wear(chdata *ch, obdata *ob, int where);
extern int find_eq_pos(chdata *ch, obdata *ob, char *arg);
extern int find_first_step(int src, int trg);

#define ALIGN_PROBS(ch, obj) ((OBJ_FLAGGED((obj), ITEM_ANTI_EVIL) \
                                                   && IS_EVIL((ch))) || \
       (OBJ_FLAGGED((obj), ITEM_ANTI_GOOD) && IS_GOOD((ch))) || \
       (OBJ_FLAGGED((obj), ITEM_ANTI_NEUTRAL) && IS_NEUTRAL((ch)))) 

// for each client, check to see if they need to repeat mob sound... 2/19/98 -jtrhone
void check_mob_music(void)
{
  extern void send_soundfile_to_client(dsdata *d, char *file);
  dsdata *d;
  chdata *m;

  for (d = descriptor_list; d;d=d->next)
  if (D_CHECK(d) && HAS_CLIENT(d) && d->mob_stimer > -1)
  {
    d->mob_stimer--;
    if (d->mob_stimer == 0)  // hey now... time to play
    {
      int room = d->character->in_room;
      if (INVALID_ROOM(room))
        continue;

      // see if that mob vnum still in this room...
      for (m = world[room].people; m; m=m->next_in_room)
        if (IS_NPC(m) && GET_MOB_VNUM(m) == d->music_mob)
          break;

      if (!m || !m->npc_specials.sound_file)
      {
        d->mob_stimer = -1;
        d->music_mob  = -1;
        continue;
      }

      // else send it and set the numbers...
      send_soundfile_to_client(d, m->npc_specials.sound_file);
      d->mob_stimer = m->npc_specials.music_timer;
      d->music_mob  = GET_MOB_VNUM(m);
    }
  }
}

chdata *choose_random_victim(chdata *ch)
{
    chdata *opponents[20];
    chdata *combatant;
    int n_opponents = 0;
    
    for (combatant = combat_list; 
	 combatant && n_opponents < 20; 
	 combatant = combatant->next_fighting) 
    {
	if (ch == combatant->specials.fighting)
	    opponents[n_opponents++] = combatant;
    }

    if (n_opponents > 0)
	return opponents[number(0, n_opponents - 1)];
    else
	return NULL;
}

void	npc_steal(chdata *ch, chdata *victim)
{
   int	gold;

   if (IS_NPC(victim))
      return;
   if (GET_LEVEL(victim) >= LEV_IMM)
      return;

   if (AWAKE(victim) && (number(0, GET_LEVEL(ch)) == 0)) {
      act("You discover that $n has $s hands in your purse.", FALSE, ch, 0, victim, TO_VICT);
      sprintf(buf, "$n tried to steal %s from $N.", currency_name_plural);
      act(buf, TRUE, ch, 0, victim, TO_NOTVICT);
   } else {
      /* Steal some gold coins */
      gold = (int) ((GET_GOLD(victim) * number(1, 10)) / 100);
      if (gold > 0) {
	 GET_GOLD(ch) += gold;
	 GET_GOLD(victim) -= gold;
      }
   }
}

/* this makes all the cityguards in victims zone start huntin em */
/* if they are not hunting someone else already */
void start_cityguard_hunt(chdata *victim)
{
  chdata *tmp;

  for (tmp = character_list; tmp; tmp = tmp->next)
    if (SPC_FLAGGED(tmp, SPC_CITYGUARD) && !HUNTING(tmp) && !FIGHTING(tmp) &&
	!IN_NOWHERE(tmp) && !IN_NOWHERE(victim) &&
        world[tmp->in_room].zone == world[victim->in_room].zone)
  {
    act("$n suddenly grabs $s weapon!", TRUE, tmp, 0, 0, TO_ROOM);
    HUNTING(tmp) = victim;
    hunt_victim(tmp);
  }
}

/* this is the normal screamin guard thing */
void do_mob_cityguard(chdata *ch)
{
   chdata *tch, *evil;
   int	max_evil;

   max_evil = 1000;
   evil = 0;

   if (IN_NOWHERE(ch))
     return;

   for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room) 
      if (FIGHTING(tch) && (GET_ALIGNMENT(tch) < max_evil) && (IS_NPC(tch) || IS_NPC(FIGHTING(tch)))) 
	 {
	    max_evil = GET_ALIGNMENT(tch);
	    evil = tch;
	 }

   if (evil && (GET_ALIGNMENT(FIGHTING(evil)) >= 0)) 
   {
      do_say(ch, "PROTECT THE INNOCENT!  BANZAI!  CHARGE!  ARARARAGGGHH!", 0, SPEAKING(ch));
      hit(ch, evil, TYPE_UNDEFINED, FALSE);
      return;
   }

   /* make guard hunt victim if not busy fighting */
   if (!evil && HUNTING(ch))
     hunt_victim(ch);
}

SPECIAL(sage)
{
   chdata *vict;
   int todo;

   if (cmd) return FALSE;

   if (GET_POS(ch) == POS_FIGHTING)
      return FALSE;

   if (IN_NOWHERE(ch)) return 0;

   todo = number(0,25);
   switch(todo) {
   case 1:
    act("$n grumbles about the dangers of the world.", 1, ch, 0, 0, TO_ROOM);
    break;
   case 2:
      act("$n mumbles something about helping newbies.", 1, ch, 0, 0, TO_ROOM);
    break;      
   case 3:
      act("$n says 'All around you is a vast world begging to be explored.'", 1, ch, 0, 0, TO_ROOM);
	break;
   case 4:
      act("$n stares at the sky and harumphs.", 1, ch, 0, 0, TO_ROOM);
        do_sit(ch, "", 0, 0);
	break;
   case 5:
      act("$n says 'I've seen many adventurers come and go.'", 1, ch, 0, 0, TO_ROOM);
   	break;
   case 6:
      act("$n says 'I try to help the younger generations.'", 1, ch, 0, 0, TO_ROOM);
      act("$n utters 'I'm not as powerful as I once was.'", 1, ch, 0, 0, TO_ROOM);
	break;
   case 7:
      do_stand(ch, "", 0, 0);
      break;
   case 9:
      act("$n says 'The Realms have changed so much in so little time.'", 1, ch, 0, 0, TO_ROOM);
   	break;
   case 10:
     if (IN_NOWHERE(ch)) break;
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_HIT(vict) < GET_MAX_HIT(vict))
       if (GET_LEVEL(vict) <= 10) {
        act("$n tells you, 'Perhaps I can help you, young one.'", FALSE, ch, 0, vict, TO_VICT);
        act("$n places $s hands on your head...", FALSE, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_CURE_CRITIC, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 12:
     if (IN_NOWHERE(ch)) break;
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_HIT(vict) < GET_MAX_HIT(vict))
       if (GET_LEVEL(vict) <= 5) {
        act("$n tells you, 'Perhaps I can help you, young one.'", FALSE, ch, 0, vict, TO_VICT);
        act("$n places $s hands on your head...", FALSE, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_CURE_CRITIC, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 13:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
	if (GET_HIT(vict) < GET_MAX_HIT(vict))
       if (GET_LEVEL(vict) <= 5) {
        act("$n tells you, 'Perhaps I can help you, young one.'", FALSE, ch, 0, vict, TO_VICT);
        act("$n places $s hands on your head...", FALSE, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_HEAL, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 14:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_LEVEL(vict) <= 5) {
        act("$n tells you, 'Perhaps I can help you, young one.'", FALSE, ch, 0, vict, TO_VICT);
        act("$n places $s hands on your head...", FALSE, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_BLESS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 15:
   case 16:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_LEVEL(vict) <= 10) {
        act("$n tells you, 'Perhaps I can help you, young one.'", FALSE, ch, 0, vict, TO_VICT);
        act("$n places $s hands on your head...", FALSE, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_ARMOR, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
     break;

   default:
     break;
   }
  return TRUE;
}

void do_mob_healer(chdata *ch)
{
   chdata *vict;

   if (IN_NOWHERE(ch)) return;

   switch(number(0, 25)) {
   case 10:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_HIT(vict) < GET_MAX_HIT(vict))
       if (GET_LEVEL(vict) <= 10) {
	sprintf(buf,"$n stares into your eyes...");
        act(buf, 1, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_CURE_CRITIC, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 12:
   case 13:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_HIT(vict) < GET_MAX_HIT(vict))
       if (GET_LEVEL(vict) <= 5) {
	sprintf(buf,"$n stares into your eyes...");
        act(buf, 1, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_HEAL, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 14:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_LEVEL(vict) <= 5) {
	sprintf(buf,"$n stares into your eyes...");
        act(buf, 1, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_BLESS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
	break;
   case 15:
   case 16:
     for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
       if (GET_LEVEL(vict) <= 10) {
	sprintf(buf,"$n stares into your eyes...");
        act(buf, 1, ch, 0, vict, TO_VICT);
	do_cast_spell(SPELL_ARMOR, ch, "", SPELL_TYPE_SPELL, vict, NULL);
       }
     break;

   default:
     break;
   }
}

void do_mob_cleric(chdata *ch)
{
   chdata *vict;

   if (!FIGHTING(ch))
      return;

   if (!(vict = choose_random_victim(ch)))
      return;

   switch (number(0,10))
       {
	 case  0: 
          if (GET_LEVEL(ch) > 0)
 	   do_cast_spell(SPELL_BLINDNESS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  1:
	 case  2:
	 case  3:
	 case  4: 
          if (GET_LEVEL(ch) > 10)
 	   do_cast_spell(SPELL_EARTHQUAKE, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  5:
	 case  6:
	 case  7: 
          if (GET_LEVEL(ch) > 20 && !IS_EVIL(ch))
 	   do_cast_spell(SPELL_DISPEL_EVIL, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  8:
	 case  9: 
          if (GET_LEVEL(ch) > 30)
 	   do_cast_spell(SPELL_CURSE, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case 10: 
          if (GET_LEVEL(ch) > 40)
 	   do_cast_spell(SPELL_HARM, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
       }
}

/* mob jets 1 out of every 10 tries in combat RoA */
void do_mob_teleport(chdata *mob)
{
   if (!FIGHTING(mob))
      return;
 
  /* 1 in 10 chance */
  if (!number(0, 10))
    do_cast_spell(SPELL_TELEPORT, mob, "", SPELL_TYPE_SPELL, NULL, NULL);
}

void do_mob_undead(chdata *ch)
{
   chdata *vict;

   if (!FIGHTING(ch))
      return;

   if (!(vict = choose_random_victim(ch)))
      return;

   switch (number(0,5))
       {
	 case  0: 
            if (GET_LEVEL(ch) > 0)
	      do_cast_spell(SPELL_CURSE, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  1: 
            if (GET_LEVEL(ch) > 7)
	      do_cast_spell(SPELL_CHILL_TOUCH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  2: 
            if (GET_LEVEL(ch) > 14)
	      do_cast_spell(SPELL_BLINDNESS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  3: 
            if (GET_LEVEL(ch) > 21)
	      do_cast_spell(SPELL_POISON, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  4: 
            if (GET_LEVEL(ch) > 28)
	      do_cast_spell(SPELL_ENERGY_DRAIN, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
	 case  5: 
            if (GET_LEVEL(ch) > 35)
	      do_cast_spell(SPELL_HARM, ch, "", SPELL_TYPE_SPELL, vict, NULL);
	    break;
       }
}

void do_mob_bash(chdata *ch)
{
    chdata *vict;

    if (!(vict = FIGHTING(ch)))
      return;

    if (number(1,20) <= MIN(GET_LEVEL(ch), 19))
    {
      if (damage(ch, vict, 1, SKILL_BASH, TRUE) == CHAR_OK)
      {
	if (GET_POS(vict) > POS_SITTING)
	  GET_POS(vict) = POS_SITTING;
        WAIT_STATE(vict, PULSE_VIOLENCE * 2);
      }
    }
    else
    {
      damage(ch, vict, 0, SKILL_BASH, TRUE);
      if (GET_POS(ch) > POS_SITTING)
	GET_POS(ch) = POS_SITTING;
    }

    WAIT_STATE(ch, PULSE_VIOLENCE * 2);
}

void do_mob_kick(chdata *ch)
{
    chdata *vict;
    int percent, prob;

    if (!(vict = FIGHTING(ch)))
      return;

    percent = ((10 - (GET_AC(vict) / 10)) << 1) + number(1, 100);
    prob = 5 * GET_LEVEL(ch);

    if (percent > MIN(prob, 95)) 
	damage(ch, vict, 0, SKILL_KICK, FALSE);
    else
	damage(ch, vict, GET_LEVEL(ch), SKILL_KICK, FALSE);

    WAIT_STATE(ch, PULSE_VIOLENCE * 3);
}

void do_mob_warrior(chdata *ch)
{
  if (WAITING(ch)) 
  {
    send_to_char("Ah ah ah... yer in no position to do that yet.\n\r",ch);
    return;
  }

  if (!number(0,1))
    do_mob_kick(ch);
  else
    do_mob_bash(ch);
}

/* do a hard wired spec_proc (only sage i think is left) */
void do_mob_hard_wired_special(chdata *ch)
{
    if (GET_MOB_RNUM(ch) <= -1) 
    {
      sprintf(buf, "SYSERR: (%s) Attempting mob func on neg rnum.",GET_NAME(ch));
      mudlog(buf, BRF, LEV_IMM, FALSE);
      REMOVE_BIT(MOB_FLAGS(ch), MOB_SPEC);
      return;
    } 
    else 
    if (!mob_index[ch->nr].func) 
    {
      sprintf(buf, "%s (#%d): Attempting to call non-existing mob func", GET_NAME(ch), mob_index[ch->nr].vnum);
      mudlog(buf, BUG, LEV_IMM, FALSE);
      REMOVE_BIT(MOB_FLAGS(ch), MOB_SPEC);
    } 
    else 
      (*mob_index[ch->nr].func) (ch, 0, "");
}

/* devour corpses and the like */
void do_mob_fido(chdata *ch)
{
  obdata *i = NULL, *inext = NULL, *next_obj = NULL, *temp = NULL;

  if (IN_NOWHERE(ch)) return;

  for (i = world[ch->in_room].contents; i; i = inext) 
  {
    inext = i->next_content;
    if (IS_CORPSE(i)) 
    {
      act("$n savagely devours a corpse.", FALSE, ch, 0, 0, TO_ROOM);
      for (temp = i->contains; temp; temp = next_obj) 
      {
	next_obj = temp->next_content;
	obj_from_obj(temp);
	float_sink_object(temp, ch->in_room);
      }
      extract_obj(i);
    }
  }
}

/* pick up the trash */
void do_mob_janitor(chdata *ch)
{
   obdata *i = 0;

   if (IN_NOWHERE(ch)) return;
   for (i = world[ch->in_room].contents; i; i = i->next_content) 
      if (IS_SET(OBJ_WEARS(i), ITEM_TAKE) && (i->cost <= 10) && i->in_room != NOWHERE) 
      {
	 sprintf(buf,"get %s", i->name);
         command_interpreter(ch, buf);
         break;
      }
}

void do_mob_warcry(chdata *ch)
{
   if (!number(0,1))
     if ((GET_LEVEL(ch) + number(0,50) > 60) && GET_LEVEL(ch) >= GET_LEVEL(FIGHTING(ch))+5)
     {
       act("$n %BHOWLS%0 a vicious war cry!!!", 1, ch, 0, 0, TO_ROOM);
       send_to_char("It %Bchills%0 you to the bone!!\n\r",FIGHTING(ch));
       do_flee(FIGHTING(ch),"",0,0);
     }
     else
     {
       act("$n %BHOWLS%0 a vicious war cry!!!", 1, ch, 0, 0, TO_ROOM);
       send_to_char("You %Bscream%0 in defiance!!!\n\r",FIGHTING(ch));
     }
}

void do_mob_snake(chdata *ch)
{
   if (WAITING(ch)) 
   {
     send_to_char("Ah ah ah... yer in no position to do that yet.\n\r",ch);
     return;
   }

   if (FIGHTING(ch) && SAME_ROOM(ch, FIGHTING(ch)) && !number(0,3))
   {
      act("$n bites $N!", 1, ch, 0, FIGHTING(ch), TO_NOTVICT);
      act("$n bites you!", 1, ch, 0, FIGHTING(ch), TO_VICT);
      do_cast_spell(SPELL_POISON, ch, "", SPELL_TYPE_SPELL, FIGHTING(ch), NULL);
   }
}

void do_mob_ppocket(chdata *ch)
{
   chdata *vict = 0;

   if (IN_NOWHERE(ch)) return;
   for (vict = world[ch->in_room].people; vict; vict = vict->next_in_room )
      if ((IS_PC(vict)) && (GET_LEVEL(vict) < 41) && (number(1, 5) == 1))
	 npc_steal(ch, vict);
}

void do_mob_gasbreath(chdata *ch)
{
  chdata *vict = FIGHTING(ch);
  act("Tendrils of %2green smoke%0 surround $n as $e inhales deeply!",
      TRUE,ch,0,0,TO_ROOM);
  if (number(0,1) || GET_LEVEL(ch) > 55)
    do_cast_spell(SPELL_GAS_BREATH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
}

void do_mob_firebreath(chdata *ch)
{
  chdata *vict = FIGHTING(ch);
  act("Small wisps of %B%1flame%0 surround $n as $e inhales deeply!",
      TRUE,ch,0,0,TO_ROOM);
  if (number(0,1) || GET_LEVEL(ch) > 55)
    do_cast_spell(SPELL_FIRE_BREATH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
}

void do_mob_icebreath(chdata *ch)
{
  chdata *vict = FIGHTING(ch);
  act("The area suddenly turns %B%6colder%0 as $n inhales deeply!",
      TRUE,ch,0,0,TO_ROOM);
  if (number(0,1) || GET_LEVEL(ch) > 55)
    do_cast_spell(SPELL_FROST_BREATH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
}

void do_mob_acidbreath(chdata *ch)
{
  chdata *vict = FIGHTING(ch);
  act("The area suddenly turns %1warmer%0 as $n inhales deeply!",
      TRUE,ch,0,0,TO_ROOM);
  if (number(0,1) || GET_LEVEL(ch) > 55)
    do_cast_spell(SPELL_ACID_BREATH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
}

void do_mob_boltbreath(chdata *ch)
{
  chdata *vict = FIGHTING(ch);
  act("You feel a hint of %Belectricity%0 as $n inhales deeply!",
      TRUE,ch,0,0,TO_ROOM);
  if (number(0,1) || GET_LEVEL(ch) > 55)
    do_cast_spell(SPELL_LIGHTNING_BREATH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
}

void do_mob_mage(chdata *ch)
{
   chdata *vict = FIGHTING(ch);

   if (vict != FIGHTING(ch) && GET_LEVEL(ch) > 13 && !number(0, 7))
   {
      act("$n utters the words 'dilan oso'.", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_SLEEP, ch, "", SPELL_TYPE_SPELL, vict, NULL);
   }

   if (GET_LEVEL(ch) > 7 && !number(0, 5))
   {
      act("$n utters the words 'koholian dia'.", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_BLINDNESS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
   }

   if (GET_LEVEL(ch) > 12 && !number(0, 8)) 
   {
      act("$n utters the words 'ib er dranker'.", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_ENERGY_DRAIN, ch, "", SPELL_TYPE_SPELL, vict, NULL);
   }

   switch (GET_LEVEL(ch)) {
   case 1:
   case 2:
   case 3:
      break;
   case 4:
   case 5:
      act("$n utters the words 'hahili duvini'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_MAGIC_MISSILE, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   case 6:
   case 7:
      act("$n utters the words 'fridra enton'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_CHILL_TOUCH, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   case 8:
   case 9:
      act("$n utters the words 'grynt oef'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_BURNING_HANDS, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   case 10:
   case 11:
      act("$n utters the words 'juier vrahe'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_SHOCKING_GRASP, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   case 12:
   case 13:
      act("$n utters the words 'sjulk divi'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_LIGHTNING_BOLT, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   case 14:
   case 15:
   case 16:
   case 17:
      act("$n utters the words 'nasson hof'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_COLOUR_SPRAY, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   default:
      act("$n utters the words 'tuborg luca'!", 1, ch, 0, 0, TO_ROOM);
      do_cast_spell(SPELL_FIREBALL, ch, "", SPELL_TYPE_SPELL, vict, NULL);
      break;
   }
}

void do_mob_peaceman(chdata *ch)
{
   chdata *tch = 0;

   if (IN_NOWHERE(ch)) return;
   switch(number(0,25)) {
   case 1:
     if (number(0,3))
    act("$n silently contemplates the violence in this world.", 1, ch, 0, 0, TO_ROOM);
    break;
   case 2:
    break;
   case 3: 
     if (number(0,3))
      act("$n says 'This land was once a land full of peace.'", 1, ch, 0, 0, TO_ROOM);
	break;
   case 4:
     if (number(0,3))
      act("$n dismisses your weapons with a shrug.", 1, ch, 0, 0, TO_ROOM);
	break;
   case 5:
   	break;
   case 6:
     if (number(0,3))
      act("$n says 'I cannot tolerate violence.'", 1, ch, 0, 0, TO_ROOM);
	break;
   case 7:
   case 8:
   case 9:
     if (number(0,3))
     act("$n raises an eyebrow.", 1, ch, 0, 0, TO_ROOM);
     if (number(0,3))
     act("$n says 'There will be no violence in my presence.'", 1, ch, 0, 0, TO_ROOM);
   case 10: 
   case 11: 
   case 12: 
   case 13:
   case 14:
   case 15:
   case 16:
   case 17:
   case 18:
   case 19:
   case 20:
	break;
   default:
     break;
   }

   // fix act(), 6/20/98 -jtrhone
   for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room )
     if (FIGHTING(tch))
     {
       act("$N has compelled you to stop fighting!", FALSE, tch, 0, ch, TO_CHAR);
       stop_fighting(tch);
     }
}

void do_mob_qheal(chdata *ch)
{
  int hitp;

  if (GET_HIT(ch) < GET_MAX_HIT(ch) && (!number(0, 4)))
  {
    act("$n's wounds rapidly disappear.", FALSE, ch, 0, 0, TO_ROOM);
    hitp = GET_MAX_HIT(ch) / 8;
    hitp = MIN(hitp, 500);
    GET_HIT(ch) += hitp;
    GET_HIT(ch) = MIN(GET_MAX_HIT(ch), GET_HIT(ch));
  }
}

/* MOB_SMART functions used in do_mob_smart */
/* Determine if the object has bad affects */
BOOL has_bad_affects(obdata *obj)
{
  int j, app;

  /* Let's not wear anything but armor */ 
  if(obj->type_flag != ITEM_ARMOR) return TRUE;
   
  /* If armor, make sure we dont have negative AC-apply */
  if(obj->value[0] < 0) return TRUE;

  /* Finally, if make sure that there is no -HP, -DAM, or -Stats effects */
  for(j = 0;j < MAX_OBJ_AFFECT;j++) {
    if(obj->affected[j].modifier < 0) {
      app = obj->affected[j].location;
      if((app == APPLY_HITROLL) || (app == APPLY_DAMROLL) || 
         (app == APPLY_HIT) || (app == APPLY_STR) || (app == APPLY_DEX) ||
         (app == APPLY_INT) || (app == APPLY_WIS) || (app == APPLY_CON)) 
             return TRUE;
    } 

    /* negative Saving affects are bad as well */
    if(obj->affected[j].modifier < 0) 
    {
      app = obj->affected[j].location;
      if((app == APPLY_SV_HEAT) || (app == APPLY_SV_COLD) || 
         (app == APPLY_SV_MAGIC) || (app == APPLY_SV_BREATH) ||
         (app == APPLY_SV_POISON))  
	return TRUE;
    }
  }
  return FALSE;
}          

void do_mob_smart(chdata *ch)
{
  BOOL success = FALSE;
  int damnodice = ch->npc_specials.damnodice;
  int damsizedice = ch->npc_specials.damsizedice;
  int weap_dam = 0, mob_dam = 0;
  obdata *wielded = 0, *obj = 0, *temp_obj = 0;
  int where;

  /* calculate mob's barehand damage */
  /* see if barehand is better */
  if ((wielded = EQ(ch, W_WIELD))) 
  {
    weap_dam = 2 * GET_DAMROLL(ch) + wielded->value[1] * (wielded->value[2] + 1);
    eq_to_inv(ch, W_WIELD, FALSE);

    mob_dam = 2 * GET_DAMROLL(ch) + damnodice * (damsizedice + 1);

    // only if equip was successful... 1/28/98 -jtrhone
    if (inv_to_eq(ch, wielded, W_WIELD, FALSE))
      if((mob_dam > weap_dam) && FIGHTING(ch)) 
      {
        do_say(ch, "Bah, why am I wielding this?", 0, SPEAKING(ch));
        perform_remove(ch, W_WIELD);
        success = TRUE;
      }
   }

   /* ok either not wielded or no succes */
   for(obj = ch->carrying; !success && obj;obj = temp_obj) 
   {
     temp_obj = obj->next_content;
     if(CAN_WEAR(obj, ITEM_WIELD) && !ALIGN_PROBS(ch, obj) && IS_WEAPON(obj)) 
     {
       /* calculate mob's barehand damage */
       damnodice = ch->npc_specials.damnodice;
       damsizedice = ch->npc_specials.damsizedice;

       /* calculate the total damage with the weapon */
       if(!(wielded = EQ(ch, W_WIELD)))
       {
         mob_dam = 2 * GET_DAMROLL(ch) + damnodice * (damsizedice + 1);
         weap_dam = obj->value[1] * (obj->value[2] + 1);

	 // equip, calc, unequip
         if (inv_to_eq(ch, obj, W_WIELD, FALSE))
         {
           weap_dam += 2 * GET_DAMROLL(ch);
           eq_to_inv(ch, W_WIELD, FALSE);

	   if((mob_dam < weap_dam) && FIGHTING(ch)) 
	   {
             act("$n searches through $s inventory...", FALSE, ch, 0, 0, TO_ROOM);
             success = perform_wear(ch, obj, W_WIELD);
           }
         }
       }
       else /* is wielded */
       {
	 /* Otherwise compare the two weapons and see which one is better */
	 /* calc first dam */
         weap_dam = 2 * GET_DAMROLL(ch) + wielded->value[1] * (wielded->value[2] + 1);

         // swap wielded with new weapon
         eq_to_inv(ch, W_WIELD, FALSE);

         if (inv_to_eq(ch, obj, W_WIELD, FALSE))
         {
	   /* now calc that damage */
           mob_dam = 2 * GET_DAMROLL(ch) + obj->value[1] * (obj->value[2] + 1);

           // swap them back
           eq_to_inv(ch, W_WIELD, FALSE);
         }
         else 
           mob_dam = 0;

         inv_to_eq(ch, wielded, W_WIELD, FALSE);

	 /* if still fighting and new weapon is better then switch */
         if((mob_dam > weap_dam) && FIGHTING(ch)) 
	 {
           act("$n looks through $s weaponry...", FALSE, ch, 0, 0, TO_ROOM);
           perform_remove(ch, W_WIELD);
           success = perform_wear(ch, obj, W_WIELD);
           act("$n starts wielding a mightier weapon!", FALSE, ch, 0, 0, TO_ROOM);
         }
       } /* end of wielded */      
     } /* if CAN_WEAR and !ALIGN_PROBS */
   } /* for loop */

  /* still no success, lets try armor */
  for(obj = ch->carrying; !success && obj;obj = temp_obj) 
  {
    temp_obj = obj->next_content;

    /* lets not wear -hp stuff */
    if (has_bad_affects(obj)) 
      continue;
       
    /* find where we can wear that eq */
    where = find_eq_pos(ch, obj, 0);

    if((where < 0) || (where >= W_WIELD)) 
      continue;

    if(!EQ(ch, where) && !ALIGN_PROBS(ch, obj)) 
    {
      switch(number(1, 3)) 
      {
        case 1:
          act("$n looks through $s inventory...", FALSE, ch, 0, 0, TO_ROOM);
          break;
        case 2:
          act("$n thinks for a little while...", FALSE, ch, 0, 0, TO_ROOM);
          break;
        default:
          if(FIGHTING(ch)) 
	  {
            act("$n decides that $N is a tougher opponent than $e thought $E was.",
		FALSE, ch, 0, FIGHTING(ch), TO_NOTVICT);
            act("$N starts taking you more seriously.", FALSE, FIGHTING(ch), 0, ch, TO_CHAR);
          }
          else 
	  act("$n grins evilly.", FALSE, ch, 0, 0, TO_ROOM);
	  break;
      } /* end of switch */
      success = perform_wear(ch, obj, where);
    } /* if EQ and !ALIGN_PROBS */
  } /* for loop lookin thru eq */
} /* end of function */

void do_mob_helper(chdata *ch)
{
  chdata *tmp_ch;

  if (IN_NOWHERE(ch) || IS_AFFECTED(ch, AFF_BLIND | AFF_SLEEP) ||
      GET_POS(ch) == POS_SLEEPING) return;

  tmp_ch = world[ch->in_room].people;
  for ( ; tmp_ch; tmp_ch = tmp_ch->next_in_room)
    if (IS_NPC(tmp_ch) && FIGHTING(tmp_ch) && IS_PC(FIGHTING(tmp_ch)))
    {
      act("$n jumps into the battle!.",FALSE,ch,0,tmp_ch,TO_ROOM);
      act("$n assists $N.", FALSE, ch, 0, tmp_ch, TO_ROOM);
      hit(ch, FIGHTING(tmp_ch), 0, FALSE);
      break;
    }
}

void do_mob_scavenger(chdata *ch)
{
  obdata *obj = 0, *best_obj = 0;
  int max = 1;

  if (IN_NOWHERE(ch)) return;
  if (world[ch->in_room].contents && !number(0, 10)) 
  {
    for (obj = world[ch->in_room].contents; obj; obj = obj->next_content) 
      if (CAN_GET_OBJ(ch, obj) && (obj->cost > max)) 
      {
	best_obj = obj;
	max = obj->cost;
      }

    if (best_obj && best_obj->in_room != NOWHERE && best_obj->name) 
    {
      one_argument(best_obj->name, buf);
      do_get(ch, buf, 0, 0);
    }
  } /* end of main if */
}

void do_mob_movement(chdata *ch)
{
  int door;

  if (IN_NOWHERE(ch)) return;

  if (((door = number(0, 45)) < NUM_OF_DIRS) && CAN_GO(ch, door) && 
      !ROOM_FLAGGED(EXIT(ch, door)->to_room, NO_MOB) && 
      !ROOM_FLAGGED(EXIT(ch, door)->to_room, FLY_DEATH) && 
      !ROOM_FLAGGED(EXIT(ch, door)->to_room, DEATH)) 
  {
    if (ch->npc_specials.last_direction == door) 
	ch->npc_specials.last_direction = -1;
    else 
    {
      if (!MOB_FLAGGED(ch, MOB_STAY_ZONE)) 
      {
	ch->npc_specials.last_direction = door;
	do_move(ch, "", ++door, 0);
      } 
      else 
      if (world[EXIT(ch, door)->to_room].zone == world[ch->in_room].zone) 
      {
	ch->npc_specials.last_direction = door;
	do_move(ch, "", ++door, 0);
      }
    }
  } /* if can go */
}

void do_mob_aggressive(chdata *ch)
{
  BOOL found = FALSE;
  chdata *tmp_ch;

  if (IN_NOWHERE(ch)) return;

  if (GET_POS(ch) <= POS_SLEEPING || affected_by_spell(ch, SPELL_SLEEP))
  {
    if (GET_LEVEL(ch) > number(1, 100))
    {
      affect_from_char(ch, SPELL_SLEEP);
      do_wake(ch, "", 0, 0);
      act("$n breaks the sleep spell!",TRUE,ch,0,0,TO_ROOM);
    }
    else
      return;
  }

  tmp_ch = world[ch->in_room].people;
  for ( ; tmp_ch && !found; tmp_ch = tmp_ch->next_in_room) 
  {
    if (IS_PC(tmp_ch) && can_see(ch, tmp_ch) && !PRF_FLAGGED(tmp_ch, PRF_NOHASSLE)) 
      if (!IS_AFFECTED2(ch, AFF2_CALM) && (!MOB_FLAGGED(ch, MOB_WIMPY) || !AWAKE(tmp_ch))) 
	if (((MOB_FLAGGED(ch, MOB_AGGR_EVIL) && IS_EVIL(tmp_ch)) || 
	    (MOB_FLAGGED(ch, MOB_AGGR_GOOD) && IS_GOOD(tmp_ch)) || 
	    (MOB_FLAGGED(ch, MOB_AGGR_NEUTRAL) && IS_NEUTRAL(tmp_ch)) || 
	    (!MOB_FLAGGED(ch, MOB_AGGR_EVIL) && 
	     !MOB_FLAGGED(ch, MOB_AGGR_NEUTRAL) && 
	     !MOB_FLAGGED(ch, MOB_AGGR_GOOD))) &&
	    check_truce(ch, tmp_ch))  
	{
	  hit(ch, tmp_ch, 0, FALSE);
	  found = TRUE;
	}
  } /* end of for */
}

/* Mob Memory Routines used in do_mob_memory */
/* make ch remember victim */
void	remember (chdata *ch, chdata *victim)
{
   memory_rec * tmp;
   BOOL present = FALSE;

   if (IS_PC(ch) || IS_NPC(victim)) 
      return;

   for (tmp = ch->npc_specials.memory; tmp && !present; tmp = tmp->next)
      if (tmp->id == GET_IDNUM(victim))
	 present = TRUE;

   if (!present) {
      CREATE(tmp, memory_rec, 1);
      tmp->id = GET_IDNUM(victim);
      tmp->next = ch->npc_specials.memory;
      ch->npc_specials.memory = tmp;
   }
}

/* make ch forget victim */
void	forget (chdata *ch, chdata *victim)
{
   memory_rec *curr = NULL, *prev = NULL;

   if (!(curr = ch->npc_specials.memory))
      return;

   while (curr && curr->id != GET_IDNUM(victim)) {
      prev = curr;
      curr = curr->next;
   }

   if (!curr) 
      return; /* person wasn't there at all. */

   if (curr == ch->npc_specials.memory)
      ch->npc_specials.memory = curr->next;
   else
      prev->next = curr->next;

   free_log(curr, "forget");
}

// scan entire list of mobs (ick) and make SURE nobody remembers ch
void global_forget(chdata *ch)
{
  chdata *m;

  for (m = character_list; m; m=m->next)
  {
    if (IS_NPC(m) && (MOB_FLAGGED(m, MOB_MEMORY) || m->npc_specials.memory))
      forget(m, ch);
  
    // also forget holder slot...
    if (HOLDER(ch) == ch)
      HOLDER(ch) = NULL;
  }
}

/* erase ch's memory */
void	clearMemory(chdata *ch)
{
   memory_rec *curr, *next;

   curr = ch->npc_specials.memory;
   while (curr) {
      next = curr->next;
      free_log(curr, "clearMemory");
      curr = next;
   }
   ch->npc_specials.memory = NULL;
}

/* use previous few functions for memory stuff */
void do_mob_memory(chdata *ch)
{
  chdata *vict = 0;
  chdata *tmp_ch;
  memory_rec *names = ch->npc_specials.memory;

  if (IN_NOWHERE(ch) || IS_AFFECTED(ch, AFF_SLEEP | AFF_BLIND)) return;
  tmp_ch = world[ch->in_room].people;
  for ( ; tmp_ch && !vict; tmp_ch = tmp_ch->next_in_room)
   if (IS_PC(tmp_ch))
     for ( ; names && !vict; names = names->next)
      if (names->id == GET_IDNUM(tmp_ch))
	vict = tmp_ch;

  if (vict) 
  {
    act("$n recognizes an enemy!", FALSE, ch, 0, 0, TO_ROOM);
    do_kill(ch, GET_NAME(vict), 0, 0);
  }
}

/* if a mob is bleeding it leaves a trail of blood objects -roa*/
void do_mob_bleeder(chdata *ch)
{
  obdata *blood;

  if (IN_NOWHERE(ch)) return;

  if (number(0, 1))
    return;

  /* only blood is object 150, will change very soon to random of like 5*/
  if (!(blood = read_object(150, VIRTUAL)))
  {
    send_to_char("Uh oh.  Your blood does not exist!\n\r",ch);
    return;
  }

  blood->value[3] = 1;   /* sets corpse flag so it will decay */

  act("You are %1bleeding%0!", FALSE, ch, 0, 0, TO_CHAR);
  act("$n is %1bleeding%0!", TRUE, ch, 0, 0, TO_ROOM);
  obj_to_room(blood, ch->in_room);
}

/* 
   following is called every hour and updates each shopkeep mob that has
   a shop_data structure allocated to it... if it's one hour to close, the
   mob will announce that and if it's the closing hour, the mob will begin
   it's track to it's vnum of its home if it is defined (>=0)...
   if the hour is the mob's opening hour, it will begin its track to its
   shop to be updated in mobile activity every few pulses.  this is all
   OLCable as usual :) -roa jtrhone 
*/
// updated 1/22/98 -jtrhone
// plshopkeep mobs are not wanderers...
BOOL wandering_shopkeep(chdata *ch)
{
  struct shop_data_type *shp = ch->npc_specials.shop_data;

  if (!shp)
  {
    sprintf(buf, "SYSERR: Shopkeep mob without shop_data struct (%s).", GET_NAME(ch));
    mudlog(buf, BRF, LEV_IMM, TRUE);
    return FALSE;
  }

  if (MOB_FLAGGED(ch, MOB_PLSHOPKEEP))
    return FALSE;

  if (shp->vshop == -1 && shp->vhome == -1 && shp->open == -1 && shp->close == -1)
    return TRUE;

  return FALSE;
}

void open_close_shops(void)
{
  chdata *ch;
  struct shop_data_type *shp;
  extern struct time_info_data time_info;

  for (ch = character_list; ch; ch = ch->next)
  if (SPC_FLAGGED(ch, SPC_SHOPKEEP) && !INVALID_ROOM(ch->in_room) && ch->npc_specials.shop_data)
  {
    if (wandering_shopkeep(ch)) 
      continue;

    shp = ch->npc_specials.shop_data;

    /* if they closed check if its opening time */
    if (!SHOPKEEP_OPEN(ch) && time_info.hours == shp->open)
    { 
     SET_BIT(CHAR_FLAGS(ch), CH_SHOP_OPEN);
#ifdef DEBUG_MAX
     sprintf(buf, "SYSUPD: %s now flagged open.",GET_NAME(ch));
     mudlog(buf, BUG, LEV_IMM, FALSE);
#endif
    }
    else  /* check to see if it's near closing time or actually is */
    if (SHOPKEEP_OPEN(ch))
    {
      if (time_info.hours == shp->close)
      {
        REMOVE_BIT(CHAR_FLAGS(ch), CH_SHOP_OPEN);
        act("$n announces that $s shop is closed.", TRUE, ch, 0, 0,TO_ROOM);
#ifdef DEBUG_MAX
        sprintf(buf, "SYSUPD: %s now flagged closed.",GET_NAME(ch));
        mudlog(buf, BUG, LEV_IMM, FALSE);
#endif
      }
      else
      if (shp->close > -1)
      if ((time_info.hours == shp->close - 1) || (time_info.hours == 23 && !shp->close))
        act("$n announces $e will be closing up shop in one hour.",TRUE, ch, 0, 0, TO_ROOM);
    }
  }
}

/* move each this shopkeep towards his/her/its destination */
void do_shopkeep_track(chdata *ch)
{
  struct shop_data_type *shp = ch->npc_specials.shop_data;
  int rhome, rshop, dir;

  if (!shp)
  {
    sprintf(buf, "SYSERR: Shopkeep without shopdata struct #%d(%s).", GET_MOB_VNUM(ch), GET_NAME(ch));
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return;
  }

  rshop = real_room(shp->vshop);
  rhome = real_room(shp->vhome);

  /* if nothing defined on this shopkeep, it could be a wanderer.. ignore
     the data for this one -roa */
  if (wandering_shopkeep(ch))
    return;

  /* if mob flagged open, better be in shop or on his way to shop */
  if (SHOPKEEP_OPEN(ch))
  {
    /* make sure room exists first man :) */
    if (rshop < 0)
    {
      sprintf(buf, "SYSERR: Shopkeep with undefined Vshop #%d(%s).", GET_MOB_VNUM(ch), GET_NAME(ch));
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return;
    }
 
    /* ok it exists, now we have to go there if we arent there */
    if (ch->in_room != rshop)
    {
      if ((dir = find_first_step(ch->in_room, rshop)) < 0)
      {
        sprintf(buf, "SYSERR: Shopkeep unable to track to shop #%d(%s).", GET_MOB_VNUM(ch), GET_NAME(ch));
        mudlog(buf, BUG, LEV_IMM, FALSE);
        return;
      }
      do_move(ch, "", dir+1, 0);
  
      /* have we arrived ? */
      if (ch->in_room == rshop)
	act("$n opens the shop.", TRUE, ch, 0, 0, TO_ROOM);
    }
  }
  else
  /* if mob flagged close, better be in home or on his way to home */
  if (!SHOPKEEP_OPEN(ch))
  {
    /* make sure room exists first man :) */
    if (rhome < 0)
    {
      sprintf(buf, "SYSERR: Shopkeep with undefined Vhome #%d(%s).", GET_MOB_VNUM(ch), GET_NAME(ch));
      mudlog(buf, BUG, LEV_IMM, FALSE);
      return;
    }
 
    /* ok it exists, now we have to go there if we arent there */
    if (ch->in_room != rhome)
    {
      if ((dir = find_first_step(ch->in_room, rhome)) < 0)
      {
        sprintf(buf, "SYSERR: Shopkeep unable to track to home #%d(%s).", GET_MOB_VNUM(ch), GET_NAME(ch));
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return;
      }
      do_move(ch, "", dir+1, 0);
    }
  }
}

// if a mob was summoned (created) track to its master -roa
void do_summoned_activity(chdata *mob)
{
  chdata *ch;
  int dir;
  extern chdata *get_char_by_id(long id);

  if (!FIGHTING(mob) && (ch = get_char_by_id(SUMMONER(mob))))
    if (!SAME_ROOM(mob, ch))
    {
      if ((dir = find_first_step(mob->in_room, ch->in_room)) >= 0)
        do_move(mob, "", dir+1, 0);
    }
    else
    {
      if (FIGHTING(ch) && FIGHTING(ch) != mob)
	do_assist(mob, GET_NAME(ch), 0, 0);
    }
}

/* the following are MOB special procedures as defined by any builder in   */
/* OLC. Checks every few pulses from comm.c on these procs goes thru list */
/* and calls appropriate functions, checks hard code first  */ 
/* 
  JTRHONE	ROA 
  Totally revamped this entire process of mobile activities...
  made each mob_flag and spc_flag individual functions
  all flags are OLCable online
  only keep hard wired checks for backwards compat for older mobs
  but most hard wired functions have been converted into the new FLAG
  type format so they are online edittable  
*/
void	mobile_activity(BOOL doubletime)
{
  chdata *ch, *next_ch;
  obdata *obj;

  for (ch = character_list; ch; ch = next_ch)
  {
    next_ch = ch->next;
    if (IS_MOB(ch) && !IN_NOWHERE(ch))
    {
    // every other call is a doubletime call
    if (doubletime && !SPC_FLAGGED(ch, SPC_DOUBLETIME))
      continue;

    /* first make everything they are carrying non touched so it
       can be purged on reset */
    for (obj = ch->carrying; obj; obj = obj->next_content)
      obj->touched = FALSE;

    /* stand em up into default positions first */
    if ((ch->npc_specials.default_pos > POS_SITTING) && 
        (GET_POS(ch) == POS_SITTING))
      do_stand(ch, "", 0, 0);

    if ((ch->npc_specials.default_pos == POS_FLOATING) && 
        (GET_POS(ch) == POS_STANDING)) 
      do_float(ch, "", 0, 0);

    /* Examine call for HARD CODED special procedures first */
    if (MOB_FLAGGED(ch, MOB_SPEC)) 
      do_mob_hard_wired_special(ch);
   
    /* do the builder defined mobprocs for these mobs */
    if (!CHARMED(ch) && SPC_FLAGGED(ch, SPC_MOBPROC))
      do_mob_mobproc(ch);

    /* do non fighting flags first */
    if (!FIGHTING(ch) && AWAKE(ch) && SPC_FLAGGED(ch, SPC_SHOPKEEP))
      do_shopkeep_track(ch);

    if (!FIGHTING(ch) && AWAKE(ch) && SPC_FLAGGED(ch, SPC_FIDO))
      do_mob_fido(ch);

    if (!FIGHTING(ch) && AWAKE(ch) && SPC_FLAGGED(ch, SPC_JANITOR))
      do_mob_janitor(ch);

    if (!FIGHTING(ch) && SPC_FLAGGED(ch, SPC_RANDOM))
      do_mob_random(ch);

    if (!FIGHTING(ch) && SPC_FLAGGED(ch, SPC_HEALER))
      do_mob_healer(ch);

    if (!FIGHTING(ch) && SPC_FLAGGED(ch, SPC_PEACE_MAN))
      do_mob_peaceman(ch);

    /* help routine for NPCs */
    if (!FIGHTING(ch) && MOB_FLAGGED(ch, MOB_HELPER) &&
        GET_POS(ch) > POS_STUNNED) 
      do_mob_helper(ch);

    if (!FIGHTING(ch) && AWAKE(ch) && MOB_FLAGGED(ch, MOB_SCAVENGER)) 
      do_mob_scavenger(ch);

    if (!FIGHTING(ch) && MOB_FLAGGED(ch, MOB_AGGR)) 
      do_mob_aggressive(ch);

    if (!FIGHTING(ch) && MOB_FLAGGED(ch, MOB_MEMORY) && 
        ch->npc_specials.memory)
      do_mob_memory(ch);

    if (!FIGHTING(ch) && AWAKE(ch) && SPC_FLAGGED(ch, SPC_CITYGUARD))
      do_mob_cityguard(ch);

    /* now do fighting procs and those which dont care */
    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_WAR_CRY))
      do_mob_warcry(ch);
 
    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_SNAKE))
      do_mob_snake(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_CLERIC))
      do_mob_cleric(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_UNDEAD))
      do_mob_undead(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_TELEPORTER))
      do_mob_teleport(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_WARRIOR))
      do_mob_warrior(ch);

    if (GET_POS(ch) == POS_STANDING && SPC_FLAGGED(ch, SPC_PPOCKET))
      do_mob_ppocket(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_GASBREATH))
      do_mob_gasbreath(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_FIREBREATH))
      do_mob_firebreath(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_ICEBREATH))
      do_mob_icebreath(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_ACIDBREATH))
      do_mob_acidbreath(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_LIGHTBREATH))
      do_mob_boltbreath(ch);

    if (FIGHTING(ch) && SPC_FLAGGED(ch, SPC_MAGIC_USER))
      do_mob_mage(ch);

    if (!FIGHTING(ch) && SPC_FLAGGED(ch, SPC_HUNTER) && HUNTING(ch) && 
       GET_LEVEL(ch) > number(0,15)) 
      hunt_victim(ch);
 
    if (MOB_FLAGGED(ch, MOB_QHEAL)) 
      do_mob_qheal(ch);
        
    /* SMART MOBS, analyze inventory and wear what they need */
    if(MOB_FLAGGED(ch, MOB_SMART) && !SPC_FLAGGED(ch, SPC_SHOPKEEP) &&
       !MOB_FLAGGED(ch, MOB_PLSHOPKEEP) && !CHARMED(ch) && (world[ch->in_room].people != ch)) 
      do_mob_smart(ch);

    if (SUMMONED(ch))
      do_summoned_activity(ch);

    if (!MOB_FLAGGED(ch, MOB_SENTINEL) && !SPC_FLAGGED(ch, SPC_MOBPROC) &&
        (GET_POS(ch) == POS_STANDING))
      do_mob_movement(ch);

    if (SPC_FLAGGED(ch, SPC_BLEEDER) && GET_HIT(ch) <= GET_MAX_HIT(ch)/5)
      do_mob_bleeder(ch);

    } // IS_MOB 
  } // end for

  // check for mob sounds...
  check_mob_music();
}

// placed here for now, check chars for saves vs hold/charm/etc
void	magical_activity(void)
{
  register chdata *ch;
  int save;

  for (ch = character_list; ch; ch = ch->next)
  if (IS_MOB(ch) && !IN_NOWHERE(ch))
  {
    if (IS_HELD(ch))
    {
      save = SAVING_THROW(ch, SV_MAGIC);
      if (save / 5 > number(1,100))	// broke it :)
      {
	act("$n %B%6breaks free%0 of the spell!",TRUE,ch,0,0,TO_ROOM);
	act("You break free of the spell!",FALSE,ch,0,0,TO_CHAR);
	affect_from_char(ch, SPELL_HOLD_PERSON);
      }
    }

    if (CHARMED(ch))
    {
      if (!ch->master)
      {
	sprintf(buf, "SYSERR: Charmed with no master, #%d %s. Corrected.", GET_MOB_VNUM(ch), GET_NAME(ch));
	mudlog(buf, BRF, LEV_IMM, TRUE);
	REMOVE_BIT(AFF_FLAGS(ch), AFF_CHARM);
	continue;
      }

      save = SAVING_THROW(ch, SV_MAGIC);
      if (save / 10 > number(1, 100))	// broke it
       if (ch->master) {
         if (MOB_CLASS_FLAGGED(ch, MOB_UNDEAD) &&
             affected_by_spell(ch, SPELL_ANIMATE_DEAD))
           raw_kill(ch);
         else
           stop_follower(ch);
       }
    }
  }
}