/* ************************************************************************
*  file: spec_other.c , Special module.                   Part of DIKUMUD *
*  Usage: Procedures handling special procedures for object/room/mobile   *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */

#include <stdio.h>
#include <strings.h>
#include <ctype.h>

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "limits.h"

/*   external vars  */

extern struct room_data *world;
extern struct zone_data *zone_table;
extern struct char_data *character_list;
extern struct descriptor_data *descriptor_list;
extern struct index_data *obj_index;
extern struct time_info_data time_info;
extern struct title_type titles[4][28];
extern char *command[];

/* extern procedures */

void hit(struct char_data *ch, struct char_data *victim, int type);
void gain_exp(struct char_data *ch, int gain);
char *strdup(char *source);


/* Room_Proc */
int arena_guard(int room, struct char_data *ch, int cmd, char *arg)
{
	char buf[256], buf2[256];

	if ((cmd!=3 || !ch || ch->in_room!=real_room(3703)) &&
			(cmd!=1 || ch->in_room!=real_room(3702)))
		return FALSE;
	if (IS_NPC(ch)) {
		return FALSE;
	}

	strcpy(buf,  "The Arena Gods prevent you from entering since you're an outlaw.\n\r");
	strcpy(buf2, "The Arena Gods prevent the outlaw, $n, from entering.");

	if ((ch->in_room == real_room(3702)) && (cmd == 1)) {/*BLUE room*/
		if (IS_SET(ch->specials.act,PLR_OUTLAW)||
		    IS_SET(ch->specials.act,PLR_ISTHIEF)||
		    IS_SET(ch->specials.act,PLR_ISKILLER)) {
			act(buf2, FALSE, ch, 0, 0, TO_ROOM);
			send_to_char(buf, ch);
			return TRUE;
		}

		if (ch->specials.arena!=ARENA_BLUE_PLR) {
			act("The Arena Gods bar $n's way since this is the BLUE team's exit\n\r",FALSE,ch,0,0,TO_ROOM);
			send_to_char("You can't enter the ARENA here without the BLUE team color!\n\r",ch);
			return TRUE;
		}

	} else if ((ch->in_room == real_room(3703)) && (cmd == 3)) { /*RED*/
		if (IS_SET(ch->specials.act,PLR_OUTLAW)||
		    IS_SET(ch->specials.act,PLR_ISTHIEF)||
		    IS_SET(ch->specials.act,PLR_ISKILLER)) {
			act(buf2, FALSE, ch, 0, 0, TO_ROOM);
			send_to_char(buf, ch);
			return TRUE;
		}
		if (ch->specials.arena!=ARENA_RED_PLR) {
			act("The Arena Gods bar $n's way since this is the RED team's entrance.\n\r",FALSE,ch,0,0,TO_ROOM);
			send_to_char("You can't enter the ARENA here without the RED team color!\n\r",ch);
			return TRUE;
		}
	}
	/* Save stats so we can restore them when you leave the Arena */
	ch->specials.arena_move=GET_MOVE(ch);
	ch->specials.arena_mana=GET_MANA(ch);
	ch->specials.arena_hits=GET_HIT(ch);
	ch->tmp_affected=ch->affected;
	ch->affected=NULL;
	ch->specials.arena_affvector=ch->specials.affected_by;
	ch->specials.affected_by=NULL;
	return FALSE;

}

/* Mob proc */
int brass_dragon(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	char buf[256], buf2[256];

	if (cmd>6 || cmd<1)
		return FALSE;

	strcpy(buf,  "The brass dragon humiliates you, and blocks your way.\n\r");
	strcpy(buf2, "The brass dragon humiliates $n, and blocks $s way.");

	if ((ch->in_room == real_room(5065)) && (cmd == 4)) {
		act(buf2, FALSE, pl, 0, 0, TO_ROOM);
		send_to_char(buf, pl);
		return TRUE;
	}

	return FALSE;

}

int puff(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	void do_say(struct char_data *ch, char *argument, int cmd);

	if (cmd)
		return(0);

	switch (number(0, 60))
	{
		case 0:
			do_say(ch, "My god! It's full of stars!", 0);
		   return(1);
		case 1:
			do_say(ch, "How'd all those fish get up here?", 0);
			return(1);
		case 2:
			do_say(ch, "I'm a very female dragon.", 0);
			return(1);
		case 3:
			do_say(ch, "I've got a peaceful, easy feeling.", 0);
			return(1);
		default:
			return(0);
	}
}
					
int janitor(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	struct obj_data *i, *temp, *next_obj;

	if (cmd || !AWAKE(ch))
		return(FALSE);

	for (i = world[ch->in_room].contents; i; i = i->next_content) {
		if (IS_SET(i->obj_flags.wear_flags, ITEM_TAKE) && 
      ((i->obj_flags.type_flag == ITEM_DRINKCON) ||
		  (i->obj_flags.cost <= 20))) {
			act("$n picks up some trash.", FALSE, ch, 0, 0, TO_ROOM);

			obj_from_room(i);
			obj_to_char(i, ch);
			return(TRUE);
		}
	}
	return(FALSE);
}


int cityguard(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	struct char_data *tch, *evil;
	int max_evil;

	if (cmd || !AWAKE(ch) || (GET_POS(ch) == POSITION_FIGHTING))
		return (FALSE);

	max_evil = 1000;
	evil = 0;

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

	if (evil && (GET_ALIGNMENT(evil->specials.fighting) >= 0)) {
		act("$n screams 'PROTECT THE INNOCENT!  BANZAI!!! CHARGE!!! ARARARAGGGHH!'", FALSE, ch, 0, 0, TO_ROOM);
		hit(ch, evil, TYPE_UNDEFINED);
		return(TRUE);
	}

	for(tch=world[ch->in_room].people; tch; tch=tch->next_in_room) {
		if (!IS_NPC(tch) && CAN_SEE(ch, tch) &&
		    (IS_SET(tch->specials.act,PLR_ISKILLER)||
 		     IS_SET(tch->specials.act,PLR_ISTHIEF))){
			act("$n screams 'Outlaw! Fresh blood! Kill!'", FALSE, ch, 0, 0, TO_ROOM);
			hit(ch, tch, TYPE_UNDEFINED);
			return(TRUE);
		}
	}
		
	return(FALSE);
}

