SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************
 *  The MUDprograms are heavily based on the original MOBprogram code that  *
 *  was written by N'Atas-ha.											    *
 ****************************************************************************/

#include	"stdafx.h"
#include	"smaug.h"
#include	"SysData.h"
#include	"area.h"
#include	"skill.h"
#include	"mobiles.h"
#include	"objects.h"
#include	"rooms.h"
#include	"races.h"
#include	"class.h"
#include	"Exits.h"
#include	"SmaugWizDoc.h"
#include	"descriptor.h"
#include	"character.h"

char	*mprog_type_to_name (int type);
ch_ret	simple_damage (CCharacter *ch, CCharacter *victim, int dam, int dt);

char *mprog_type_to_name (int type)
{
    switch (type)
    {
	case IN_FILE_PROG:      return "in_file_prog";
	case ACT_PROG:          return "act_prog";
	case SPEECH_PROG:       return "speech_prog";
	case RAND_PROG:         return "rand_prog";
	case FIGHT_PROG:        return "fight_prog";
	case HITPRCNT_PROG:     return "hitprcnt_prog";
	case DEATH_PROG:        return "death_prog";
	case ENTRY_PROG:        return "entry_prog";
	case GREET_PROG:        return "greet_prog";
	case ALL_GREET_PROG:    return "all_greet_prog";
	case GIVE_PROG:         return "give_prog";
	case BRIBE_PROG:        return "bribe_prog";
	case HOUR_PROG:		return "hour_prog";
	case TIME_PROG:		return "time_prog";
	case WEAR_PROG:         return "wear_prog";
	case REMOVE_PROG:       return "remove_prog";
	case SAC_PROG :         return "sac_prog";
	case LOOK_PROG:         return "look_prog";
	case EXA_PROG:          return "exa_prog";
	case ZAP_PROG:          return "zap_prog";
	case GET_PROG:          return "get_prog";
	case DROP_PROG:         return "drop_prog";
	case REPAIR_PROG:       return "repair_prog";
	case DAMAGE_PROG:       return "damage_prog";
	case PULL_PROG:         return "pull_prog";
	case PUSH_PROG:         return "push_prog";
	case SCRIPT_PROG:	return "script_prog";
	case SLEEP_PROG:        return "sleep_prog";
	case REST_PROG:         return "rest_prog";
	case LEAVE_PROG:        return "leave_prog";
	case USE_PROG:          return "use_prog";
	default:                return "ERROR_PROG";
    }
}


// A trivial rehack of do_mstat.  This doesnt show all the data, but just
// enough to identify the mob and give its basic condition.  It does however,
// show the MUDprograms which are set.
void do_mpstat (CCharacter *ch, char *argument)
{
	char			arg [MAX_INPUT_LENGTH];
	CCharacter		*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("MProg stat whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (! victim->IsNpc ()) {
		ch->SendText ("Only Mobiles can have MobPrograms!\n\r");
		return;
	}

	if (victim->GetMobIndex ()->m_Progtypes.IsEmpty ()) {
		ch->SendText ("That Mobile has no Programs set.\n\r");
		return;
	}

	ch->SendTextf ("Name: %s.  Vnum: %d.\n\r",
		victim->GetName (), victim->GetMobIndex ()->vnum);

	ch->SendTextf ("Short description: %s.\n\rLong  description: %s",
		victim->GetShortDescr (),
		victim->HasLongDescription () ?
			victim->GetLongDescr () : "(none).\n\r");

	ch->SendTextf ("Hp: %d/%d.  Mana: %d/%d.  Move: %d/%d. \n\r",
		victim->GetHp (), victim->GetMaxHp (), victim->GetMana (),
		victim->GetMaxMana (), victim->GetMove (), victim->GetMaxMove ());

	ch->SendTextf (
		"Lv: %d.  Class: %d.  Align: %d.  AC: %d.  Gold: %d.  Exp: %d.\n\r",
		victim->GetLevel (), victim->GetClass (), victim->GetAlignment (),
		victim->GetAc (), victim->GetGold (), victim->GetExp ());

	CPtrList	&PList = victim->GetMobIndex ()->MobPrgList;
	POSITION	pos = PList.GetHeadPosition ();
	while (pos) {
		CMobProgData	&Mprg = *(CMobProgData*) PList.GetNext (pos);
		ch->SendTextf (">%s %s\n\r%s\n\r",
			mprog_type_to_name (Mprg.type), Mprg.arglist, Mprg.comlist);
	}
	return;
}

/* Opstat - Scryn 8/12*/
void do_opstat (CCharacter *ch, char *argument)
{
    char		arg [MAX_INPUT_LENGTH];
    CObjData	*obj;

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	ch->SendText ("OProg stat what?\n\r");
	return;
    }

    if ((obj = get_obj_world (ch, arg)) == NULL)
    {
	ch->SendText ("You cannot find that.\n\r");
	return;
    }

    if (obj->pIndexData->m_Progtypes.IsEmpty ())
    {
	ch->SendText ("That object has no programs set.\n\r");
	return;
    }

    ch->SendTextf ("Name: %s.  Vnum: %d.\n\r",
	obj->GetName (), obj->pIndexData->vnum);

    ch->SendColorf ("Short description: %s.\n\r",
	    obj->GetShortDescr ());

	CPtrList	&PList = obj->pIndexData->ObjPrgList;
	POSITION	pos = PList.GetHeadPosition ();
	while (pos) {
		CMobProgData	&Oprg = *(CMobProgData*) PList.GetNext (pos);
		ch->SendTextf (">%s %s\n\r%s\n\r",
			mprog_type_to_name (Oprg.type), Oprg.arglist, Oprg.comlist);
	}
    return;
}


/* Rpstat - Scryn 8/12 */
void do_rpstat (CCharacter *ch, char *argument)
{
    if (ch->GetInRoom ()->m_Progtypes.IsEmpty ()) {
		ch->SendText ("This room has no programs set.\n\r");
		return;
    }

    ch->SendTextf ("Name: %s.  Vnum: %d.\n\r",
		ch->GetInRoom ()->GetName (), ch->GetInRoom ()->vnum);

	CPtrList	&PList = ch->GetInRoom ()->RoomPrgList;
	POSITION	pos = PList.GetHeadPosition ();
	while (pos) {
		CMobProgData	&Rprg = *(CMobProgData*) PList.GetNext (pos);
		ch->SendColorf (">%s %s\n\r%s\n\r",
			mprog_type_to_name (Rprg.type), Rprg.arglist, Rprg.comlist);
	}
}


// Prints the argument to all the rooms around the mobile
void do_mpasound (CCharacter *ch, char *argument)
{
	CRoomIndexData	*was_in_room;
	CExitData		*pexit;

	if (! ch) {
		bug ("Nonexistent ch in do_mpasound!");
		return;
	}

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (argument [0] == '\0') {
		progbug ("Mpasound - No argument", ch);
		return;
	}

	CActFlags	actflags = ch->GetActFlags ();	// save act flags
	ch->ClrSecretive ();
	was_in_room = ch->GetInRoom ();

	for (pexit = was_in_room->first_exit; pexit; pexit = pexit->GetNext ()) {
		if (pexit->GetToRoom () && pexit->GetToRoom () != was_in_room) {
			ch->SetInRoom (pexit->GetToRoom ());
			MOBtrigger  = FALSE;
			act (AT_SAY, argument, ch, NULL, NULL, TO_ROOM);
		}
	}
	ch->SetActFlags (actflags);					// restore act flags
	ch->SetInRoom (was_in_room);
}