#define PER_LEVEL	10	/* coins per level needed to play in arena */

int arena_shop(int room, struct char_data *ch, int cmd, char *arg)
{
	char buf[MAX_STRING_LENGTH];
	int gold_needed;

	gold_needed=GET_LEVEL(ch)*PER_LEVEL;

	if (cmd==59) { /* List */
		send_to_char("Your choice of team colors are:\n\r", ch);
		send_to_char("\n\rRED\n\rBLUE\n\r\n\r",ch);
		send_to_char("You may JOIN RED, or JOIN BLUE\n\r\n\r",ch);
		send_to_char("No outlaws are allowed in the Holy Arena\n\r",ch);
		sprintf(buf,"It will cost you %d coins to join a team.\n\r",
			gold_needed);
		send_to_char(buf,ch);
		return(TRUE);
	} else if (cmd==228) { /* JOIN */

		if(IS_SET(ch->specials.act,PLR_ISTHIEF)||
		   IS_SET(ch->specials.act,PLR_ISKILLER)){
			send_to_char("The Arena Gods forbid outlaws from joining!\n\r",ch);
			return(FALSE);
		}

		arg = one_argument(arg, buf);
		if(!strcmp(buf,"red")&&!strcmp(buf,"blue")) {
			send_to_char("You can only join a RED or BLUE team.\n\r",ch);
			return(TRUE);
		}

		if(GET_GOLD(ch)<gold_needed){
			sprintf(buf,"You need %d coins to join!! Go away\n\r",
				gold_needed);
			send_to_char(buf,ch);
			return(TRUE);
		}

		if (!strcmp(buf,"red")) {
			ch->specials.arena=ARENA_RED_PLR;
			send_to_char("You are now a member of the RED team!\n\r",ch);
			return(TRUE);
		}

		if (!strcmp(buf,"blue")) {
			ch->specials.arena=ARENA_BLUE_PLR;
			send_to_char("You are now a member of the BLUE team!\n\r",ch);
			return(TRUE);
		}

		send_to_char("The Gods decree that you may only join red or blue teams!\n\r",ch);
		return(TRUE);
			
	}

	/* All commands except list and buy */
	return(FALSE);
}

/* Idea of the LockSmith is functionally similar to the Pet Shop */
/* The problem here is that each key must somehow be associated  */
/* with a certain player. My idea is that the players name will  */
/* appear as the another Extra description keyword, prefixed     */
/* by the words 'item_for_' and followed by the player name.     */
/* The (keys) must all be stored in a room which is (virtually)  */
/* adjacent to the room of the lock smith.                       */

int pray_for_items(int room, struct char_data *ch, int cmd, char *arg)
{
  char buf[256];
  int key_room, gold;
  bool found;
  struct obj_data *obj;
  struct extra_descr_data *ext;

  if (cmd != 176) /* You must pray to get the stuff */
	return FALSE;

  key_room = 1+ch->in_room;

  strcpy(buf, "item_for_");
  strcat(buf, GET_NAME(ch));

  gold = 0;
  found = FALSE;

  for (obj=world[key_room].contents; obj && !found; obj = obj->next_content)
    for(ext = obj->ex_description; ext && !found; ext = ext->next)
      if (str_cmp(buf, ext->keyword) == 0) {
		  if (gold == 0) {
		     gold = 1;
			   act("$n kneels and at the altar and chants a prayer to Odin.",
					 FALSE, ch, 0, 0, TO_ROOM);
				act("You notice a faint light in Odin's eye.",
					 FALSE, ch, 0, 0, TO_CHAR);
		  }
	obj_from_room(obj);
	act("$p slowly fades into existence.",FALSE,ch,obj,0,TO_ROOM);
	act("$p slowly fades into existence.",FALSE,ch,obj,0,TO_CHAR);
        gold += obj->obj_flags.cost;
        obj_to_room(obj, ch->in_room);
        found = TRUE;
      }


  if (found) {
    GET_GOLD(ch) -= gold;
    GET_GOLD(ch) = MAX(0, GET_GOLD(ch));
    return TRUE;
	}

  return FALSE;
}


/* ********************************************************************
*  Special procedures for objects                                     *
******************************************************************** */



#define CHAL_ACT \
"You are torn out of reality!\n\r\
You roll and tumble through endless voids for what seems like eternity...\n\r\
\n\r\
After a time, a new reality comes into focus... you are elsewhere.\n\r"


int chalice(struct obj_data *obj, struct char_data *ch, int cmd, char *arg)
{
	/* 222 is the normal chalice, 223 is chalice-on-altar */

	struct obj_data *chalice;
	char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
	static int chl = -1, achl = -1;

	if (chl < 1)
	{
		chl = real_object(222);
		achl = real_object(223);
	}

	switch(cmd)
	{
		case 10:    /* get */
			if (!(chalice = get_obj_in_list_num(chl,
				world[ch->in_room].contents))
				&& CAN_SEE_OBJ(ch, chalice))
				if (!(chalice = get_obj_in_list_num(achl,
					world[ch->in_room].contents)) && CAN_SEE_OBJ(ch, chalice))
					return(0);
	
			/* we found a chalice.. now try to get us */			
			do_get(ch, arg, cmd);
			/* if got the altar one, switch her */
			if (chalice == get_obj_in_list_num(achl, ch->carrying))
			{
				extract_obj(chalice);
				chalice = read_object(chl, VIRTUAL);
				obj_to_char(chalice, ch);
			}
			return(1);
		break;
		case 67: /* put */
			if (!(chalice = get_obj_in_list_num(chl, ch->carrying)))
				return(0);

			argument_interpreter(arg, buf1, buf2);
			if (!str_cmp(buf1, "chalice") && !str_cmp(buf2, "altar"))
			{
				extract_obj(chalice);
				chalice = read_object(achl, VIRTUAL);
				obj_to_room(chalice, ch->in_room);
				send_to_char("Ok.\n\r", ch);
			}
			return(1);
		break;
		case 176: /* pray */
			if (!(chalice = get_obj_in_list_num(achl,
				world[ch->in_room].contents)))
				return(0);

			do_action(ch, arg, cmd);  /* pray */
			send_to_char(CHAL_ACT, ch);
			extract_obj(chalice);
			act("$n is torn out of existence!", TRUE, ch, 0, 0, TO_ROOM);
			char_from_room(ch);
			char_to_room(ch, real_room(2500),0);   /* before the fiery gates */
			do_look(ch, "", 15);
			return(1);
		break;
		default:
			return(0);
		break;
	}
}




int kings_hall(int room, struct char_data *ch, int cmd, char *arg)
{
	if (cmd != 176)
		return(0);

	do_action(ch, arg, 176);

	send_to_char("You feel as if some mighty force has been offended.\n\r", ch);
	send_to_char(CHAL_ACT, ch);
	act("$n is struck by an intense beam of light and vanishes.",
		TRUE, ch, 0, 0, TO_ROOM);
	char_from_room(ch);
	char_to_room(ch, real_room(1420),0);  /* behind the altar */
	do_look(ch, "", 15);
	return(1);
}

/* The salesman, always after a tidy profit and the satisfaction of a sale, is
   a social individual...Maybe overly so... <grin> */