// Woowoo - Blodkai, November 1997
void do_mpasupress (CCharacter* ch, char* argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	int			rnds;

	if (! ch->IsNpc () || ch->IsCharmed ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	if (arg1 [0] == '\0') {
		ch->SendText ("Mpasupress who?\n\r");
		progbug ("Mpasupress:  invalid argument", ch );
		return;
	}

	if (arg2 [0] == '\0') {
		ch->SendText ("Supress their attacks for how many rounds?\n\r");
		progbug ("Mpasupress:  invalid argument", ch);
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("No such victim in the room.\n\r");
		progbug ("Mpasupress:  victim not present", ch);
		return;
	}

	rnds = atoi (arg2);
	if (rnds < 0 || rnds > 32000) {
		ch->SendText ("Invalid number of rounds to supress attacks.\n\r");
		progbug ("Mpsupress:  invalid argument", ch);
		return;
	}

	add_timer (victim, TIMER_ASUPRESSED, rnds, NULL, 0);   
}


// lets the mobile kill any player or mobile without murder
void do_mpkill (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	if (! ch->IsNpc () || ch->IsCharmed ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (! ch) {
		bug ("Nonexistent ch in do_mpkill!");
		return;
	}

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		progbug ("MpKill - no argument", ch);
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		progbug ("MpKill - Victim not in room", ch);
		return;
	}

	if (victim == ch) {
		progbug ("MpKill - Bad victim to attack", ch);
		return;
	}

	if (ch->IsCharmed () && ch->GetMaster () == victim) {
		progbug ("MpKill - Charmed mob attacking master", ch);
		return;
	}

	if (ch->IsFightPosition ()) {
		progbug ("MpKill - Already fighting", ch);
		return;
	}

	multi_hit (ch, victim, TYPE_UNDEFINED);
}


// lets the mobile destroy an object in its inventory
// it can also destroy a worn object and it can destroy
// items using all.xxxxx or just plain all of them
void do_mpjunk (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		progbug ("Mpjunk - No argument", ch);
		return;
	}

	if (str_cmp (arg, "all") && str_prefix ("all.", arg)) {
		if (obj = get_obj_wear (ch, arg)) {
			unequip_char (ch, obj);
			extract_obj (obj);
			return;
		}
		if ((obj = get_obj_carry (ch, arg)) == NULL)
			return;
		extract_obj (obj);
	} else {
		POSITION	pos = ch->GetHeadCarryPos ();
		while (obj = ch->GetNextCarrying (pos)) {
			if (arg [3] == '\0' || is_name (&arg [4], obj->GetName ())) {
				if (obj->wear_loc != WEAR_NONE)
					unequip_char (ch, obj);
				extract_obj (obj);
			}
		}
	}
}


/*
 * This function examines a text string to see if the first "word" is a
 * color indicator (e.g. _red, _whi_, _blu).  -  Gorog
 */
int get_color (char *argument)    /* get color code from command string */ 
{ 
   char color[MAX_INPUT_LENGTH]; 
   const char *cptr; 
   static char const * color_list= 
         "_bla_red_dgr_bro_dbl_pur_cya_cha_dch_ora_gre_yel_blu_pin_lbl_whi"; 
   static char const * blink_list= 
         "*bla*red*dgr*bro*dbl*pur*cya*cha*dch*ora*gre*yel*blu*pin*lbl*whi"; 
        
   one_argument (argument, color); 
   if (color[0]!='_' && color[0]!='*') return 0;
   if ((cptr = strstr (color_list, color))) 
     return (cptr - color_list) / 4; 
   if ((cptr = strstr (blink_list, color))) 
     return (cptr - blink_list) / 4 + AT_BLINK; 
   return 0; 
} 

 
// prints the message to everyone in the room other than the mob and victim
void do_mpechoaround (CCharacter *ch, char *argument)
{
	char		arg[ MAX_INPUT_LENGTH ];
	CCharacter	*victim;
	short		color;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		progbug ("Mpechoaround - No argument", ch);
		return;
	}

	if (! (victim = get_char_room (ch, arg))) {
		progbug ("Mpechoaround - victim does not exist", ch);
		return;
	}

	CActFlags	actflags = ch->GetActFlags ();
	ch->ClrSecretive ();

	if ((color = get_color (argument))) {
		argument = one_argument (argument, arg);
		act (color, argument, ch, NULL, victim, TO_NOTVICT);
	}
	else
		act (AT_ACTION, argument, ch, NULL, victim, TO_NOTVICT);

	ch->SetActFlags (actflags);
}


// prints message only to victim 
void do_mpechoat (CCharacter *ch, char *argument)
{
	char		arg[ MAX_INPUT_LENGTH ];
	CCharacter	*victim;
	short		color;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0' || argument [0] == '\0') {
		progbug ("Mpechoat - No argument", ch);
		return;
	}

	if (! (victim = get_char_room (ch, arg))) {
		CString	s;
		s.Format ("Mpechoat - victim does not exist: %s", arg);
		progbug (s, ch);
		return;
	}

	CActFlags	actflags = ch->GetActFlags ();
	ch->ClrSecretive ();

	if ((color = get_color (argument))) {
		argument = one_argument (argument, arg);
		act (color, argument, ch, NULL, victim, TO_VICT);
	}
	else
		act (AT_ACTION, argument, ch, NULL, victim, TO_VICT);

	ch->SetActFlags (actflags);
}
 

// prints message to room at large.
void do_mpecho (CCharacter *ch, char *argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	short	color;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (argument [0] == '\0') {
		progbug ("Mpecho - called w/o argument", ch);
		return;
	}

	CActFlags	actflags = ch->GetActFlags ();
	ch->ClrSecretive ();

	if ((color = get_color (argument))) {
		argument = one_argument (argument, arg1);
		act (color, argument, ch, NULL, NULL, TO_ROOM);
	}
	else
		act (AT_ACTION, argument, ch, NULL, NULL, TO_ROOM);

	ch->SetActFlags (actflags);
}


/* lets the mobile load an item or mobile.  All items
are loaded into inventory.  you can specify a level with
the load object portion as well. */

void do_mpmload (CCharacter *ch, char *argument)
{
    char            arg[ MAX_INPUT_LENGTH ];
    CMobIndexData *pMobIndex;
    CCharacter      *victim;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    one_argument (argument, arg);

    if (arg[0] == '\0' || !is_number (arg))
    {
	progbug ("Mpmload - Bad vnum as arg", ch);
	return;
    }

    if ((pMobIndex = MobTable.GetMob (atoi (arg))) == NULL)
    {
	progbug ("Mpmload - Bad mob vnum", ch);
	return;
    }

    victim = create_mobile (pMobIndex);
    victim->SendToRoom (ch->GetInRoom ());
    return;
}