int sales_spec(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
   char buf[MAX_STRING_LENGTH],
	arg1[MAX_STRING_LENGTH],arg2[MAX_STRING_LENGTH];
   int i_val = 0;
   struct obj_data *selling=0, *s_item = 0, *obj=0;
   struct char_data *c_obj=0,*k, *dummy_char, *old_follow=NULL;

   extern void do_insult(struct char_data *ch,char *argument,int cmd);
   extern void do_say(struct char_data *ch,char *argument,int cmd);

   /* Find out if we have anything to sell, either in first equipment slot */
   /* or something being carried */
#if CONFIG_JAIL
   if(witness(ch,pl,cmd,arg))
	return(TRUE);
#endif

   if (selling = ch->equipment[WIELD])
      i_val = ch->equipment[WIELD]->obj_flags.cost * 2 + 3;
   else if (selling = ch->carrying)
      i_val = ch->carrying->obj_flags.cost * 2 + 3;
   /* Handle cases where we might care what a player does: buy, steal, etc. */
   if (cmd != 0) {
      argument_interpreter(arg,arg1,arg2);
      if (*arg1) c_obj=get_char_room(arg1,ch->in_room);
      switch(cmd) {
         case 9:
         case 113:
         case 118:
         case 120:
         case 121:
         case 123:
         case 138:
         case 160:
            /* Actions of questionable intent */
            if(c_obj!=ch || GET_POS(ch)<=POSITION_SLEEPING)
               return FALSE;
            if(pl->player.sex != 2) {
               act("$N slaps you before you can even begin.",
                  FALSE,pl,0,ch,TO_CHAR);
               act("$N slaps $n for his naughty intentions.",
                  FALSE,pl,0,ch,TO_ROOM);
            }
            return TRUE;
            break;
         case 19:
            if(c_obj!=ch || GET_POS(ch)<=POSITION_SLEEPING)
               return FALSE;
            do_say(ch,"I can talk all day, but only you can buy...",0);
            return TRUE;
            break;
         case 23:
            /* The salesman suffers from acceptance anxiety :-) */
	    if(GET_POS(ch)<=POSITION_SLEEPING)
		return FALSE;
	    do_action(pl, arg1, cmd);
            act("$n smiles too, trying to join in on the fun.",
               TRUE,ch,0,0,TO_ROOM);
            return TRUE;
            break;
         case 33:
            if(c_obj!=ch || GET_POS(ch)<=POSITION_SLEEPING)
               return FALSE;
            do_insult(pl,arg,0);
            act("$N humbles you with a greater insult.",FALSE,pl,
		0,ch,TO_CHAR);
            act("$N snaps back with a greater insult.",FALSE,pl,
		0,ch,TO_ROOM);
            return TRUE;
            break;
         case 46:
            if(c_obj!=ch)
               return FALSE;
            if(GET_POS(ch) != POSITION_SLEEPING)
               act("$N is not sleeping.",FALSE,pl,0,ch,TO_CHAR);
            else {
               act("Your gentle nudging awakens $N, who yawns and clears his throat.",FALSE,pl,0,ch,TO_CHAR);
               act("$n nudges $N awake.",FALSE,pl,0,ch,TO_ROOM);
               GET_POS(ch) = POSITION_STANDING;
            }
            return TRUE;
            break;
         case 94:
            /* An exchange of poking */
            if(c_obj!=ch || GET_POS(ch)<=POSITION_SLEEPING)
               return FALSE;
	    do_action(pl, arg, 94);
	    act("$N pokes you back.",FALSE,pl,0,ch,TO_CHAR);
	    act("$N pokes $n back.",TRUE,pl,0,ch,TO_ROOM);
            return TRUE;
            break;
         case 154:
            if(c_obj!=ch || GET_POS(ch)<=POSITION_SLEEPING)
               return FALSE;
            act("Oof! $N knocks you down.",FALSE,pl,0,ch,TO_CHAR);
            act("$n tries to backstab $N who, more alert than \
he appears, slams\n\r$m down on the ground instead.",FALSE,pl,0,ch,TO_ROOM);
            do_say(ch,"I've dealt with your kind before!",0);
            GET_POS(pl) = POSITION_SITTING;
            return TRUE;
            break;
         case 56:
            /* "To buy is to be" is the salesman's motto... */
            if (strlen(arg1)==0 || GET_POS(ch)<=POSITION_SLEEPING || !selling)
		return FALSE;
            if (c_obj==ch) {
               do_say(ch,"I'm not for sale, idiot!",0);
               return TRUE;
            }
            if (!generic_find(arg1,FIND_OBJ_EQUIP,ch,&dummy_char,&s_item))
               s_item=get_obj_in_list(arg1,selling);
            if (strlen(arg2)==0) {
	       if(!get_char_room_vis(pl, "2.salesman")) {
                  if(s_item==selling) {
                     if(transact(ch,s_item,pl,i_val)) {
			if(ch->master)
	                        stop_follower(ch);
                        REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
                     }
                  } else if (s_item) {
                     sprintf(buf,"$n grins and says, 'Buy the %s \
first, and then I'll\n\rconsider selling you the %s.",selling->short_description,
s_item->short_description);
                     act(buf,FALSE,ch,0,0,TO_ROOM);
                  } else do_say(ch,"Sell you what?",0);
                  return(TRUE);
               } else if(ch==get_char_room_vis(ch,"salesman")){
                  sprintf(buf,"$n arches an eyebrow and says, 'Who \
\n\r'ya talkin' to, %s?'\n\rUse: BUY <OBJ> [FROM] <SELLER>.",pl->player.name);
                  act(buf,FALSE,ch,0,0,TO_ROOM);
               } else
                  do_say(ch,"Yeah, we can't ALL oblige you, ya know?",0);
            } else {
               if (ch == get_char_room_vis(pl,arg2)) {
                  if (s_item==selling) {
                     if(transact(ch,s_item,pl,i_val)) {
			if(ch->master)
				stop_follower(ch);
                        REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
		     }
                  } else
                     do_say(ch,"I don't have that.",0);
                  return(TRUE);
               }
            }
            break;
         default:
            return FALSE;
            break;
      }
   } else if (IS_LIGHT(ch->in_room)) {
      if (GET_POS(ch) == POSITION_SLEEPING) {
         ch->specials.position = POSITION_STANDING;
         act("$n becomes alert, ready to assault any \
unsuspecting\n\rpersons with $s salesmanship.",TRUE,ch,0,0,TO_ROOM);
      }
      if (ch->master) {
         if (!selling) {
            /* No items to sell, must have had item stolen */
            act("$n looks puzzled.",TRUE,ch,0,0,TO_ROOM);
            stop_follower(ch);
            REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
            return(FALSE);
         }
         i_val = selling->obj_flags.cost * 2 + 4;
         if (ch->master->in_room == ch->in_room) {
            if (ch->specials.spec[0] > 108) { /* Number is not fixed in stone */
               act("$n throws $s hands up in disgust.",TRUE,
                     ch,0,0,TO_ROOM);
               old_follow=ch->master;
               stop_follower(ch);
               REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
            } else {
	       if(GET_POS(ch->master)<=POSITION_SLEEPING)
			return(0);
 	       buf[0]=0;
               switch (number(0,14)) {
                  case 0:
                     act("$n says 'I tell you this $o is of the finest quality.'",FALSE,ch,selling,0,TO_ROOM);
                     break;
                  case 1:
                     sprintf(buf,"Only %d pieces of gold - a bargain!",i_val);
                     do_say(ch,buf,0);
                     break;
                  case 2:
                     buf[0]='a';
                     act("$N splutters 'You know, I have six\
 hungry wives\n\rand a child to feed...'",FALSE,pl,0,ch,TO_CHAR);
                     break;
                  case 3:
	             act("$N waves the $p in your face.",
                         FALSE,ch->master,selling,ch,TO_CHAR);
	             act("$N waves the $p in $n's face.",
                         FALSE,ch->master,selling,ch,TO_ROOM);
		     break;
		  case 4:
		     act("The salesman demonstrates the unique usefulness of the $o.",TRUE,ch,selling,0,TO_ROOM);
		     break;
		  case 5:
		     do_action(ch,"",107);
		     break;
                  default:
                     break;
               }
               if(buf[0]) {
                  act("$n tries to sell the $o to $N.",FALSE,ch,selling,ch->master,TO_NOTVICT);
                  ch->specials.spec[0] +=1;
               }
            }
         } else {
           stop_follower(ch);
           REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
	 }
      }
      if (!ch->master && !selling ) {
         SET_BIT(ch->specials.act,ACT_SCAVENGER);
         if(number(0,5)==0) act("$n scans the floor.",TRUE,ch,0,0,TO_ROOM);
      } else if(!ch->master) {
         REMOVE_BIT(ch->specials.act,ACT_SCAVENGER);
         for(k=world[ch->in_room].people;pl=k;k=k->next_in_room) {
            if (/*!IS_NPC(pl) &&*/ number(0,4)<3 && CAN_SEE(ch,pl) &&
	         !circle_follow(ch,pl)&&old_follow!=pl) {
               add_follower(ch,pl);
               SET_BIT(ch->specials.act,ACT_SENTINEL);
               sprintf(buf,"The salesman saunters up to you and says, 'Hey %s! \
Have I got a\n\rdeal for you! Take a look at this magnificent $o.\n\rIsn't it \
just a dream? And it can be yours for just %d coins!'",pl->player.name, i_val);
               act(buf,FALSE,pl,selling,0,TO_CHAR);
               act("$N makes a sales pitch to $n.",FALSE,pl,
                  0,ch,TO_ROOM);
               ch->specials.spec[0] = 100;
               break;
            }  
         }
      }
   } else if(GET_POS(ch) > POSITION_SLEEPING) {
      if(!ch->equipment[WEAR_LIGHT]) {  /* See if we have a light source */
         for(obj=ch->carrying;obj;obj=obj->next_content) {
            if(obj->obj_flags.type_flag==ITEM_LIGHT) {
	       do_grab(ch,obj->name,0);
               return(FALSE);
            }
         }
      } else {
	 do_remove(ch,obj->name,0);
	 do_drop(ch,obj->name,0);
         return(FALSE);
      }
      if(number(0,5) == 0) {
         GET_POS(ch) = POSITION_SLEEPING;
         do_say(ch,"Ah, must be time to go to bed!",0);
         act("The sounds of violent snoring filter through the area.",FALSE,
            ch,0,0,TO_ROOM);
         if (ch->master) {
            stop_follower(ch);
            REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
         }
      }
   }
   return(FALSE);
}

int jester(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	void do_say(struct char_data *ch, char *argument, int cmd);

#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if (cmd)
		return(0);

	switch (number(0, 60))
	{
		case 0:
			do_say(ch, "You are a real stinker!", 0);
		   return(1);
		case 1:
			do_say(ch, "Have you considered getting a lobotomy?", 0);
			return(1);
		case 2:
			do_say(ch, "You're as stupid as you look!", 0);
			return(1);
		case 3:
			do_say(ch, "Get a real hair-cut!", 0);
			return(1);
		case 4:
			act("$n does a backflip.",TRUE,ch,0,0,TO_ROOM);
			do_say(ch, "Ha!",0);
			return(1);
		default:
			return(0);
	}
}

int spiny(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	void do_say(struct char_data *ch, char *argument, int cmd);

	if(pl) {
		return(NULL);
	} else {
		if(GET_POS(ch)!=POSITION_FIGHTING) {
			switch(dice(3,2)) {
				case 3:
					act("$n flips onto its back...or is that its front?",TRUE,ch,0,0,TO_ROOM);
					break;
				case 4:
					act("$n makes some clicking noises.",FALSE,ch,0,0,TO_ROOM);
					break;
				default:
					break;
			}
		}
	}
}

int snowvulture(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	void do_say(struct char_data *ch, char *argument, int cmd);

	if(pl) {
		return(NULL);
	} else {
		if(GET_POS(ch)!=POSITION_FIGHTING) {
			switch(dice(3,3)) {
				case 3:
					do_say(ch,"Skaaa? reet.",0);
					break;
				case 4:
					act("$n flaps about.",FALSE,ch,0,0,TO_ROOM);
					break;
				case 5:
					devour(ch,pl,cmd,arg);
					break;
				default:
					break;
			}
		}
	}
	return(FALSE);
}


int snowbeast(struct char_data *ch, struct char_data *pl, int cmd, char *arg)
{
	void do_say(struct char_data *ch, char *argument, int cmd);

	if(pl) {
		return(NULL);
	} else {
		if(GET_POS(ch)!=POSITION_FIGHTING) {
			switch(dice(3,6)) {
				case 3:
					do_say(ch,"Yaargh, arrogha!!?!",0);
					break;
				case 4:
					do_say(ch,"Hmmph.",0);
					break;
				case 5:
					act("The snowbeast scratches itself.",TRUE,ch,0,0,TO_ROOM);
					break;
				case 6:
					act("The snowbeast stares inquisitively at a point in space.",TRUE,ch,0,0,TO_ROOM);
					break;
				default:
					break;
			}
		}
	}
	return(FALSE);
}

/* A special for each tower roof in Anapest (room-based) 
int tower(int room, struct char_data *ch, int cmd, char *arg)
{
	if(!cmd) {
		if....
			act("There is activity along the valley rim.\n\r",....);
	} else if(cmd==...look...) {
		if(*arg) {
			number = search_block(arg,t_skills,FALSE);
			if(number == -1) {

.....nasty...may need to change call with self reference like w/mobs */

/* A special for the Knife Shop Proprieter (mob-based) */
int clyde(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	char buf[MAX_STRING_LENGTH];
	if(!pl) {
		if(GET_POS(ch)!=POSITION_STANDING)
			return(FALSE);
		switch(dice(2,5)) {
			case 1:
				act("An evil grin crosses $n's face.",FALSE,ch,
					0,0,TO_ROOM);
				break;
			case 2:
				act("$n whistles a tune.",FALSE,ch,0,0,TO_ROOM);
				break;
			default:
				break;
		};
	} else if(ch->in_room==real_room(12595) && cmd==3 &&
			GET_CLASS(pl)!=CLASS_THIEF && GET_POS(ch) == 
			POSITION_STANDING) {
		act("With a gentle, but firm hand, Clyde guides you away from the curtain.",FALSE,pl,0,0,TO_CHAR);
		act("Clyde skillfully redirects $n from going behind the curtain.",FALSE,pl,0,0,TO_ROOM);
		return(TRUE);
	} else if(cmd==56 || cmd==57 || cmd==58 || cmd==59) {
		do_say(ch,"I'm not open for business right now.",0);
		/* in fact, he's never open... */
	}
	return(FALSE);
}