void do_mpoload (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    CObjIndexData *pObjIndex;
    CObjData       *obj;
    int             level;
    int		    timer = 0;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);

    if (arg1[0] == '\0' || !is_number (arg1))
    {
	progbug ("Mpoload - Bad syntax", ch);
	return;
    }

    if (arg2[0] == '\0')
	level = ch->GetTrustLevel ();
    else
    {
	/*
	 * New feature from Alander.
	 */
	if (!is_number (arg2))
	{
	    progbug ("Mpoload - Bad level syntax", ch);
	    return;
	}
	level = atoi (arg2);
	if (level < 0 || level > ch->GetTrustLevel ())
	{
	    progbug ("Mpoload - Bad level", ch);
	    return;
	}

	/*
	 * New feature from Thoric.
	 */
	timer = atoi (argument);
	if (timer < 0)
	{
	   progbug ("Mpoload - Bad timer", ch);
	   return;
	}
    }

    if ((pObjIndex = OIdxTable.GetObj (atoi (arg1))) == NULL)
    {
	progbug ("Mpoload - Bad vnum arg", ch);
	return;
    }

    obj = create_object (pObjIndex, level);
    obj->timer = timer;
    if (obj->CanWear (ITEM_TAKE))
	obj_to_char (obj, ch);
    else
	obj_to_room (obj, ch->GetInRoom ());

    return;
}


// Just a hack of do_pardon from act_wiz.c -- Blodkai, 6/15/97
void do_mppardon (CCharacter* ch, char* argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	if (ch->IsNpc () || ch->IsCharmed ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}


	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	if (arg1 [0] == '\0' || arg2 [0] == '\0') {
		progbug ("Mppardon:  missing argument", ch);
		ch->SendText ("Mppardon who for what?\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		progbug ("Mppardon: offender not present", ch);
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		progbug ("Mppardon:  trying to pardon NPC", ch);
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (! str_cmp (arg2, "attacker")) {
		if (victim->IsAttacker ()) {
			victim->ClrAttacker ();
			ch->SendText ("Attacker flag removed.\n\r");
			victim->SendText ("Your crime of attack has been pardoned.\n\r");
		}
		return;
	}

	if (! str_cmp (arg2, "killer")) {
		if (victim->IsKiller ()) {
			victim->ClrKiller ();
			ch->SendText ("Killer flag removed.\n\r");
			victim->SendText ("Your crime of murder has been pardoned.\n\r");
		}
		return;
	}

	if (! str_cmp (arg2, "litterbug")) {
		if (victim->IsLitterBug ()) {
			victim->ClrLitterBug ();
			ch->SendText ("Litterbug flag removed.\n\r");
			victim->SendText ("Your crime of littering has been pardoned./n/r");
		}
		return;
	}

	if (! str_cmp (arg2, "thief")) {
		if (victim->IsThief ()) {
			victim->ClrThief ();
			ch->SendText ("Thief flag removed.\n\r");
			victim->SendText ("Your crime of theft has been pardoned.\n\r");
		}
		return;
	}

	ch->SendText ("Pardon who for what?\n\r");
	progbug ("Mppardon: Invalid argument", ch);
}


/* lets the mobile purge all objects and other npcs in the room,
   or purge a specified object or mob in the room.  It can purge
   itself, but this had best be the last command in the MUDprogram
   otherwise ugly stuff will happen */

void do_mppurge (CCharacter *ch, char *argument)
{
    char       arg[ MAX_INPUT_LENGTH ];
    CCharacter *victim;
    CObjData  *obj;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	/* 'purge' */
	CCharacter *vnext;

	for (victim = ch->GetInRoom ()->first_person; victim; victim = vnext)
	{
	    vnext = victim->GetNextInRoom ();
	    if (victim->IsNpc () && victim != ch)
	      extract_char (victim, TRUE);
	}
	while (! ch->GetInRoom ()->IsEmpty ())
	   extract_obj (ch->GetInRoom ()->GetFirstContent ());

	return;
    }

    if ((victim = get_char_room (ch, arg)) == NULL)
    {
	if ((obj = get_obj_here (ch, arg)) != NULL)
	    extract_obj (obj);
	else
	    progbug ("Mppurge - Bad argument", ch);
	return;
    }

    if (!victim->IsNpc ())
    {
	progbug ("Mppurge - Trying to purge a PC", ch);
	return;
    }

    if (victim == ch)
    {
    	progbug ("Mppurge - Trying to purge oneself", ch);
    	return;
    }

    if (victim->IsNpc () && victim->GetMobIndex ()->vnum == 3)
    {
        progbug ("Mppurge: trying to purge supermob", ch);
	return;
    }
    
    extract_char (victim, TRUE);
    return;
}


/* Allow mobiles to go wizinvis with programs -- SB */
 
void do_mpinvis (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    short level;
 
    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
 
    argument = one_argument (argument, arg);
    if (arg && arg[0] != '\0')
    {
        if (!is_number (arg))
        {
           progbug ("Mpinvis - Non numeric argument ", ch);
           return;
        }       
        level = atoi (arg);
        if (level < 2 || level > 51)
        {
            progbug ("MPinvis - Invalid level ", ch);
            return;
        }
 
	ch->SetMobInvisLevel (level);
	ch->SendTextf ("Mobinvis level set to %d.\n\r", level);
	return;
    }
 
    if (ch->GetMobInvisLevel () < 2)
      ch->SetMobInvisLevel (ch->GetLevel ());
 
    if (ch->IsAction (ACT_MOBINVIS))
    {
        ch->ClrActBit (ACT_MOBINVIS);
	act (AT_IMMORT, "$n slowly fades into existence.", ch, NULL, NULL,TO_ROOM);
	ch->SendText ("You slowly fade back into existence.\n\r");       
    }
    else
    {
        ch->SetActBit (ACT_MOBINVIS);
	act (AT_IMMORT, "$n slowly fades into thin air.", ch, NULL, NULL, TO_ROOM);
        ch->SendText ("You slowly vanish into thin air.\n\r");
    }
    return;
}

/* lets the mobile goto any location it wishes that is not private */

void do_mpgoto (CCharacter *ch, char *argument)
{
    char             arg[ MAX_INPUT_LENGTH ];
    CRoomIndexData *location;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    one_argument (argument, arg);
    if (arg[0] == '\0')
    {
	progbug ("Mpgoto - No argument", ch);
	return;
    }

    if ((location = find_location (ch, arg)) == NULL)
    {
	progbug ("Mpgoto - No such location", ch);
	return;
    }

    if (ch->GetFightData ())
	stop_fighting (ch, TRUE);

    ch->RemoveFromRoom ();
    ch->SendToRoom (location);

    return;
}

/* lets the mobile do a command at another location. Very useful */

void do_mpat (CCharacter *ch, char *argument)
{
    char             arg[ MAX_INPUT_LENGTH ];
    CRoomIndexData *location;
    CRoomIndexData *original;
    CCharacter       *wch;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg);

    if (arg[0] == '\0' || argument[0] == '\0')
    {
	progbug ("Mpat - Bad argument", ch);
	return;
    }

    if ((location = find_location (ch, arg)) == NULL)
    {
	progbug ("Mpat - No such location", ch);
	return;
    }

    original = ch->GetInRoom ();
    ch->RemoveFromRoom ();
    ch->SendToRoom (location);
    interpret (ch, argument);

    /*
     * See if 'ch' still exists before continuing!
     * Handles 'at XXXX quit' case.
     */
    for (wch = first_char; wch; wch = wch->GetNext ())
	if (wch == ch)
	{
	    ch->RemoveFromRoom ();
	    ch->SendToRoom (original);
	    break;
	}

    return;
}

/* allow a mobile to advance a player's level... very dangerous */
void do_mpadvance (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CCharacter *victim;
    int level;
    int iLevel;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || ch->GetDesc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	progbug ("Mpadvance - Bad syntax", ch);
	return;
    }

    if ((victim = get_char_room (ch, arg)) == NULL)
    {
	progbug ("Mpadvance - Victim not there", ch);
	return;
    }

    if (victim->IsNpc ())
    {
	progbug ("Mpadvance - Victim is NPC", ch);
	return;
    }

    if (victim->GetLevel () >= LEVEL_AVATAR)
      return;

	level = victim->GetLevel () + 1;

	if (victim->GetLevel () > ch->GetLevel ())
	{
	  act (AT_TELL, "$n tells you, 'Sorry... you must seek someone more powerful than I.'",
	       ch, NULL, victim, TO_VICT);
	  return;
	}

	if (victim->GetLevel () >= LEVEL_AVATAR)
	{
	  set_char_color (AT_IMMORT, victim);
	  act (AT_IMMORT, "$n makes some arcane gestures with $s hands, then points $s fingers at you!",
	       ch, NULL, victim, TO_VICT);
	  act (AT_IMMORT, "$n makes some arcane gestures with $s hands, then points $s fingers at $N!",
	       ch, NULL, victim, TO_NOTVICT);
	  set_char_color (AT_WHITE, victim);
	  victim->SendText ("You suddenly feel very strange...\n\r\n\r");
	  set_char_color (AT_LBLUE, victim);
	}

	switch (level)
	{
	default:
	  victim->SendText ("You feel more powerful!\n\r");
	  break;
	case LEVEL_IMMORTAL:
	  do_help (victim, "M_GODLVL1_");
	  set_char_color (AT_WHITE, victim);
	  victim->SendText ("You awake... all your possessions are gone.\n\r");

	  while (victim->IsCarrying ())
	    extract_obj (victim->GetFirstCarrying ());
	  break;
	case LEVEL_ACOLYTE:
	  do_help (victim, "M_GODLVL2_");
	  break;
	case LEVEL_CREATOR:
	  do_help (victim, "M_GODLVL3_");
	  break;
	case LEVEL_SAVIOR:
	  do_help (victim, "M_GODLVL4_");
	  break;
	case LEVEL_DEMI:
	  do_help (victim, "M_GODLVL5_");
	  break;
	case LEVEL_TRUEIMM:
	  do_help (victim, "M_GODLVL6_");
	  break;
	case LEVEL_LESSER:
	  do_help (victim, "M_GODLVL7_");
	  break;
	case LEVEL_GOD:
	  do_help (victim, "M_GODLVL8_");
	  break;
	case LEVEL_GREATER:
	  do_help (victim, "M_GODLVL9_");
	  break;
	case LEVEL_ASCENDANT:
	  do_help (victim, "M_GODLVL10_");
	  break;
	case LEVEL_SUB_IMPLEM:
	  do_help (victim, "M_GODLVL11_");
	  break;
	case LEVEL_IMPLEMENTOR:
	  do_help (victim, "M_GODLVL12_");
	  break;
	case LEVEL_ETERNAL:
	  do_help (victim, "M_GODLVL13_");
	  break;
	case LEVEL_INFINITE:
	  do_help (victim, "M_GODLVL14_");
	  break;
	case LEVEL_SUPREME:
	  do_help (victim, "M_GODLVL15_");
	}

    for (iLevel = victim->GetLevel () ; iLevel < level; iLevel++)
    {
	if (level < LEVEL_IMMORTAL)
	  victim->SendText ("You raise a level!!  ");
	victim->AddLevel (1);
	advance_level (victim);
    }
    victim->SetExp (1000 * UMAX (1, victim->GetLevel ()));
    victim->SetTrust (0);
}



/* lets the mobile transfer people.  the all argument transfers
   everyone in the current room to the specified location */

void do_mptransfer (CCharacter *ch, char *argument)
{
    char             arg1[ MAX_INPUT_LENGTH ];
    char             arg2[ MAX_INPUT_LENGTH ];
    char buf[MAX_STRING_LENGTH];
    CRoomIndexData *location;
    CCharacter       *victim;
    CCharacter       *nextinroom;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);

    if (arg1[0] == '\0')
    {
	progbug ("Mptransfer - Bad syntax", ch);
	return;
    }

    /* Put in the variable nextinroom to make this work right. -Narn */
    if (!str_cmp (arg1, "all"))
    {
	for (victim = ch->GetInRoom ()->first_person; victim; victim = nextinroom)
	{
            nextinroom = victim->GetNextInRoom ();
	    if (victim != ch
	    &&   victim->IsAuthed ()
	    &&   can_see (ch, victim))
	    {
		sprintf (buf, "%s %s", victim->GetName (), arg2);
		do_mptransfer (ch, buf);
	    }
	}
	return;
    }

	// Thanks to Grodyn for the optional location parameter.
	CString		s;
	if (arg2 [0] == '\0')
		location = ch->GetInRoom ();
	else {
		s.Format ("Mptransfer - No such location: %s", arg2);
		if ((location = find_location (ch, arg2)) == NULL) {
			progbug (s, ch);
			return;
		}

		if (room_is_private (location)) {
			progbug ("Mptransfer - Private room", ch);
			return;
		}
	}

	if ((victim = get_char_world (ch, arg1)) == NULL) {
		s.Format ("Mptransfer - No such person: %s", arg1);
		progbug (s, ch);
		return;
	}

	if (! victim->GetInRoom ()) {
		progbug ("Mptransfer - Victim in Limbo", ch);
		return;
	}

	if (! victim->IsAuthed () && location->GetArea () != victim->GetInRoom ()->GetArea ()) {
		s.Format ("Mptransfer - transferring unauthorized player: %s", arg1);
		progbug (s, ch);
		return;
	}


	// If victim not in area's level range, do not transfer
	if (!in_hard_range (victim, location->GetArea ()) 
		&& ! location->IsPrototype ())
			return;

	if (victim->GetFightData ())
		stop_fighting (victim, TRUE);

	victim->RemoveFromRoom ();
	victim->SendToRoom (location);
}