/* Another mob-based special... */
int waiter(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	int check1,check2,check3,check4,check5;
	char buf[MAX_STRING_LENGTH];
	struct obj_data *i;
	
#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(cmd==2 && ch->in_room==real_room(12576)) {
		check1=real_object(12530);
		check2=real_object(12531);
		check3=real_object(12532);
		check4=-1;
		check5=-1; /* For when I add other menu items */
		for(i=pl->carrying;i;i=i->next_content) {
			if(i->item_number==check1 || i->item_number==check2
                            || i->item_number==check3 || i->item_number==check4
			    || i->item_number==check5){
				act("The waiter prevents you from leaving.",
					FALSE,pl,0,0,TO_CHAR);
				act("The waiter prevents $n from leaving.",
					FALSE,pl,0,0,TO_ROOM);
				do_say(ch,"You must finish your meal here!",0);
				return(TRUE);
			}
		}
	}
	return(shop_keeper(ch,pl,cmd,arg));
}

int barmaid(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	/* Do special stuff, then call regular shop routine */
#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	return(shop_keeper(ch,pl,cmd,arg));
}

int cookie(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	/* Have him kick people he can see out through side door... */
#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(pl) {
	} else {
		switch(number(1,15)) {
			case 1:
				do_action(ch,"cookie",244);
				break;
			case 2:
				do_action(ch,"",106);
				switch(number(1,3)) {
					case 1:
						do_say(ch,"Mmm! Mammoth!",0);
						break;
					case 2:
						do_say(ch,"Mmm! Yak liver!",0);
						break;
					case 3:
						do_say(ch,"Hmm. Can't quite place that one.",0);
						break;
					default:
						break;
				}
			default:
				break;
		}
	}
	return(FALSE);
}

int neophyte(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(pl) {
		if(ch->in_room==real_room(12587)) {
		    if(cmd==4 && GET_CLASS(pl)!=CLASS_CLERIC &&
				!(pl->specials.act & PLR_ISMULTICL)) {
			do_say(ch,"Only the chosen get to see the master!",0);
			return(TRUE);
		     }
		}
	} else {
		switch(number(1,15)) {
			case 1:
				do_action(ch,"",244);
				break;
			default:
				break;
		}
	}
	return(FALSE);
}

int guru_anapest(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{ /* If in floating position, rotate, slow flips, etc... */
	struct char_data *who;
	char arg1[MAX_STRING_LENGTH],arg2[MAX_STRING_LENGTH];
	
	if(pl) {
		if(GET_POS(ch)<=POSITION_SLEEPING)
			return(FALSE);
		argument_interpreter(arg,arg1,arg2);
		who=get_char_room(arg1,ch->in_room);
		switch(cmd) {
			case 197:
				if(who==ch) {
					do_action(pl,arg,197);
					do_say(ch,"Don't worship me, for none are worthy of such respect.",0);
					return(TRUE);
				}
				break;
			case 185:
				if(who==ch) {
					do_action(pl,arg,185);
					do_action(ch,GET_NAME(pl),146);
					return(TRUE);
				};
				break;
			case 146:
				if(who==ch) {
					do_action(pl,arg,146);
					do_action(ch,GET_NAME(pl),185);
					return(TRUE);
				};
				break;
		}
	} else if(GET_POS(ch)==POSITION_FIGHTING) {
		if(GET_HIT(ch) < (GET_MAX_HIT(ch)/4)) {
			spell_teleport(GET_LEVEL(ch),ch,ch,NULL);
		}
	} else {
		switch(number(0,25)) {
			case 1:
				do_say(ch,"Existence is suffering.",0);
				break;
			case 2:
				do_say(ch,"Suffering is the end result of greed.",0);
				break;
			case 3:
				do_say(ch,"Information complicates our lives.",0);
				break;
			case 4:
				do_say(ch,"The pinnacle of existence is nothingness.",0);
				break;
			default:
				break;
		}
	}
	return(guild(ch,pl,cmd,arg));
}

int confess_figure(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(pl) {
		if(cmd==19) { /* Tell */
			return(TRUE);
		}
	} else if(GET_POS(ch)==POSITION_FIGHTING) {
		switch(number(1,11)) {
			case 1:
				do_say(ch,"I hope your conscience bothers you!",
					0);
				break;
			default:
				break;
		}
		return(FALSE);
	} else {
		if(ch->specials.spec[0]) {
		} else switch(number(1,10)) {
			case 1:
				do_action(ch,"",109);
				break;
			default:
				break;
		}
	}
	return(FALSE);
}

int taxman(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	struct char_data *who;
	char arg1[MAX_STRING_LENGTH],arg2[MAX_STRING_LENGTH];

	if(GET_POS(ch) <= POSITION_SLEEPING)
		return(FALSE);
	if(pl) {
		argument_interpreter(arg,arg1,arg2);
		who=get_char_room(arg1,ch->in_room);
		switch(cmd) {
			case 154:
				if(who==ch) {
					do_say(ch,"Oh no you don't!",0);
					do_action(ch,GET_NAME(pl),191);
				}
				break;
			default:
				break;
		}
	} else {
		switch(number(1,15)) {
			case 1:
				do_action(ch,"",26);
				break;
			default:
				break;
		}
	}
	return(FALSE);
}

int albert(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	char buf[MAX_INPUT_LENGTH];

#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(!pl) {
		if(IS_SET(ch->specials.act,ACT_SENTINEL) &&
					GET_HIT(ch)==GET_MAX_HIT(ch)) {
			if(GET_POS(ch)==POSITION_SLEEPING)
				do_wake(ch,"",0);
			else if(GET_POS(ch)<POSITION_STANDING)
				do_stand(ch,"",0);
			REMOVE_BIT(ch->specials.act,ACT_SENTINEL);
		} else if(world[ch->in_room].number==12613 ||
				world[ch->in_room].number==12614) {
			if(IS_FIGHTING(ch)) {
				do_action(ch,"",32);
				do_flee(ch,"",0);
			}
		} else if(GET_HIT(ch)!=GET_MAX_HIT(ch)) {
			strcpy(buf,"rub ring");
			command_interpreter(ch,buf);
			if(world[ch->in_room].number!=12613) {
				do_say(ch,"What happened to my ring?",0);
			} else {
				SET_BIT(ch->specials.act,ACT_SENTINEL);
			}
		}
	}
	return(FALSE);
}