// lets the mobile force someone to do something.  must be mortal level
// and the all argument only affects those in the room with the mobile
void do_mpforce (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];
	CString	s;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc () || ch->GetDesc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0' || argument [0] == '\0') {
		progbug ("Mpforce - Bad syntax, no argument", ch);
		return;
	}

	if (! str_cmp (arg, "all")) {
		CCharacter	*vch = ch->GetInRoom ()->first_person;

		for ( ; vch; vch = vch->GetNextInRoom ())
			if (vch->GetTrustLevel () < ch->GetTrustLevel ()
				&& can_see (ch, vch))
					interpret (vch, argument);
	} else {
		CCharacter	*victim;

		if ((victim = get_char_room (ch, arg)) == NULL) {
			s.Format ("Mpforce - No such victim: %s", arg);
			progbug (s, ch);
			return;
		}

		if (victim == ch) {
			progbug ("Mpforce - Forcing oneself", ch);
			return;
		}

		if (! victim->IsNpc ()
		  && (! victim->GetDesc ())
		  && victim->IsImmortal ()) {
			s.Format ("Mpforce - Attempting to force link dead immortal: %s", arg);
			progbug (s, ch);
			return;
		}

		interpret (victim, argument);
	}
}


// mpbodybag for mobs to do cr's  --Shaddai
void do_mpbodybag (CCharacter* ch, char* argument)
{
	CCharacter	*victim;
	CObjData	*obj;
	char	arg [MAX_STRING_LENGTH];
	char	buf2 [MAX_STRING_LENGTH];
	char	buf3 [MAX_STRING_LENGTH];


	if (! ch->IsNpc () || ch->GetDesc () || ch->IsCharmed ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		progbug ("Mpbodybag - called w/o enough arguments", ch);
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("Victim must be in room.\n\r");
		progbug ("Mpbodybag: victim not in room", ch);
		return;
	}

	if (victim->IsNpc ()) {
		progbug ("Mpbodybag: bodybagging a npc corpse", ch);
		return;
	}

	sprintf (buf2, "the corpse of %s", arg);
	int		count = 0;

	CObjIndexData	&Idx = *OIdxTable.Find (OBJ_VNUM_CORPSE_PC);
	if (! &Idx)
		bug ("do_bodybag: No object index for OBJ_VNUM_CORPSE_PC.");

	else {
		POSITION	pos = Idx.m_ObjList.GetHeadPosition ();
		while (pos) {
			obj = Idx.m_ObjList.GetNext (pos);
			if (obj->in_room && !str_cmp (buf2, obj->GetShortDescr ())) {
				obj_from_room (obj); 
				obj = obj_to_char (obj, ch);
				obj->timer = -1;
				++count;
			}
		}
	}

	// Maybe should just make the command logged... Shrug I am not sure
	// --Shaddai
	if (count) {
		sprintf (buf3, "Mpbodybag: Grabbed %s (%d)", buf2, count);
		progbug (buf3, ch);
	}
}


// syntax:  mppractice victim spell_name max%
void do_mp_practice (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		arg3 [MAX_INPUT_LENGTH];
	char		buf [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	int			sn, max, tmp, adept;
	char		*skill_name;

	if (ch->IsCharmed ())
		return;

	if (! ch->IsNpc ()) {		// security breach, i guess
		ch->SendText ("Huh?\n\r");
		return;
	}

	argument = one_argument (argument, arg1);  
	argument = one_argument (argument, arg2);  
	argument = one_argument (argument, arg3);  

	if (arg1 [0] == '\0' || arg2 [0] == '\0' || arg3 [0] == '\0') {
		ch->SendText ("Mppractice: bad syntax");
		progbug ("Mppractice - Bad syntax", ch);
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("Mppractice: Student not in room? Invis?");
		progbug ("Mppractice: Invalid student not in room", ch);
		return;
	}

	if ((sn = SkillTable.Lookup (arg2)) < 0) {
		ch->SendText ("Mppractice: Invalid spell/skill name");
		progbug ("Mppractice: Invalid spell/skill name", ch);
		return;
	}


	if (victim->IsNpc ()) {
		ch->SendText ("Mppractice: Can't train a mob");
		progbug ("Mppractice: Can't train a mob", ch);
		return;
	}

	skill_name = SkillTable.GetName (sn);

	max = atoi (arg3);
	if ((max<0) || (max>100)) {
		sprintf (log_buf, "mp_practice: Invalid maxpercent: %d", max);
		ch->SendText (log_buf);
		progbug (log_buf, ch);
		return;
	}

	if (victim->GetLevel () < SkillTable.GetClassLevel (sn,
	  victim->GetClass ())) {
		sprintf (buf, "$n attempts to tutor you in %s, but it's beyond "
			"your comprehension.", skill_name);
		act (AT_TELL, buf, ch, NULL, victim, TO_VICT);
		return;
	}

	// adept is how high the player can learn it
	adept = SkillTable.GetClassAdept (sn, victim->GetClass ());

	if ((victim->GetPcData ()->learned[sn] >= adept)
	  || (victim->GetPcData ()->learned[sn] >= max)) {
		sprintf (buf, "$n shows some knowledge of %s, but yours is "
			"clearly superior.", skill_name);
		act (AT_TELL, buf, ch, NULL, victim, TO_VICT);
		return;
	}


	// past here, victim learns something
	tmp = UMIN (victim->GetPcData ()->learned[sn] +
		int_app [victim->GetIntelligence ()].learn, max);
	act (AT_ACTION, "$N demonstrates $t to you.  You feel more learned "
		"in this subject.", victim, SkillTable.GetName (sn), ch,TO_CHAR);

	victim->GetPcData ()->learned [sn] = max; 


	if (victim->GetPcData ()->learned[sn] >= adept) {
		victim->GetPcData ()->learned[sn] = adept;
		act (AT_TELL,
			"$n tells you, 'You have learned all I know on this subject...'",
			ch, NULL, victim, TO_VICT);
	}
}


/*
 * syntax: mpslay (character)
 */
void do_mp_slay (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    CCharacter *victim;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || ch->GetDesc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
    argument = one_argument (argument, arg1);  
    if (arg1[0] == '\0')
    {
       ch->SendText ("mpslay whom?\n\r");
       progbug ("Mpslay: invalid (nonexistent?) argument", ch);
       return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        ch->SendText ("Victim must be in room.\n\r");
        progbug ("Mpslay: victim not in room", ch);
	return;
    }

    if (victim == ch)
    {
        ch->SendText ("You try to slay yourself.  You fail.\n\r");
        progbug ("Mpslay: trying to slay self", ch);
	return;
    }

    if (victim->IsNpc () && victim->GetMobIndex ()->vnum == 3)
    {
        ch->SendText ("You cannot slay supermob!\n\r");
        progbug ("Mpslay: trying to slay supermob", ch);
	return;
    }

    if (victim->GetLevel () < LEVEL_IMMORTAL)
    {
       act (AT_IMMORT, "You slay $M in cold blood!",  ch, NULL, victim, TO_CHAR);
       act (AT_IMMORT, "$n slays you in cold blood!", ch, NULL, victim, TO_VICT);
       act (AT_IMMORT, "$n slays $N in cold blood!",  ch, NULL, victim, TO_NOTVICT);
       set_cur_char (victim);
       raw_kill (ch, victim);
       stop_fighting (ch, FALSE);
       stop_hating (ch);
       stop_fearing (ch);
       stop_hunting (ch);
    } 
    else 
    {
       act (AT_IMMORT, "You attempt to slay $M and fail!",  ch, NULL, victim, TO_CHAR);
       act (AT_IMMORT, "$n attempts to slay you.  What a kneebiter!", ch, NULL, victim, TO_VICT);
       act (AT_IMMORT, "$n attempts to slay $N.  Needless to say $e fails.",  ch, NULL, victim, TO_NOTVICT);
    }
    return;
}

/*
 * syntax: mpdamage (character) (#hps)
 */
void do_mp_damage (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    CCharacter *victim;
    int dam;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
    argument = one_argument (argument, arg1);  
    argument = one_argument (argument, arg2);  

    if (arg1[0] == '\0')
    {
       ch->SendText ("mpdamage whom?\n\r");
       progbug ("Mpdamage: invalid argument1", ch);
       return;
    }

    if (arg2[0] == '\0')
    {
       ch->SendText ("mpdamage inflict how many hps?\n\r");
       progbug ("Mpdamage: invalid argument2", ch);
       return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        ch->SendText ("Victim must be in room.\n\r");
        progbug ("Mpdamage: victim not in room", ch);
	return;
    }

    if (victim == ch)
    {
        ch->SendText ("You can't mpdamage yourself.\n\r");
        progbug ("Mpdamage: trying to damage self", ch);
	return;
    }

    dam = atoi (arg2);

    if ((dam<0) || (dam>32000))
    {
       ch->SendText ("Mpdamage how much?\n\r");
       progbug ("Mpdamage: invalid (nonexistent?) argument", ch);
       return;
    }

   /* this is kinda begging for trouble        */
   /*
    * Note from Thoric to whoever put this in...
    * Wouldn't it be better to call damage (ch, ch, dam, dt)?
    * I hate redundant code
    */
    if (simple_damage (ch, victim, dam, TYPE_UNDEFINED) == rVICT_DIED) 
    {
	stop_fighting (ch, FALSE);
	stop_hating (ch);
	stop_fearing (ch);
	stop_hunting (ch);
    }

    return;
}


/*
 * syntax: mprestore (character) (#hps)                Gorog
 */
void do_mp_restore (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    CCharacter *victim;
    int hp;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
    argument = one_argument (argument, arg1);  
    argument = one_argument (argument, arg2);  

    if (arg1[0] == '\0')
    {
       ch->SendText ("mprestore whom?\n\r");
       progbug ("Mprestore: invalid argument1", ch);
       return;
    }

    if (arg2[0] == '\0')
    {
       ch->SendText ("mprestore how many hps?\n\r");
       progbug ("Mprestore: invalid argument2", ch);
       return;
    }

    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        ch->SendText ("Victim must be in room.\n\r");
        progbug ("Mprestore: victim not in room", ch);
	return;
    }

    hp = atoi (arg2);

    if ((hp<0) || (hp>32000))
    {
       ch->SendText ("Mprestore how much?\n\r");
       progbug ("Mprestore: invalid (nonexistent?) argument", ch);
       return;
    }
    hp += victim->GetHp ();
    victim->SetHp ((hp > 32000 || hp < 0 || hp > victim->GetMaxHp ()) ?
                  victim->GetMaxHp () : hp);
}