int mage_anapest(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	char buf[MAX_STRING_LENGTH];
	struct char_data *who,*i,*temp;
	char arg1[MAX_STRING_LENGTH],arg2[MAX_STRING_LENGTH];

	if(GET_POS(ch) <= POSITION_SLEEPING)
		return(FALSE);
	if(pl) {
		switch(cmd) {
			case 154:
				do_action(ch,"",31);
				spell_teleport(GET_LEVEL(ch),ch,pl,NULL);
				act("She apparently doesn't like that.\n\r",
					FALSE,pl,0,0,TO_CHAR);
				return(TRUE);
				break;
			default:
				break;
		}
	} else {
		if(ch->in_room==real_room(12581)) {
			for(i=world[ch->in_room].people;i;i=temp) {
				temp=i->next_in_room;
				if(i!=ch && GET_CLASS(i) != CLASS_MAGIC_USER){
					do_say(ch,"Be gone!",0);
					/* Get rid of them */
					spell_teleport(GET_LEVEL(ch),ch,i,NULL);
				} else if(i!=ch && GET_ALIGNMENT(i) > 350) {
					sprintf(buf,"%s I don't think I like you!",i->player.name);
					do_tell(ch,buf,0);
				}
			}
		}
	}
				
	return(guild(ch,pl,cmd,arg));
}

int farmer(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	struct char_data *who;
	char arg1[MAX_STRING_LENGTH],arg2[MAX_STRING_LENGTH],*str=NULL;

#if CONFIG_JAIL
	if(witness(ch,pl,cmd,arg))
		return(TRUE);
#endif

	if(pl) {
		if(GET_POS(ch) <= POSITION_SLEEPING)
			return(FALSE);
		argument_interpreter(arg,arg1,arg2);
		who=get_char_room(arg1,ch->in_room);
		switch(cmd) {
			case 19: /* Tell */
				if(who==ch) {
					do_tell(pl,arg,cmd);
					do_action(ch,"",35);
					switch(number(1,20)) {
						case 1:
						str=" I ain't got no problem with that - it's your opinion.";
							break;
						case 2:
						str=" Hehehe.";
							break;
						case 3:
						str=" You're just SO much smarter than simple little farmers like us...NOT!";
							break;
						default:
							break;
					}
					if(str) {
						arg2[0]=0;
						strcat(arg2,GET_NAME(pl));
						strcat(arg2,str);
						do_tell(ch,arg2,0);
					}
				}
		}
	} else {
		switch(number(1,13)) {
			case 1:
				do_action(ch,"",198);
				break;
			case 2:
				if(world[ch->in_room].room_flags & INDOORS)
					do_say(ch,"Ya know, I really like being outside.",0);
				else {
					act("$n examines the ground for its agricultural potential.",TRUE,ch,0,0,TO_ROOM);
					if(world[ch->in_room].sector_type<=SECT_CITY)
						do_say(ch,"Pbbbbbt!",0);
				}
				break;
			default:
				break;
		}
	}
	return(FALSE);
}

int phalanx(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	struct obj_data *obj;
	sh_int temp=0,temp2=0;

	if(cmd < 0) {
		obj=read_object(12000,VIRTUAL);
		act("BOOM! $n explodes, leaving a $o, which\n\rfalls toward the ground, sparkling along the way.\n\r",FALSE,ch,obj,0,TO_ROOM);
		obj_to_room(obj,ch->in_room);
		return(FALSE);
	}
	if(pl) {
		if(cmd==5 && pl!=ch) {
			act("$n whirrs around the ceiling.",TRUE,ch,0,0,TO_ROOM);
			act("$N is preventing you.",FALSE,pl,0,ch,TO_CHAR);
			return(TRUE);
		}
	} else {
		if(GET_POS(ch)==POSITION_FIGHTING) {
			if((GET_HIT(ch) < (GET_MAX_HIT(ch)/4)) && 
					(ch->in_room!=real_room(12144))) {
				temp=ch->in_room;
				do_move(ch,"",5);
				if(ch->in_room!=temp) {
					temp2=ch->in_room;
					char_from_room(ch);
					char_to_room(ch,temp,0);
					act("$n retreats upward.",TRUE,ch,0,0,TO_ROOM);
					ch->points.hit += ch->points.hit;
					char_from_room(ch);
					char_to_room(ch,temp2,0);
					act("$n has arrived.",TRUE,ch,0,0,TO_ROOM);
				}
			}
		} else if(ch->points.armor==0) {
			act("$n forms a new configuration.",TRUE,ch,0,0,TO_ROOM);
			ch->points.armor=-50;
		} else {
			switch(dice(3,7)) {
				case 20:
				act("$n splits apart to reorganize.",TRUE,ch,
					0,0,TO_ROOM);
				ch->points.armor=0;
				break;
				case 19:
				act("$n makes some crackling noises.",
					FALSE,ch,0,0,TO_ROOM);
				break;
				case 7:
				act("A spark emanates from the interior of $n.",
					FALSE,ch,0,0,TO_ROOM);
				break;
				default:
				break;
			}
		}
	}
	return(FALSE);
}

int skeleton(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	struct char_data *temp;

	if(cmd<0) {
		if(!ch->specials.spec[0])
			ch->specials.spec[0]=3;
		else if(!--ch->specials.spec[0])
			return(FALSE);
			
		temp=read_mobile(ch->nr,REAL);
		if(temp) {
			char_to_room(temp,ch->in_room,0);
			temp->specials.spec[0]=ch->specials.spec[0];
		}
		temp=read_mobile(ch->nr,REAL);
		if(temp) {
			char_to_room(temp,ch->in_room,0);
			temp->specials.spec[0]=ch->specials.spec[0];
		}
		act("The bones of the skeleton split apart and reform into two new skeletons.",TRUE,ch,0,0,TO_ROOM);
	}
	return(FALSE);
}