/*
 * Syntax mpfavor target number
 * Raise a player's favor in progs.
 */
void  do_mpfavor (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    CCharacter *victim;
    int favor;
 
    if (ch->IsCharmed ())
      return;
 
    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
        ch->SendText ("Huh?\n\r");
        return;
    }
    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);

    if (arg1[0] == '\0')
    {
       ch->SendText ("mpfavor whom?\n\r");
       progbug ("Mpfavor: invalid argument1", ch);
       return;
    }
 
    if (arg2[0] == '\0')
    {
       ch->SendText ("mpfavor how much favor?\n\r");
       progbug ("Mpfavor: invalid argument2", ch);
       return;
    }
 
    if ((victim = get_char_room (ch, arg1)) == NULL)
    {
        ch->SendText ("Victim must be in room.\n\r");
        progbug ("Mpfavor: victim not in room", ch);
        return;
    }
 
    favor = atoi (arg2);
    victim->GetPcData ()->favor = URANGE (-1000, victim->GetPcData ()->favor + favor, 1000);
} 

/*
 * Syntax mp_open_passage x y z
 *
 * opens a 1-way passage from room x to room y in direction z
 *
 *  won't mess with existing exits
 */
void do_mp_open_passage (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    char arg3[ MAX_INPUT_LENGTH ];
    CRoomIndexData *targetRoom, *fromRoom;
    int targetRoomVnum, fromRoomVnum, exit_num;
    CExitData *pexit;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg1);  
    argument = one_argument (argument, arg2);  
    argument = one_argument (argument, arg3);  

    if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    if (!is_number (arg1))
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    fromRoomVnum = atoi (arg1);
    if ( (fromRoom = RoomTable.GetRoom (fromRoomVnum))  ==NULL)
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    if (!is_number (arg2))
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    targetRoomVnum = atoi (arg2);
    if ( (targetRoom = RoomTable.GetRoom (targetRoomVnum))  ==NULL)
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    if (!is_number (arg3))
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    exit_num = atoi (arg3);
    if ((exit_num < 0) || (exit_num > MAX_DIR))
    {
	progbug ("MpOpenPassage - Bad syntax", ch);
	return;
    }

    if ((pexit = get_exit (fromRoom, exit_num)) != NULL)
    {
	if (! pexit->IsPassage ())
	  return;
	progbug ("MpOpenPassage - Exit exists", ch);
	return;
    }

    pexit = make_exit (fromRoom, targetRoom, exit_num);
    pexit->keyword = STRALLOC ("");
    pexit->description = STRALLOC ("");
    pexit->key = -1;
    pexit->SetPassage ();

    /* act (AT_PLAIN, "A passage opens!", ch, NULL, NULL, TO_CHAR); */
    /* act (AT_PLAIN, "A passage opens!", ch, NULL, NULL, TO_ROOM); */

    return;
}

/*
 * Syntax mp_close_passage x y 
 *
 * closes a passage in room x leading in direction y
 *
 * the exit must have EX_PASSAGE set
 */
void do_mp_close_passage (CCharacter *ch, char *argument)
{
    char arg1[ MAX_INPUT_LENGTH ];
    char arg2[ MAX_INPUT_LENGTH ];
    char arg3[ MAX_INPUT_LENGTH ];
    CRoomIndexData *fromRoom;
    int fromRoomVnum, exit_num;
    CExitData *pexit;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg1);  
    argument = one_argument (argument, arg2);  
    argument = one_argument (argument, arg3);  

    if (arg1[0] == '\0' || arg2[0] == '\0' || arg2[0] == '\0')
    {
	progbug ("MpClosePassage - Bad syntax", ch);
	return;
    }

    if (!is_number (arg1))
    {
	progbug ("MpClosePassage - Bad syntax", ch);
	return;
    }

    fromRoomVnum = atoi (arg1);
    if ( (fromRoom = RoomTable.GetRoom (fromRoomVnum))  ==NULL)
    {
	progbug ("MpClosePassage - Bad syntax", ch);
	return;
    }

    if (!is_number (arg2))
    {
	progbug ("MpClosePassage - Bad syntax", ch);
	return;
    }

    exit_num = atoi (arg2);
    if ((exit_num < 0) || (exit_num > MAX_DIR))
    {
	progbug ("MpClosePassage - Bad syntax", ch);
	return;
    }

    if ((pexit = get_exit (fromRoom, exit_num)) == NULL)
    {
	  return;    /* already closed, ignore...  so rand_progs */
		     /*                            can close without spam */
    }

    if (! pexit->IsPassage ())
    {
	progbug ("MpClosePassage - Exit not a passage", ch);
	return;
    }

    extract_exit (fromRoom, pexit);

    /* act (AT_PLAIN, "A passage closes!", ch, NULL, NULL, TO_CHAR); */
    /* act (AT_PLAIN, "A passage closes!", ch, NULL, NULL, TO_ROOM); */

    return;
}