/* item proc */
int crystal_spike(struct obj_data *obj,struct char_data *ch,int cmd,char *arg)
{
	int pos=-1,i;

	if(!ch)
		return(FALSE);

	if(!obj->equipped_by)
		return(FALSE);

	for(i=0;i<MAX_WEAR;i++)
		if(obj->equipped_by->equipment[i]==obj)
			pos=i;
	if(pos==-1)
		return(FALSE);

	if(cmd && obj->equipped_by==ch) {
		if(cmd==84) { /* Cast */
			obj->obj_flags.value[0]--;
			if(obj->obj_flags.value[0] < 1) {
				act("Your $p fades slowly, and disappears into nothing.",FALSE,obj->equipped_by,obj,0,TO_CHAR);
				act("$n's $p fades slowly, and disappears into nothing.",FALSE,obj->equipped_by,obj,0,TO_ROOM);
				unequip_char(obj->equipped_by,pos);
				extract_obj(obj);
			}
		}
	}
	return(FALSE);
}

int spore_ball(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	struct char_data *k;

	if(cmd==-1) {
		act("$n crumples, a noxious gas escaping its interior.",FALSE,ch,0,0,TO_ROOM);
		if(is_in_safe(ch))
			act("The gas dissipates harmlessly.",FALSE,ch,0,0,TO_ROOM);
		else
			for(k=world[ch->in_room].people;k;k=k->next_in_room)
				if(k!=ch)
					spell_poison(24,ch,k,0);
	}
	return(FALSE);
}

int bridge_troll(struct char_data *ch,struct char_data *pl,int cmd,char *arg)
{
	int gold;
	struct char_data *k,*save;

	if(pl) {
		if(cmd==72) { /* give */
			gold=GET_GOLD(ch);
			do_give(pl,arg,cmd);
			if(gold=GET_GOLD(ch)-gold) {
				if(gold<500)
					do_say(ch,"You STILL need to pay me 500 gold, pal.",0);
				else {
					do_action(ch,GET_NAME(pl),23);/*smile*/
					k=world[ch->in_room].people;
					while(k!=ch && k!=pl && k)
						k=k->next_in_room;
					if(!k) { /* Should not happen! */
						log("Troll error 1!");
						return(TRUE);
					}
					act("$N picks you and tosses you to the other side of the bridge!",FALSE,pl,0,ch,TO_CHAR);
					act("$N throws $n to the other side of the bridge!",TRUE,pl,0,ch,TO_NOTVICT);
					char_from_room(pl);
					if(k==ch)
						char_to_room(pl,real_room(14236),0);
					else
						char_to_room(pl,real_room(14238),2);
					act("$n lands in a pile here from the direction of the bridge!",TRUE,pl,0,0,TO_ROOM);
					GET_POS(pl)==POSITION_SITTING;
					do_look(pl,"",0);
				}
			}
			return(TRUE);
		}
	} else {
		ch->specials.spec[0]++;
		if(ch->specials.spec[0]==6) {
			ch->specials.spec[0]=0;
			GET_HIT(ch)=MIN(GET_HIT(ch)+6,hit_limit(ch));
		}
	}
	return(FALSE);
}

/* Pi's room proc */
struct obj_data *find_key(struct char_data *ch, int key)
{
	struct obj_data *o, *tar_obj;
	tar_obj=0;
  if(!has_key(ch,key)) return(0);
	for(o=ch->carrying; o; o=o->next_content)
	if(obj_index[o->item_number].virtual==key)
		tar_obj=o;
	if(ch->equipment[HOLD])
		if(obj_index[ch->equipment[HOLD]->item_number].virtual == key)
			tar_obj=ch->equipment[HOLD];
  return(tar_obj);
}

int feed_lock(int room,struct char_data *ch, int cmd, char *arg)
{	
	void do_unlock(struct char_data *ch, char *argument, int cmd);
	struct obj_data *obj;
	int door;
	char type[100], dir[100];

	if (cmd!=102) return FALSE;

	if (cmd==102) { /*Unlock*/
		argument_interpreter(arg, type, dir);
		if (!(door = find_door(ch, type, dir))) return FALSE; 
		if (!(obj=find_key(ch, EXIT(ch,door)->key))) return FALSE;  
  		if (IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED)) {
		  do_unlock(ch,arg,cmd);
		  act("The Lock says 'yummie... I like to eat keys.'\n\rthe Lock looks at the key.\n\rthe Lock grins evily.\n\r\n\r",TRUE,ch,obj,0,TO_ROOM);
 		  act("The Lock says 'yummie... I like to eat keys.'\n\rthe Lock looks at the key.\n\rthe Lock grins evily.\n\r\n\r",TRUE,ch,obj,0,TO_CHAR);
 		  act("Hey!. The Lock has eaten $p.\n\r",TRUE,ch,obj,0,TO_ROOM);
		  act("Hey!. The Lock has eaten your key!.\n\r",TRUE,ch,obj,0,TO_CHAR);
		  act("The Lock says 'mo food ..mo food.. I'm still hungry'\n\r",TRUE,ch,obj,0,TO_ROOM); 
		  act("The Lock says 'mo food ..mo food.. I'm still hungry'\n\r",TRUE,ch,obj,0,TO_CHAR); 

		  if ((ch->equipment[HOLD]) && (ch->equipment[HOLD]==obj))
			unequip_char(ch, HOLD);
		  extract_obj(obj); 
		  return TRUE;
		}
		return FALSE;
	}
	return FALSE;
}