/*
 * Does nothing.  Used for scripts.
 */
void do_mpnothing (CCharacter *ch, char *argument)
{
    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }
    return;
}


/*
 *   Sends a message to sleeping character.  Should be fun
 *    with room sleep_progs
 *
 */
void do_mpdream (CCharacter *ch, char *argument)
{
    char arg1[MAX_STRING_LENGTH];
    CCharacter *vict;

    if (ch->IsCharmed ())
      return;

    if (!ch->IsNpc () || (ch->GetDesc () && ch->GetTrustLevel () < LEVEL_IMMORTAL) )
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    argument = one_argument (argument, arg1);  

    if ( (vict =get_char_world (ch, arg1)) == NULL)
    {
        progbug ("Mpdream: No such character", ch);
        return;
    }
    
    if (vict->GetPosition () <= POS_SLEEPING)
    {
      vict->SendText (argument);
      vict->SendText ("\n\r");
    } 
    return;
}


void do_mpapply (CCharacter *ch, char *argument)
{
	CCharacter	*victim;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (argument [0] == '\0') {
		progbug ("Mpapply - bad syntax", ch);
		return;
	}

	if ((victim = get_char_room (ch, argument)) == NULL) {
		progbug ("Mpapply - no such player in room.", ch);
		return;
	}

	if (! victim->GetDesc ()) {
		ch->SendText ("Not on linkdeads.\n\r");
		return;
	}

	if (victim->IsAuthed ())
		return;

	if (victim->GetPcData ()->auth_state >= 1)
		return;

	sprintf (log_buf, "%s%s new %s %s applying for authorization...", 
		victim->GetName (), victim->GetDesc ()->m_pHost, 
		RaceTable.GetName (victim->GetRace ()), 
		ClassTable.GetName (victim->GetClass ()));

	gpDoc->LogString (log_buf);
	to_channel (log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL);
	victim->GetPcData ()->auth_state = 1;
}


void do_mpapplyb (CCharacter *ch, char *argument)
{
	CCharacter	*victim;

	if (! ch->IsNpc ()) {
		ch->SendText ("Huh?\n\r");
		return;
	}

	if (argument [0] == '\0') {
		progbug ("Mpapplyb - bad syntax", ch);
		return;
	}

	if ((victim = get_char_room (ch, argument)) == NULL) {
		progbug ("Mpapplyb - no such player in room.", ch);
		return;
	}

	if (! victim->GetDesc ()) {
		ch->SendText ("Not on linkdeads.\n\r");
		return;
	}

	if (victim->IsAuthed ())
		return;

	if (get_timer (victim, TIMER_AUTH) >= 1)
		return;

	int		delay = SysData.m_AuthDelay / 3;

	switch (victim->GetPcData ()->auth_state) {
	  case 0:
	  case 1:   
	  default:
		victim->SendTextf ("You attempt to regain the gods' attention.\n\r");
		sprintf (log_buf, "%s%s new %s %s applying for authorization...",                      
			victim->GetName (), victim->GetDesc ()->m_pHost,
			RaceTable.GetName (victim->GetRace ()), 
			ClassTable.GetName (victim->GetClass ()));
		gpDoc->LogString (log_buf);
		to_channel (log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL);

		if (SysData.IsAutoAuth ())
			add_timer (victim, TIMER_DO_FUN, delay, do_AutoAuthorize, 0);
		else
			add_timer (victim, TIMER_AUTH, delay, NULL, 0);
		victim->GetPcData ()->auth_state = 1;
		break; 

	  case 2:
		victim->SendText ("Your name has been deemed unsuitable by the gods.  Please choose a more medieval name with the 'name' command.\n\r");
		add_timer (victim, TIMER_AUTH, delay, NULL, 0);
		break;

	  case 3:
		victim->SendTextf ("The gods permit you to enter the %s.\n\r",
			SysData.GetLongTitle ());  
		victim->ClrUnauthed ();
		if (victim->GetFightData ())
			stop_fighting (victim, TRUE);
		victim->RemoveFromRoom ();
		victim->SendToRoom (RoomTable.GetRoom (SysData.m_RoomSchool));
		act (AT_WHITE, "$n enters this world from within a column of blinding light!",
		victim, NULL, NULL, TO_ROOM);
		do_look (victim, "auto");
		break;
	}
}

/*
 * Deposit some gold into the current area's economy		-Thoric
 */
void do_mp_deposit (CCharacter *ch, char *argument)
{
    char arg[MAX_STRING_LENGTH];
    int gold;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	progbug ("Mpdeposit - bad syntax", ch);
	return;
    }
    gold = atoi (arg);
    if (gold <= ch->GetGold () && ch->GetInRoom ())
    {
	ch->AddGold (-gold);
	ch->GetInRoom ()->GetArea ()->BoostEconomy (gold);
    }
}


/*
 * Withdraw some gold from the current area's economy		-Thoric
 */
void do_mp_withdraw (CCharacter *ch, char *argument)
{
    char arg[MAX_STRING_LENGTH];
    int gold;

    if (!ch->IsNpc ())
    {
	ch->SendText ("Huh?\n\r");
	return;
    }

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	progbug ("Mpwithdraw - bad syntax", ch);
	return;
    }
    gold = atoi (arg);
    if (ch->GetGold () < 1000000000 && gold < 1000000000 && ch->GetInRoom ()
    &&   ch->GetInRoom ()->GetArea ()->CheckGold (gold))
    {
	ch->AddGold (gold);
	ch->GetInRoom ()->GetArea ()->LowerEconomy (gold);
    }
}


void do_mppkset (CCharacter *ch, char *argument)
{
  CCharacter *victim;
  char arg[MAX_STRING_LENGTH];

  if (!ch->IsNpc ())
  {
    ch->SendText ("Huh?\n\r");
    return;
  }

  argument = one_argument (argument, arg);

  if (argument[0] == '\0' || arg[0] == '\0')
  {
    progbug ("Mppkset - bad syntax", ch);
    return;
  }

  if ((victim = get_char_room (ch, arg)) == NULL)
  {
    progbug ("Mppkset - no such player in room.", ch);
    return;
  }

	if (!str_cmp (argument, "yes") || !str_cmp (argument, "y")) {
		if (! victim->IsPkiller ())
			victim->SetPkiller ();
	}
	else if (!str_cmp (argument, "no") || !str_cmp (argument, "n")) {
		if (victim->IsPkiller ())
			victim->ClrPkiller ();
	}
	else progbug ("Mppkset - bad syntax", ch);
}



/*
 * Inflict damage from a mudprogram
 *
 *  note: should be careful about using victim afterwards
 */
ch_ret simple_damage (CCharacter *ch, CCharacter *victim, int dam, int dt)
{
    short dameq;
    BOOL npcvict;
    CObjData *damobj;
    ch_ret retcode;


    retcode = rNONE;

    if (!ch)
    {
	bug ("Damage: null ch!", 0);
	return rERROR;
    }
    if (!victim)
    {
	progbug ("Damage: null victim!", ch);
	return rVICT_DIED;
    }

    if (victim->GetPosition () == POS_DEAD)
    {
	return rVICT_DIED;
    }

    npcvict = victim->IsNpc ();

    if (dam)
    {
	if (IS_FIRE (dt))
	  dam = ris_damage (victim, dam, RIS_FIRE);
	else
	if (IS_COLD (dt))
	  dam = ris_damage (victim, dam, RIS_COLD);
	else
	if (IS_ACID (dt))
	  dam = ris_damage (victim, dam, RIS_ACID);
	else
	if (IS_ELECTRICITY (dt))
	  dam = ris_damage (victim, dam, RIS_ELECTRICITY);
	else
	if (IS_ENERGY (dt))
	  dam = ris_damage (victim, dam, RIS_ENERGY);
	else
	if (dt == gsn_poison)
	  dam = ris_damage (victim, dam, RIS_POISON);
	else
	if (dt == (TYPE_HIT + 7) || dt == (TYPE_HIT + 8))
	  dam = ris_damage (victim, dam, RIS_BLUNT);
	else
	if (dt == (TYPE_HIT + 2) || dt == (TYPE_HIT + 11))
	  dam = ris_damage (victim, dam, RIS_PIERCE);
	else
	if (dt == (TYPE_HIT + 1) || dt == (TYPE_HIT + 3))
	  dam = ris_damage (victim, dam, RIS_SLASH);
	if (dam < 0)
	  dam = 0;
    }

    if (victim != ch)
    {
	/*
	 * Damage modifiers.
	 */
	if (victim->HasSanctuary ())
	    dam /= 2;

	if (victim->IsAffected (AFF_PROTECT) && ch->IsEvil ())
	    dam -= (int) (dam / 4);

	if (dam < 0)
	    dam = 0;

	/* dam_message (ch, victim, dam, dt); */
    }

    /*
     * Check for EQ damage.... ;)
     */

    if (dam > 10)
    {
	/* get a random body eq part */
	dameq  = number_range (WEAR_LIGHT, WEAR_EYES);
	damobj = get_eq_char (victim, dameq);
	if (damobj)
	{
	  if (dam > get_obj_resistance (damobj))
	  {
	     set_cur_obj (damobj);
	     damage_obj (damobj);
	  }
	}
    }

   /*
    * Hurt the victim.
    * Inform the victim of his new state.
    */
    victim->AddHp (-dam);
    if (!victim->IsNpc ()
    &&   victim->GetLevel () >= LEVEL_IMMORTAL
    &&   victim->GetHp () < 1)
    victim->SetHp (1);

    if (!npcvict
    &&   victim->GetTrustLevel () >= LEVEL_IMMORTAL
    &&	 ch->GetTrustLevel () >= LEVEL_IMMORTAL
    &&   victim->GetHp () < 1)
	victim->SetHp (1);
    update_pos (victim);

    switch (victim->GetPosition ())
    {
    case POS_MORTAL:
    act (AT_DYING, "$n is mortally wounded, and will die soon, if not aided.",
	    victim, NULL, NULL, TO_ROOM);
    act (AT_DANGER, "You are mortally wounded, and will die soon, if not aided.",
	victim, NULL, NULL, TO_CHAR);
	break;

    case POS_INCAP:
    act (AT_DYING, "$n is incapacitated and will slowly die, if not aided.",
	    victim, NULL, NULL, TO_ROOM);
    act (AT_DANGER, "You are incapacitated and will slowly die, if not aided.",
	victim, NULL, NULL, TO_CHAR);
	break;

    case POS_STUNNED:
        if (! victim->IsParalysed ())
        {
    act (AT_ACTION, "$n is stunned, but will probably recover.",
	    victim, NULL, NULL, TO_ROOM);
    act (AT_HURT, "You are stunned, but will probably recover.",
	victim, NULL, NULL, TO_CHAR);
	}
	break;

    case POS_DEAD:
    act (AT_DEAD, "$n is DEAD!!", victim, 0, 0, TO_ROOM);
    act (AT_DEAD, "You have been KILLED!!\n\r", victim, 0, 0, TO_CHAR);
	break;

    default:
	if (dam > victim->GetMaxHp () / 4)
	act (AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR);
	if (victim->GetHp () < victim->GetMaxHp () / 4)
	act (AT_DANGER, "You wish that your wounds would stop BLEEDING so much!",
	 victim, 0, 0, TO_CHAR);
	break;
    }

    /*
     * Payoff for killing things.
     */
    if (victim->GetPosition () == POS_DEAD)
    {
	if (!npcvict)
	{
	    sprintf (log_buf, "%s killed by %s at %d",
		victim->GetName (),
		 (ch->IsNpc () ? ch->GetShortDescr () : ch->GetName ()),
		victim->GetInRoom ()->vnum);
	    gpDoc->LogString (log_buf);
	    to_channel (log_buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL);

	    /*
	     * Dying penalty:
	     * 1/2 way back to previous level.
	     */
	    if (victim->GetExp () > exp_level (victim, victim->GetLevel ()))
		gain_exp (victim, (exp_level (victim, victim->GetLevel ()) - victim->GetExp ())/2);

	    /*
	     * New penalty... go back to the beginning of current level.
	     victim->GetExp () = exp_level (victim, victim->GetLevel ());
	     */
	}
	set_cur_char (victim);
	raw_kill (ch, victim);
	victim = NULL;

	return rVICT_DIED;
    }

    if (victim == ch)
	return rNONE;

    /*
     * Take care of link dead people.
     */
    if (!npcvict && !victim->GetDesc ())
    {
	if (number_range (0, victim->GetWait ()) == 0)
	{
	    do_recall (victim, "");
	    return rNONE;
	}
    }

    /*
     * Wimp out?
     */
    if (npcvict && dam > 0)
    {
	if ((victim->IsWimpy () && number_bits (1) == 0
	&&   victim->GetHp () < victim->GetMaxHp () / 2)
	||   (victim->IsCharmed () && victim->GetMaster ()
	&&     victim->GetMaster ()->GetInRoom () != victim->GetInRoom ()))
	{
	    start_fearing (victim, ch);
	    stop_hunting (victim);
	    do_flee (victim, "");
	}
    }

    if (!npcvict
    &&   victim->GetHp () > 0
    &&   victim->GetHp () <= victim->GetWimpLevel ()
    &&   victim->GetWait () == 0)
	do_flee (victim, "");
    else
    if (!npcvict && victim->IsAction (PLR_FLEE))
	do_flee (victim, "");

    return rNONE;
}