wileymud-1.187b/
wileymud-1.187b/attic/
wileymud-1.187b/attic/bin/
wileymud-1.187b/attic/lib/
wileymud-1.187b/attic/lib/adm/
wileymud-1.187b/attic/lib/man/
wileymud-1.187b/attic/lib/new-wld/
wileymud-1.187b/attic/lib/new-wld/default/
wileymud-1.187b/attic/lib/old/
wileymud-1.187b/attic/lib/wld/
wileymud-1.187b/attic/public_html/
wileymud-1.187b/attic/public_html/gfx/
wileymud-1.187b/attic/src/bin/
wileymud-1.187b/attic/src/etc/
wileymud-1.187b/attic/src/libauth-4.0-p5/
wileymud-1.187b/attic/src/sedna/
wileymud-1.187b/backups/
wileymud-1.187b/bin/
wileymud-1.187b/docs/
wileymud-1.187b/etc/
wileymud-1.187b/lib/
wileymud-1.187b/lib/adm/
wileymud-1.187b/lib/boards/
wileymud-1.187b/lib/log/
wileymud-1.187b/lib/man/
wileymud-1.187b/lib/ply/
wileymud-1.187b/lib/ply/a/
wileymud-1.187b/lib/ply/b/
wileymud-1.187b/lib/ply/c/
wileymud-1.187b/lib/ply/d/
wileymud-1.187b/lib/ply/g/
wileymud-1.187b/lib/ply/k/
wileymud-1.187b/lib/ply/m/
wileymud-1.187b/lib/ply/s/
wileymud-1.187b/lib/ply/t/
wileymud-1.187b/public_html/gfx/
wileymud-1.187b/src/bin/
wileymud-1.187b/src/convert/attic/
wileymud-1.187b/src/convert/obj/
wileymud-1.187b/src/convert/perl/
wileymud-1.187b/src/convert/perl/MudConvert/
wileymud-1.187b/src/convert/perl/MudConvert/DUMP/
wileymud-1.187b/src/convert/perl/MudConvert/Report/
wileymud-1.187b/src/convert/perl/MudConvert/WileyMUD/
wileymud-1.187b/src/convert/perl/output/
wileymud-1.187b/src/convert/perl/output/DUMP/
wileymud-1.187b/src/convert/perl/output/Report/
wileymud-1.187b/src/convert/perl/output/WileyMUD/
wileymud-1.187b/src/etc/
wileymud-1.187b/src/etc/init.d/
wileymud-1.187b/src/etc/rc.d/
wileymud-1.187b/src/etc/rc.d/init.d/
wileymud-1.187b/src/lib/
wileymud-1.187b/src/lib/adm/
wileymud-1.187b/src/lib/boards/
wileymud-1.187b/src/lib/log/
wileymud-1.187b/src/lib/man/
wileymud-1.187b/src/lib/ply/
wileymud-1.187b/src/lib/ply/a/
wileymud-1.187b/src/lib/ply/b/
wileymud-1.187b/src/lib/ply/c/
wileymud-1.187b/src/lib/ply/d/
wileymud-1.187b/src/lib/ply/e/
wileymud-1.187b/src/lib/ply/f/
wileymud-1.187b/src/lib/ply/g/
wileymud-1.187b/src/lib/ply/h/
wileymud-1.187b/src/lib/ply/i/
wileymud-1.187b/src/lib/ply/j/
wileymud-1.187b/src/lib/ply/k/
wileymud-1.187b/src/lib/ply/l/
wileymud-1.187b/src/lib/ply/m/
wileymud-1.187b/src/lib/ply/n/
wileymud-1.187b/src/lib/ply/o/
wileymud-1.187b/src/lib/ply/p/
wileymud-1.187b/src/lib/ply/q/
wileymud-1.187b/src/lib/ply/r/
wileymud-1.187b/src/lib/ply/s/
wileymud-1.187b/src/lib/ply/t/
wileymud-1.187b/src/lib/ply/u/
wileymud-1.187b/src/lib/ply/v/
wileymud-1.187b/src/lib/ply/w/
wileymud-1.187b/src/lib/ply/x/
wileymud-1.187b/src/lib/ply/y/
wileymud-1.187b/src/lib/ply/z/
wileymud-1.187b/src/obj/
wileymud-1.187b/src/utils/
wileymud-1.187b/src/utils/mobmaker/
/*
 * file: act.movement.c , Implementation of commands      Part of DIKUMUD
 * Usage : Movement commands, close/open & lock/unlock doors.
 * Copyright (C) 1990, 1991 - see 'license.doc' for complete information.
 */

#include <stdio.h>
#include <stdlib.h>
/* #include <unistd.h> */
#include <sys/types.h>
#include <string.h>

#include "global.h"
#include "utils.h"
#include "bug.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "trap.h"
#include "constants.h"
#include "whod.h"
#include "multiclass.h"
#include "fight.h"
#include "reception.h"
#include "magic_utils.h"
#include "spell_parser.h"
#include "act_info.h"
#include "act_skills.h"
#define _ACT_MOVE_C
#include "act_move.h"

/*
 * Some new movement commands for diku-mud.. a bit more object oriented.
 */

void NotLegalMove(struct char_data *ch)
{
    if (DEBUG > 2)
	log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));

    cprintf(ch, "Alas, you cannot go that way...\r\n");
}

int check_exit_alias(struct char_data *ch, const char *argument)
{
    struct room_direction_data             *exitp = NULL;
    int                                     exit_index = -1;

#if 0
    return 0;
#endif

    if (DEBUG > 2)
	log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(argument));

    for (exit_index = 0; exit_index < MAX_NUM_EXITS; exit_index++) {
	if ((exitp = EXIT(ch, exit_index))) {
	    if (IS_SET(exitp->exit_info, EX_ALIAS))
		if (!strncmp(exitp->exit_alias, argument, strlen(exitp->exit_alias)))
		    return (do_move(ch, "", exit_index + 1));
	}
    }
    return 0;
}

int ValidMove(struct char_data *ch, int cmd)
{
    struct room_direction_data             *exitp = NULL;
    struct room_data                       *there = NULL;
    struct char_data                       *v = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), cmd);

    exitp = EXIT(ch, cmd);

    if (!exit_ok(exitp, NULL)) {
	NotLegalMove(ch);
	return (FALSE);
    }
    there = real_roomp(exitp->to_room);

    if (MOUNTED(ch)) {
	if (GET_POS(MOUNTED(ch)) < POSITION_FIGHTING) {
	    cprintf(ch, "Your mount must be standing\r\n");
	    return (FALSE);
	}
	if (ch->in_room != MOUNTED(ch)->in_room) {
	    Dismount(ch, MOUNTED(ch), POSITION_STANDING);
	}
    }
    if (IS_SET(exitp->exit_info, EX_CLOSED)) {
	if (exitp->keyword) {
	    if (IS_NOT_SET(exitp->exit_info, EX_SECRET)
		&& (strcmp(fname(exitp->keyword), "secret"))) {
		if (IS_IMMORTAL(ch)) {
		    if (IS_SET(ch->specials.act, PLR_STEALTH)) {
			if (!real_roomp(ch->in_room))
			    return FALSE;
			for (v = real_roomp(ch->in_room)->people; v; v = v->next_in_room) {
			    if ((ch != v) && (GetMaxLevel(v) >= GetMaxLevel(ch))) {
				act("$n casually walks out THROUGH the %s!", FALSE, ch, 0, v,
				    TO_VICT, fname(exitp->keyword));
			    }
			}
		    } else {
			act("$n casually walks out THROUGH the %s!", FALSE, ch, 0, 0,
			    TO_ROOM, fname(exitp->keyword));
		    }
		    return TRUE;
		}
		cprintf(ch, "The %s seems to be closed.\r\n", fname(exitp->keyword));
		return (FALSE);
	    } else {
		NotLegalMove(ch);
		return (FALSE);
	    }
	} else {
	    NotLegalMove(ch);
	    return (FALSE);
	}
    } else {
	if (IS_SET(there->room_flags, INDOORS)) {
	    if (MOUNTED(ch)) {
		cprintf(ch, "Your mount refuses to go that way\r\n");
		return (FALSE);
	    }
	}
	if (IS_SET(there->room_flags, DEATH)) {
	    if (MOUNTED(ch)) {
		cprintf(ch, "Your mount refuses to go that way\r\n");
		return (FALSE);
	    }
	}
	return (TRUE);
    }
}

int RawMove(struct char_data *ch, int dir)
{
    struct obj_data                        *obj = NULL;
    struct room_data                       *from_here = NULL;
    struct room_data                       *to_here = NULL;
    struct char_data                       *pers = NULL;
    int                                     need_movement = FALSE;
    int                                     has_boat = FALSE;
    int                                     amount = 0;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir);

    if (special(ch, dir + 1, ""))			       /* Check for special routines(North is 1) */
	return (FALSE);

    if (!ValidMove(ch, dir)) {
	return (FALSE);
    }
    if (IS_AFFECTED(ch, AFF_CHARM) && (ch->master) && (ch->in_room == ch->master->in_room)) {
	act("$n bursts into tears.", FALSE, ch, 0, 0, TO_ROOM);
	act("You burst into tears at the thought of leaving $N", FALSE, ch, 0, ch->master,
	    TO_CHAR);
	return (FALSE);
    }
    amount = 0;
    if (IS_AFFECTED(ch, AFF_SNEAK)) {
	amount = 2;

	if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 1) && (GET_LEVEL(ch, BestThiefClass(ch)) < 5))
	    amount += 13;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 5) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 10))
	    amount += 11;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 10) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 15))
	    amount += 9;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 15) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 20))
	    amount += 7;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 20) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 25))
	    amount += 5;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 25) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 30))
	    amount += 3;
	else if ((GET_LEVEL(ch, BestThiefClass(ch)) >= 30) &&
		 (GET_LEVEL(ch, BestThiefClass(ch)) < 40))
	    amount += 1;

	amount -= MAX(2, wis_app[(int)GET_DEX(ch)].bonus);

	if (amount <= 0)
	    amount = 1;

	GET_MANA(ch) -= amount;
	if (GET_MANA(ch) <= 0) {
	    affect_from_char(ch, SKILL_SNEAK);
	    GET_MANA(ch) = 0;
	}
    }
    from_here = real_roomp(ch->in_room);
    to_here = real_roomp(from_here->dir_option[dir]->to_room);

    if (to_here == NULL) {
	char_from_room(ch);
	char_to_room(ch, 0);
	cprintf(ch,
		"Uh-oh.  The ground melts beneath you as you fall into the swirling chaos.\r\n");
	do_look(ch, "", 15);
	return TRUE;
    }
    if (IS_AFFECTED(ch, AFF_FLYING))
	need_movement = 1;
    else {
	need_movement = (movement_loss[from_here->sector_type] +
			 movement_loss[to_here->sector_type]) / 2;
    }

    /*
     **   Movement in water_nowswim
     */

    if ((from_here->sector_type == SECT_WATER_SWIM)
	|| (to_here->sector_type == SECT_WATER_SWIM)) {
	if ((!IS_AFFECTED(ch, AFF_WATERBREATH)) && (!IS_AFFECTED(ch, AFF_FLYING))) {
	    has_boat = number(1, 101);
	    if (has_boat < ch->skills[SKILL_SWIMMING].learned)
		need_movement = 1;
	}
    }
    if ((from_here->sector_type == SECT_WATER_NOSWIM)
	|| (to_here->sector_type == SECT_WATER_NOSWIM)) {
	if (MOUNTED(ch)) {
	    if (!IS_AFFECTED(MOUNTED(ch), AFF_WATERBREATH)
		&& !IS_AFFECTED(MOUNTED(ch), AFF_FLYING)) {
		cprintf(ch, "Your mount would have to fly or swim to go there\r\n");
		return (FALSE);
	    }
	}
	if ((!IS_AFFECTED(ch, AFF_WATERBREATH)) && (!IS_AFFECTED(ch, AFF_FLYING))) {
	    has_boat = FALSE;
	    /*
	     * See if char is carrying a boat 
	     */
	    for (obj = ch->carrying; obj; obj = obj->next_content)
		if (obj->obj_flags.type_flag == ITEM_BOAT)
		    has_boat = TRUE;
	    if (!has_boat) {
		cprintf(ch, "You need a boat to go there.\r\n");
		return (FALSE);
	    }
	    if (has_boat)
		need_movement = 1;
	}
    }
    /*
     * Movement in SECT_AIR
     */

    if ((from_here->sector_type == SECT_AIR) || (to_here->sector_type == SECT_AIR)) {
	if (MOUNTED(ch)) {
	    if (!IS_AFFECTED(MOUNTED(ch), AFF_FLYING)) {
		cprintf(ch, "Your mount would have to fly to go there!\r\n");
		return (FALSE);
	    }
	}
	if (!IS_AFFECTED(ch, AFF_FLYING)) {
	    cprintf(ch, "You would have to Fly to go there!\r\n");
	    return (FALSE);
	}
    }
    /*
     * Movement in SECT_UNDERWATER
     */

    if ((from_here->sector_type == SECT_UNDERWATER)
	|| (to_here->sector_type == SECT_UNDERWATER)) {
	if (MOUNTED(ch)) {
	    if (!IS_AFFECTED(MOUNTED(ch), AFF_WATERBREATH)) {
		cprintf(ch, "Your mount would need gills to go there!\r\n");
		return (FALSE);
	    }
	}
	if (!IS_AFFECTED(ch, AFF_WATERBREATH)) {
	    cprintf(ch, "You would need to be a fish to go there!\r\n");
	    return (FALSE);
	}
    }
    if (!MOUNTED(ch)) {
	if (GET_MOVE(ch) < need_movement) {
	    cprintf(ch, "You are too exhausted.\r\n");
	    return (FALSE);
	}
    } else {
	if (GET_MOVE(MOUNTED(ch)) < need_movement) {
	    cprintf(ch, "Your mount is too exhausted.\r\n");
	    return (FALSE);
	}
    }

    if (IS_MORTAL(ch) || MOUNTED(ch)) {
	if (IS_NPC(ch)) {
	    GET_MOVE(ch) -= 1;
	} else {
	    if (MOUNTED(ch)) {
		GET_MOVE(MOUNTED(ch)) -= need_movement;
	    } else {
		GET_MOVE(ch) -= need_movement;
	    }
	}
    }
    /*
     *  nail the unlucky with traps.
     */

    if (!MOUNTED(ch)) {
	if (CheckForMoveTrap(ch, dir))
	    return (FALSE);
    } else {
	if (CheckForMoveTrap(MOUNTED(ch), dir))
	    return (FALSE);
    }

    if (MOUNTED(ch)) {
	char_from_room(ch);
	char_to_room(ch, from_here->dir_option[dir]->to_room);
	char_from_room(MOUNTED(ch));
	char_to_room(MOUNTED(ch), from_here->dir_option[dir]->to_room);
    } else {
	char_from_room(ch);
	char_to_room(ch, from_here->dir_option[dir]->to_room);
    }

    do_look(ch, "", 15);

    if (IS_SET(to_here->room_flags, DEATH) && IS_MORTAL(ch)) {
	death_cry(ch);
	if (MOUNTED(ch))
	    death_cry(MOUNTED(ch));

	if (IS_NPC(ch) && (IS_SET(ch->specials.act, ACT_POLYSELF))) {
	    /*
	     *   take char from storage, to room     
	     */
	    if (MOUNTED(ch))
		extract_char(MOUNTED(ch));

	    pers = ch->desc->original;
	    char_from_room(pers);
	    char_to_room(pers, ch->in_room);
	    SwitchStuff(ch, pers);
	    zero_rent(ch);
	    extract_char(ch);
	    ch = pers;
	}
	zero_rent(ch);
	extract_char(ch);
	return (FALSE);
    }
    return (TRUE);
}

int MoveOne(struct char_data *ch, int dir)
{
    int                                     was_in = FALSE;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir);

    was_in = ch->in_room;
    if (RawMove(ch, dir)) {				       /* no error */
	DisplayOneMove(ch, dir, was_in);
	return TRUE;
    } else
	return FALSE;
}

int MoveGroup(struct char_data *ch, int dir)
{
    int                                     was_in = FALSE;
    int                                     i = 0;
    int                                     heap_top = 0;
    int                                     heap_tot[50];
    struct follow_type                     *k = NULL;
    struct follow_type                     *next_dude = NULL;
    struct char_data                       *heap_ptr[50];

    /*
     *   move the leader. (leader never duplicates)
     */

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir);

    was_in = ch->in_room;
    if (RawMove(ch, dir)) {				       /* no error */
	DisplayOneMove(ch, dir, was_in);
	if (ch->followers) {
	    heap_top = 0;
	    for (k = ch->followers; k; k = next_dude) {
		next_dude = k->next;
		/*
		 *  compose a list of followers, w/heaping
		 */
		if ((was_in == k->follower->in_room)
		    && (GET_POS(k->follower) >= POSITION_STANDING)) {
		    act("You follow $N.", FALSE, k->follower, 0, ch, TO_CHAR);
		    if (k->follower->followers) {
			MoveGroup(k->follower, dir);
		    } else {
			if (RawMove(k->follower, dir)) {
			    AddToCharHeap(heap_ptr, &heap_top, heap_tot, k->follower);
			    /*
			     * if (!AddToCharHeap(heap_ptr, &heap_top, heap_tot, k->follower))
			     * displayOneMove(k->follower, dir, was_in);
			     */
			}
		    }
		}
	    }
	    /*
	     *  now, print out the heaped display message
	     */
	    for (i = 0; i < heap_top; i++) {
		if (heap_tot[i] > 1) {
		    DisplayGroupMove(heap_ptr[i], dir, was_in, heap_tot[i]);
		} else {
		    DisplayOneMove(heap_ptr[i], dir, was_in);
		}
	    }
	}
    }
    return 1;
}

void DisplayOneMove(struct char_data *ch, int dir, int was_in)
{
    if (DEBUG > 2)
	log_info("called %s with %s, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir, was_in);

    DisplayMove(ch, dir, was_in, 1);
}

void DisplayGroupMove(struct char_data *ch, int dir, int was_in, int total)
{
    if (DEBUG > 2)
	log_info("called %s with %s, %d, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir,
		 was_in, total);

    DisplayMove(ch, dir, was_in, total);
}

/* void do_move(struct char_data *ch, const char *argument, int cmd) */
int do_move(struct char_data *ch, const char *argument, int cmd)
{
    if (DEBUG > 1)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    if (RIDDEN(ch)) {
	if (RideCheck(RIDDEN(ch))) {
	    return (do_move(RIDDEN(ch), argument, cmd));
	} else {
	    FallOffMount(RIDDEN(ch), ch);
	    Dismount(RIDDEN(ch), ch, POSITION_SITTING);
	}
    }
    if (RIDDEN(ch)) {
	if (RIDDEN(ch)->specials.fighting) {
	    cprintf(ch, "You can't, your rider is fighting!\r\n");
	    return FALSE;
	}
    }
    if (MOUNTED(ch)) {
	if (MOUNTED(ch)->specials.fighting) {
	    cprintf(ch, "You can't, your mount is fighting!\r\n");
	    return FALSE;
	}
    }
    cmd -= 1;

    /*
     ** the move is valid, check for follower/master conflicts.
     */

    if (ch->attackers > 2) {
	cprintf(ch, "There's too many people around, no place to flee!\r\n");
	return FALSE;
    }
    if (!ch->followers && !ch->master) {
	return (MoveOne(ch, cmd));
    } else {
	if (!ch->followers) {
	    return (MoveOne(ch, cmd));
	} else {
	    return (MoveGroup(ch, cmd));
	}
    }
}

/*
 * MoveOne and MoveGroup print messages.  Raw move sends success or failure.
 */

void DisplayMove(struct char_data *ch, int dir, int was_in, int total)
{
    struct char_data                       *tmp_ch = NULL;
    char                                    tmp[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";

    if (DEBUG > 2)
	log_info("called %s with %s, %d, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir,
		 was_in, total);

    for (tmp_ch = real_roomp(was_in)->people; tmp_ch; tmp_ch = tmp_ch->next_in_room) {
	if ((!IS_AFFECTED(ch, AFF_SNEAK)) || (IS_IMMORTAL(tmp_ch))) {
	    if ((ch != tmp_ch) && (AWAKE(tmp_ch)) && (CAN_SEE(tmp_ch, ch))) {
		if (total > 1) {
		    if (IS_NPC(ch)) {
			sprintf(tmp, "%s leaves %s. [%d]\r\n", ch->player.short_descr,
				dirs[dir], total);
		    } else {
			sprintf(tmp, "%s leaves %s.[%d]\r\n", GET_NAME(ch), dirs[dir], total);
		    }
		} else {
		    if (IS_NPC(ch)) {
			if (MOUNTED(ch)) {
			    struct char_data                       *mount;

			    mount = MOUNTED(ch);
			    sprintf(tmp, "%s leaves %s, riding on %s\r\n",
				    ch->player.short_descr, dirs[dir],
				    mount->player.short_descr);
			} else {
			    sprintf(tmp, "%s leaves %s.\r\n", ch->player.short_descr,
				    dirs[dir]);
			}
		    } else {
			if (MOUNTED(ch)) {
			    sprintf(tmp, "%s leaves %s, riding on %s\r\n",
				    GET_NAME(ch), dirs[dir], MOUNTED(ch)->player.short_descr);
			} else {
			    sprintf(tmp, "%s leaves %s\r\n", GET_NAME(ch), dirs[dir]);
			}
		    }
		}
		cprintf(tmp_ch, "%s", tmp);
	    }
	}
    }

    for (tmp_ch = real_roomp(ch->in_room)->people; tmp_ch; tmp_ch = tmp_ch->next_in_room) {
	if (((!IS_AFFECTED(ch, AFF_SNEAK)) || (IS_IMMORTAL(tmp_ch))) &&
	    (CAN_SEE(tmp_ch, ch)) && (AWAKE(tmp_ch))) {
	    if (tmp_ch != ch) {
		if (dir < 4) {
		    if (total == 1) {
			if (MOUNTED(ch)) {
			    sprintf(tmp, "%s has arrived from the %s, riding on %s",
				    PERS(ch, tmp_ch), dirs[rev_dir[dir]], PERS(MOUNTED(ch),
									       tmp_ch));
			} else {
			    sprintf(tmp, "%s has arrived from the %s.", PERS(ch, tmp_ch),
				    dirs[rev_dir[dir]]);
			}
		    } else {
			sprintf(tmp, "%s has arrived from the %s.", PERS(ch, tmp_ch),
				dirs[rev_dir[dir]]);
		    }
		} else if (dir == 4) {
		    if (total == 1) {
			if (MOUNTED(ch)) {
			    sprintf(tmp, "%s has arrived from below, riding on %s",
				    PERS(ch, tmp_ch), PERS(MOUNTED(ch), tmp_ch));
			} else {
			    sprintf(tmp, "%s has arrived from below.", PERS(ch, tmp_ch));
			}
		    } else {
			sprintf(tmp, "%s has arrived from below.", PERS(ch, tmp_ch));
		    }
		} else if (dir == 5) {
		    if (total == 1) {
			if (MOUNTED(ch)) {
			    sprintf(tmp, "%s has arrived from above, riding on %s",
				    PERS(ch, tmp_ch), PERS(MOUNTED(ch), tmp_ch));
			} else {
			    sprintf(tmp, "%s has arrived from above", PERS(ch, tmp_ch));
			}
		    } else {
			sprintf(tmp, "%s has arrived from above.", PERS(ch, tmp_ch));
		    }
		} else {
		    if (total == 1) {
			if (MOUNTED(ch)) {
			    sprintf(tmp, "%s has arrived from somewhere, riding on %s",
				    PERS(ch, tmp_ch), PERS(MOUNTED(ch), tmp_ch));
			} else {
			    sprintf(tmp, "%s has arrived from somewhere.", PERS(ch, tmp_ch));
			}
		    } else {
			sprintf(tmp, "%s has arrived from somewhere.", PERS(ch, tmp_ch));
		    }
		}

		if (total > 1) {
		    sprintf(tmp + strlen(tmp), " [%d]", total);
		}
		strcat(tmp, "\r\n");
		cprintf(tmp_ch, "%s", tmp);
	    }
	}
    }
}

void AddToCharHeap(struct char_data *heap[50], int *top, int total[50], struct char_data *k)
{
    int                                     found = FALSE;
    int                                     i = 0;

    if (DEBUG > 2)
	log_info("called %s with %08zx, %08zx, %08zx, %s", __PRETTY_FUNCTION__, (size_t) heap,
		 (size_t) top, (size_t) total, SAFE_NAME(k));

    if (*top <= 50) {
	found = FALSE;
	for (i = 0; (i < *top && !found); i++) {
	    if (*top > 0) {
		if ((IS_NPC(k)) &&
		    (k->nr == heap[i]->nr) &&
		    (heap[i]->player.short_descr) &&
		    (!strcmp(k->player.short_descr, heap[i]->player.short_descr))) {
		    total[i] += 1;
		    found = TRUE;
		}
	    }
	}
	if (!found) {
	    heap[*top] = k;
	    total[*top] = 1;
	    *top += 1;
	}
    }
}

int find_door(struct char_data *ch, char *type, char *dir)
{
    int                                     door = -1;

    const char                             *exit_dirs[] = {
	"north",
	"east",
	"south",
	"west",
	"up",
	"down",
	"\n"
    };
    struct room_direction_data             *exitp = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(type),
		 VNULL(dir));

    if (*dir) {						       /* a direction was specified */
	if ((door = search_block(dir, exit_dirs, FALSE)) == -1) {	/* Partial Match */
	    cprintf(ch, "That's not a direction.\r\n");
	    return (-1);
	}
	exitp = EXIT(ch, door);
	if (exitp) {
	    if (!exitp->keyword)
		return (door);
	    if ((isname(type, exitp->keyword)) && (strcmp(type, "secret"))) {
		return (door);
	    } else {
		cprintf(ch, "I see no %s there.\r\n", type);
		return (-1);
	    }
	} else {
	    cprintf(ch, "I see no %s there.\r\n", type);
	    return (-1);
	}
    } else {						       /* try to locate the keyword */
	for (door = 0; door < MAX_NUM_EXITS; door++)
	    if ((exitp = EXIT(ch, door)) && exitp->keyword && isname(type, exitp->keyword))
		return (door);

	cprintf(ch, "I see no %s here.\r\n", type);
	return (-1);
    }
}

/*
 * remove all necessary bits and send messages 
 */
void open_door(struct char_data *ch, int dir)
{
    struct room_direction_data             *exitp = NULL;
    struct room_direction_data             *back = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir);

    rp = real_roomp(ch->in_room);
    if (rp == NULL) {
	log_error("NULL rp in open_door() for %s.", PERS(ch, ch));
    }
    exitp = rp->dir_option[dir];

    REMOVE_BIT(exitp->exit_info, EX_CLOSED);
    if (exitp->keyword) {
	if (strcmp(exitp->keyword, "secret") && (IS_NOT_SET(exitp->exit_info, EX_SECRET))) {
	    act("$n opens the %s", FALSE, ch, 0, 0, TO_ROOM, fname(exitp->keyword));
	} else {
	    act("$n reveals a hidden passage!", FALSE, ch, 0, 0, TO_ROOM);
	}
    } else
	act("$n opens the door.", FALSE, ch, 0, 0, TO_ROOM);

    /*
     * now for opening the OTHER side of the door! 
     */
    if (exit_ok(exitp, &rp) &&
	(back = rp->dir_option[rev_dir[dir]]) && (back->to_room == ch->in_room)) {
	REMOVE_BIT(back->exit_info, EX_CLOSED);
	if (back->keyword) {
	    rprintf(exitp->to_room, "The %s is opened from the other side.\r\n",
		    fname(back->keyword));
	} else
	    rprintf(exitp->to_room, "The door is opened from the other side.\r\n");
    }
}

/*
 * remove all necessary bits and send messages 
 */
void raw_open_door(struct char_data *ch, int dir)
{
    struct room_direction_data             *exitp = NULL;
    struct room_direction_data             *back = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), dir);

    rp = real_roomp(ch->in_room);
    if (rp == NULL)
	log_error("NULL rp in open_door() for %s.", PERS(ch, ch));
    exitp = rp->dir_option[dir];

    REMOVE_BIT(exitp->exit_info, EX_CLOSED);
    /*
     * now for opening the OTHER side of the door! 
     */
    if (exit_ok(exitp, &rp) &&
	(back = rp->dir_option[rev_dir[dir]]) && (back->to_room == ch->in_room)) {
	REMOVE_BIT(back->exit_info, EX_CLOSED);
	if (back->keyword && (strcmp("secret", fname(back->keyword)))) {
	    rprintf(exitp->to_room, "The %s is opened from the other side.\r\n",
		    fname(back->keyword));
	} else {
	    rprintf(exitp->to_room, "The door is opened from the other side.\r\n");
	}
    }
}

void do_open(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    char                                    type[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    char                                    dir[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct obj_data                        *obj = NULL;
    struct char_data                       *victim = NULL;
    struct room_direction_data             *exitp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    argument_interpreter(argument, type, dir);

    if (!*type)
	cprintf(ch, "Open what?\r\n");
    else if (generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj)) {
	/*
	 * this is an object 
	 */
	if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	    cprintf(ch, "That's not a container.\r\n");
	else if (IS_NOT_SET(obj->obj_flags.value[1], CONT_CLOSED))
	    cprintf(ch, "But it's already open!\r\n");
	else if (IS_NOT_SET(obj->obj_flags.value[1], CONT_CLOSEABLE))
	    cprintf(ch, "You can't do that.\r\n");
	else if (IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	    cprintf(ch, "It seems to be locked.\r\n");
	else {
	    REMOVE_BIT(obj->obj_flags.value[1], CONT_CLOSED);
	    cprintf(ch, "Ok.\r\n");
	    act("$n opens $p.", FALSE, ch, obj, 0, TO_ROOM);
	}
    } else if ((door = find_door(ch, type, dir)) >= 0) {
	/*
	 * perhaps it is a door 
	 */
	exitp = EXIT(ch, door);
	if (IS_NOT_SET(exitp->exit_info, EX_ISDOOR))
	    cprintf(ch, "That's impossible, I'm afraid.\r\n");
	else if (IS_NOT_SET(exitp->exit_info, EX_CLOSED))
	    cprintf(ch, "It's already open!\r\n");
	else if (IS_SET(exitp->exit_info, EX_LOCKED))
	    cprintf(ch, "It seems to be locked.\r\n");
	else {
	    open_door(ch, door);
	    cprintf(ch, "Ok.\r\n");
	}
    }
}

void do_close(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    char                                    type[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    char                                    dir[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct room_direction_data             *back = NULL;
    struct room_direction_data             *exitp = NULL;
    struct obj_data                        *obj = NULL;
    struct char_data                       *victim = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    argument_interpreter(argument, type, dir);

    if (!*type)
	cprintf(ch, "Close what?\r\n");
    else if (generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj)) {

	/*
	 * this is an object 
	 */

	if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	    cprintf(ch, "That's not a container.\r\n");
	else if (IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	    cprintf(ch, "But it's already closed!\r\n");
	else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSEABLE))
	    cprintf(ch, "That's impossible.\r\n");
	else {
	    SET_BIT(obj->obj_flags.value[1], CONT_CLOSED);
	    cprintf(ch, "Ok.\r\n");
	    act("$n closes $p.", FALSE, ch, obj, 0, TO_ROOM);
	}
    } else if ((door = find_door(ch, type, dir)) >= 0) {

	/*
	 * Or a door 
	 */
	exitp = EXIT(ch, door);
	if (!IS_SET(exitp->exit_info, EX_ISDOOR))
	    cprintf(ch, "That's absurd.\r\n");
	else if (IS_SET(exitp->exit_info, EX_CLOSED))
	    cprintf(ch, "It's already closed!\r\n");
	else {
	    SET_BIT(exitp->exit_info, EX_CLOSED);
	    if (exitp->keyword)
		act("$n closes the $F.", 0, ch, 0, exitp->keyword, TO_ROOM);
	    else
		act("$n closes the door.", FALSE, ch, 0, 0, TO_ROOM);
	    cprintf(ch, "Ok.\r\n");
	    /*
	     * now for closing the other side, too 
	     */
	    if (exit_ok(exitp, &rp) &&
		(back = rp->dir_option[rev_dir[door]]) && (back->to_room == ch->in_room)) {
		SET_BIT(back->exit_info, EX_CLOSED);
		if (back->keyword) {
		    rprintf(exitp->to_room, "The %s closes quietly.\r\n", back->keyword);
		} else
		    rprintf(exitp->to_room, "The door closes quietly.\r\n");
	    }
	}
    }
}

int has_key(struct char_data *ch, int key)
{
    struct obj_data                        *o = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), key);

    for (o = ch->carrying; o; o = o->next_content)
	if (obj_index[o->item_number].virtual == key)
	    return (1);

    if (ch->equipment[HOLD])
	if (obj_index[ch->equipment[HOLD]->item_number].virtual == key)
	    return (1);

    return (0);
}

void raw_unlock_door(struct char_data *ch, struct room_direction_data *exitp, int door)
{
    struct room_data                       *rp = NULL;
    struct room_direction_data             *back = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %08zx, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 (size_t) exitp, door);

    REMOVE_BIT(exitp->exit_info, EX_LOCKED);
    /*
     * now for unlocking the other side, too 
     */
    rp = real_roomp(exitp->to_room);
    if (rp && (back = rp->dir_option[rev_dir[door]]) && back->to_room == ch->in_room) {
	REMOVE_BIT(back->exit_info, EX_LOCKED);
    } else {
	log_info("Inconsistent door locks in rooms %d->%d", ch->in_room, exitp->to_room);
    }
}

void raw_lock_door(struct char_data *ch, struct room_direction_data *exitp, int door)
{
    struct room_data                       *rp = NULL;
    struct room_direction_data             *back = NULL;

    if (DEBUG > 2)
	log_info("called %s with %s, %08zx, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 (size_t) exitp, door);

    SET_BIT(exitp->exit_info, EX_LOCKED);
    /*
     * now for locking the other side, too 
     */
    rp = real_roomp(exitp->to_room);
    if (rp && (back = rp->dir_option[rev_dir[door]]) && back->to_room == ch->in_room) {
	SET_BIT(back->exit_info, EX_LOCKED);
    } else {
	log_info("Inconsistent door locks in rooms %d->%d", ch->in_room, exitp->to_room);
    }
}

void do_lock(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    char                                    type[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    char                                    dir[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct room_direction_data             *back = NULL;
    struct room_direction_data             *exitp = NULL;
    struct obj_data                        *obj = NULL;
    struct char_data                       *victim = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    argument_interpreter(argument, type, dir);

    if (!*type)
	cprintf(ch, "Lock what?\r\n");
    else if (generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj)) {

	/*
	 * this is an object 
	 */

	if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	    cprintf(ch, "That's not a container.\r\n");
	else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	    cprintf(ch, "Maybe you should close it first...\r\n");
	else if (obj->obj_flags.value[2] < 0)
	    cprintf(ch, "That thing can't be locked.\r\n");
	else if (!has_key(ch, obj->obj_flags.value[2]))
	    cprintf(ch, "You don't seem to have the proper key.\r\n");
	else if (IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	    cprintf(ch, "It is locked already.\r\n");
	else {
	    SET_BIT(obj->obj_flags.value[1], CONT_LOCKED);
	    cprintf(ch, "*Cluck*\r\n");
	    act("$n locks $p - 'cluck', it says.", FALSE, ch, obj, 0, TO_ROOM);
	}
    } else if ((door = find_door(ch, type, dir)) >= 0) {

	/*
	 * a door, perhaps 
	 */
	exitp = EXIT(ch, door);

	if (!IS_SET(exitp->exit_info, EX_ISDOOR))
	    cprintf(ch, "That's absurd.\r\n");
	else if (!IS_SET(exitp->exit_info, EX_CLOSED))
	    cprintf(ch, "You have to close it first, I'm afraid.\r\n");
	else if (exitp->key < 0)
	    cprintf(ch, "There does not seem to be any keyholes.\r\n");
	else if (!has_key(ch, exitp->key))
	    cprintf(ch, "You don't have the proper key.\r\n");
	else if (IS_SET(exitp->exit_info, EX_LOCKED))
	    cprintf(ch, "It's already locked!\r\n");
	else {
	    SET_BIT(exitp->exit_info, EX_LOCKED);
	    if (exitp->keyword)
		act("$n locks the $F.", 0, ch, 0, exitp->keyword, TO_ROOM);
	    else
		act("$n locks the door.", FALSE, ch, 0, 0, TO_ROOM);
	    cprintf(ch, "*Click*\r\n");
	    /*
	     * now for locking the other side, too 
	     */
	    rp = real_roomp(exitp->to_room);
	    if (rp && (back = rp->dir_option[rev_dir[door]]) && back->to_room == ch->in_room)
		SET_BIT(back->exit_info, EX_LOCKED);
	}
    }
}

void do_unlock(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    char                                    type[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    char                                    dir[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct room_direction_data             *back = NULL;
    struct room_direction_data             *exitp = NULL;
    struct obj_data                        *obj = NULL;
    struct char_data                       *victim = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    argument_interpreter(argument, type, dir);

    if (!*type)
	cprintf(ch, "Unlock what?\r\n");
    else if (generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj)) {

	/*
	 * this is an object 
	 */

	if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	    cprintf(ch, "That's not a container.\r\n");
	else if (obj->obj_flags.value[2] < 0)
	    cprintf(ch, "Odd - you can't seem to find a keyhole.\r\n");
	else if (!has_key(ch, obj->obj_flags.value[2]))
	    cprintf(ch, "You don't seem to have the proper key.\r\n");
	else if (!IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	    cprintf(ch, "Oh.. it wasn't locked, after all.\r\n");
	else {
	    REMOVE_BIT(obj->obj_flags.value[1], CONT_LOCKED);
	    cprintf(ch, "*Click*\r\n");
	    act("$n unlocks $p.", FALSE, ch, obj, 0, TO_ROOM);
	}
    } else if ((door = find_door(ch, type, dir)) >= 0) {

	/*
	 * it is a door 
	 */
	exitp = EXIT(ch, door);

	if (!IS_SET(exitp->exit_info, EX_ISDOOR))
	    cprintf(ch, "That's absurd.\r\n");
	else if (!IS_SET(exitp->exit_info, EX_CLOSED))
	    cprintf(ch, "Heck.. it ain't even closed!\r\n");
	else if (exitp->key < 0)
	    cprintf(ch, "You can't seem to spot any keyholes.\r\n");
	else if (!has_key(ch, exitp->key))
	    cprintf(ch, "You do not have the proper key for that.\r\n");
	else if (!IS_SET(exitp->exit_info, EX_LOCKED))
	    cprintf(ch, "It's already unlocked, it seems.\r\n");
	else {
	    REMOVE_BIT(exitp->exit_info, EX_LOCKED);
	    if (exitp->keyword)
		act("$n unlocks the $F.", 0, ch, 0, exitp->keyword, TO_ROOM);
	    else
		act("$n unlocks the door.", FALSE, ch, 0, 0, TO_ROOM);
	    cprintf(ch, "*click*\r\n");
	    /*
	     * now for unlocking the other side, too 
	     */
	    rp = real_roomp(exitp->to_room);
	    if (rp && (back = rp->dir_option[rev_dir[door]]) && back->to_room == ch->in_room)
		REMOVE_BIT(back->exit_info, EX_LOCKED);
	}
    }
}

void do_pick(struct char_data *ch, const char *argument, int cmd)
{
    int                                     percent_chance = 0;
    int                                     door = -1;
    char                                    type[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    char                                    dir[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct room_direction_data             *back = NULL;
    struct room_direction_data             *exitp = NULL;
    struct obj_data                        *obj = NULL;
    struct char_data                       *victim = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    argument_interpreter(argument, type, dir);

    percent_chance = number(1, 101);			       /* 101% is a complete failure */

    if (percent_chance > (ch->skills[SKILL_PICK_LOCK].learned)) {
	cprintf(ch, "You failed to pick the lock.\r\n");
	return;
    }
    if (!*type) {
	cprintf(ch, "Pick what?\r\n");
    } else if (generic_find(argument, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj)) {
	/*
	 * this is an object 
	 */
	if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	    cprintf(ch, "That's not a container.\r\n");
	else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	    cprintf(ch, "Silly - it ain't even closed!\r\n");
	else if (obj->obj_flags.value[2] < 0)
	    cprintf(ch, "Odd - you can't seem to find a keyhole.\r\n");
	else if (!IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	    cprintf(ch, "Oho! This thing is NOT locked!\r\n");
	else if (IS_SET(obj->obj_flags.value[1], CONT_PICKPROOF))
	    cprintf(ch, "It resists your attempts at picking it.\r\n");
	else {
	    REMOVE_BIT(obj->obj_flags.value[1], CONT_LOCKED);
	    cprintf(ch, "*Click*\r\n");
	    act("$n fiddles with $p.", FALSE, ch, obj, 0, TO_ROOM);
	    if (ch->skills[SKILL_PICK_LOCK].learned < 50)
		ch->skills[SKILL_PICK_LOCK].learned += 2;
	}
    } else if ((door = find_door(ch, type, dir)) >= 0) {
	exitp = EXIT(ch, door);
	if (!IS_SET(exitp->exit_info, EX_ISDOOR))
	    cprintf(ch, "That's absurd.\r\n");
	else if (!IS_SET(exitp->exit_info, EX_CLOSED))
	    cprintf(ch, "You realize that the door is already open.\r\n");
	else if (exitp->key < 0)
	    cprintf(ch, "You can't seem to spot any lock to pick.\r\n");
	else if (!IS_SET(exitp->exit_info, EX_LOCKED))
	    cprintf(ch, "Oh.. it wasn't locked at all.\r\n");
	else if (IS_SET(exitp->exit_info, EX_PICKPROOF))
	    cprintf(ch, "You seem to be unable to pick this lock.\r\n");
	else {
	    REMOVE_BIT(exitp->exit_info, EX_LOCKED);
	    if (exitp->keyword)
		act("$n skillfully picks the lock of the $F.", 0, ch, 0, exitp->keyword,
		    TO_ROOM);
	    else
		act("$n picks the lock.", TRUE, ch, 0, 0, TO_ROOM);
	    cprintf(ch, "The lock quickly yields to your skills.\r\n");
	    /*
	     * now for unlocking the other side, too 
	     */
	    rp = real_roomp(exitp->to_room);
	    if (rp && (back = rp->dir_option[rev_dir[door]]) && back->to_room == ch->in_room)
		REMOVE_BIT(back->exit_info, EX_LOCKED);
	    if (ch->skills[SKILL_PICK_LOCK].learned < 50)
		ch->skills[SKILL_PICK_LOCK].learned += 2;
	}
    }
}

void do_enter(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    char                                    buf[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct room_direction_data             *exitp = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    one_argument(argument, buf);

    if (*buf) {						       /* an argument was supplied, search for door keyword */
	for (door = 0; door < MAX_NUM_EXITS; door++)
	    if (exit_ok(exitp = EXIT(ch, door), NULL) && exitp->keyword &&
		0 == str_cmp(exitp->keyword, buf)) {
		do_move(ch, "", ++door);
		return;
	    }
	cprintf(ch, "There is no %s here.\r\n", buf);
    } else if (IS_SET(real_roomp(ch->in_room)->room_flags, INDOORS)) {
	cprintf(ch, "You are already indoors.\r\n");
    } else {
	/*
	 * try to locate an entrance 
	 */
	for (door = 0; door < MAX_NUM_EXITS; door++)
	    if (exit_ok(exitp = EXIT(ch, door), &rp) &&
		!IS_SET(exitp->exit_info, EX_CLOSED) && IS_SET(rp->room_flags, INDOORS)) {
		do_move(ch, "", ++door);
		return;
	    }
	cprintf(ch, "You can't seem to find anything to enter.\r\n");
    }
}

void do_leave(struct char_data *ch, const char *argument, int cmd)
{
    int                                     door = -1;
    struct room_direction_data             *exitp = NULL;
    struct room_data                       *rp = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    if (!IS_SET(RM_FLAGS(ch->in_room), INDOORS))
	cprintf(ch, "You are outside.. where do you want to go?\r\n");
    else {
	for (door = 0; door < MAX_NUM_EXITS; door++)
	    if (exit_ok(exitp = EXIT(ch, door), &rp) &&
		!IS_SET(exitp->exit_info, EX_CLOSED) && !IS_SET(rp->room_flags, INDOORS)) {
		do_move(ch, "", ++door);
		return;
	    }
	cprintf(ch, "I see no obvious exits to the outside.\r\n");
    }
}

void do_stand(struct char_data *ch, const char *argument, int cmd)
{
    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    switch (GET_POS(ch)) {
	case POSITION_STANDING:{
		act("You are already standing.", FALSE, ch, 0, 0, TO_CHAR);
	    }
	    break;
	case POSITION_SITTING:{
		act("You stand up.", FALSE, ch, 0, 0, TO_CHAR);
		act("$n clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_STANDING;
	    }
	    break;
	case POSITION_RESTING:{
		act("You stop resting, and stand up.", FALSE, ch, 0, 0, TO_CHAR);
		act("$n stops resting, and clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_STANDING;
	    }
	    break;
	case POSITION_SLEEPING:{
		act("You have to wake up first!", FALSE, ch, 0, 0, TO_CHAR);
	    }
	    break;
	case POSITION_MOUNTED:
	    cprintf(ch, "But you are mounted?\r\n");
	    break;
	case POSITION_FIGHTING:{
		act("Do you not consider fighting as standing?", FALSE, ch, 0, 0, TO_CHAR);
	    }
	    break;
	default:{
		act("You stop floating around, and put your feet on the ground.",
		    FALSE, ch, 0, 0, TO_CHAR);
		act("$n stops floating around, and puts $s feet on the ground.",
		    TRUE, ch, 0, 0, TO_ROOM);
	    }
	    break;
    }
}

void do_sit(struct char_data *ch, const char *argument, int cmd)
{
    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    switch (GET_POS(ch)) {
	case POSITION_STANDING:{
		act("You sit down.", FALSE, ch, 0, 0, TO_CHAR);
		act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SITTING;
	    }
	    break;
	case POSITION_SITTING:{
		cprintf(ch, "You'r sitting already.\r\n");
	    }
	    break;
	case POSITION_RESTING:{
		act("You stop resting, and sit up.", FALSE, ch, 0, 0, TO_CHAR);
		act("$n stops resting.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SITTING;
	    }
	    break;
	case POSITION_SLEEPING:{
		act("You have to wake up first.", FALSE, ch, 0, 0, TO_CHAR);
	    }
	    break;
	case POSITION_MOUNTED:
	    cprintf(ch, "But you are mounted?\r\n");
	    break;
	case POSITION_FIGHTING:{
		act("Sit down while fighting? are you MAD?", FALSE, ch, 0, 0, TO_CHAR);
	    }
	    break;
	default:{
		act("You stop floating around, and sit down.", FALSE, ch, 0, 0, TO_CHAR);
		act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SITTING;
	    }
	    break;
    }
}

void do_rest(struct char_data *ch, const char *argument, int cmd)
{
    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    switch (GET_POS(ch)) {
	case POSITION_STANDING:{
		cprintf(ch, "You sit down and rest your tired bones.\r\n");
		act("$n sits down and rests.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_RESTING;
	    }
	    break;
	case POSITION_SITTING:{
		cprintf(ch, "You rest your tired bones\r\n.");
		act("$n rests.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_RESTING;
	    }
	    break;
	case POSITION_RESTING:{
		cprintf(ch, "You are already resting.\r\n");
	    }
	    break;
	case POSITION_SLEEPING:{
		cprintf(ch, "You have to wake up first.\r\n");
	    }
	    break;
	case POSITION_MOUNTED:
	    cprintf(ch, "But you are mounted?\r\n");
	    break;
	case POSITION_FIGHTING:{
		cprintf(ch, "Rest while fighting? are you MAD?\r\n");
	    }
	    break;
	default:{
		act("You stop floating around, and stop to rest your tired bones.",
		    FALSE, ch, 0, 0, TO_CHAR);
		act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SITTING;
	    }
	    break;
    }
}

void do_sleep(struct char_data *ch, const char *argument, int cmd)
{
    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    switch (GET_POS(ch)) {
	case POSITION_STANDING:
	case POSITION_SITTING:
	case POSITION_RESTING:{
		cprintf(ch, "You go to sleep.\r\n");
		act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SLEEPING;
	    }
	    break;
	case POSITION_SLEEPING:{
		cprintf(ch, "You are already sound asleep.\r\n");
	    }
	    break;
	case POSITION_MOUNTED:
	    cprintf(ch, "But you are mounted?\r\n");
	    break;
	case POSITION_FIGHTING:{
		cprintf(ch, "Sleep while fighting? are you MAD?\r\n");
	    }
	    break;
	default:{
		act("You stop floating around, and lie down to sleep.", FALSE, ch, 0, 0,
		    TO_CHAR);
		act("$n stops floating around, and lie down to sleep.", TRUE, ch, 0, 0,
		    TO_ROOM);
		GET_POS(ch) = POSITION_SLEEPING;
	    }
	    break;
    }
}

void do_wake(struct char_data *ch, const char *argument, int cmd)
{
    struct char_data                       *tmp_char = NULL;
    char                                    arg[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0";

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    one_argument(argument, arg);
    if (*arg) {
	if (GET_POS(ch) == POSITION_SLEEPING) {
	    act("You can't wake people up if you are asleep yourself!", FALSE, ch, 0, 0,
		TO_CHAR);
	} else {
	    tmp_char = get_char_room_vis(ch, arg);
	    if (tmp_char) {
		if (tmp_char == ch) {
		    act("If you want to wake yourself up, just type 'wake'", FALSE, ch, 0, 0,
			TO_CHAR);
		} else {
		    if (GET_POS(tmp_char) == POSITION_SLEEPING) {
			if (IS_AFFECTED(tmp_char, AFF_SLEEP)) {
			    act("You can not wake $M up!", FALSE, ch, 0, tmp_char, TO_CHAR);
			} else {
			    act("You wake $M up.", FALSE, ch, 0, tmp_char, TO_CHAR);
			    GET_POS(tmp_char) = POSITION_SITTING;
			    act("You are awakened by $n.", FALSE, ch, 0, tmp_char, TO_VICT);
			}
		    } else {
			act("$N is already awake.", FALSE, ch, 0, tmp_char, TO_CHAR);
		    }
		}
	    } else {
		cprintf(ch, "You do not see that person here.\r\n");
	    }
	}
    } else {
	if (IS_AFFECTED(ch, AFF_SLEEP)) {
	    cprintf(ch, "You can't wake up!\r\n");
	} else {
	    if (GET_POS(ch) > POSITION_SLEEPING)
		cprintf(ch, "You are already awake...\r\n");
	    else {
		cprintf(ch, "You wake, and sit up.\r\n");
		act("$n awakens.", TRUE, ch, 0, 0, TO_ROOM);
		GET_POS(ch) = POSITION_SITTING;
	    }
	}
    }
}

void do_follow(struct char_data *ch, const char *argument, int cmd)
{
    char                                    name[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
    struct char_data                       *leader = NULL;

    if (DEBUG)
	log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
		 VNULL(argument), cmd);

    only_argument(argument, name);

    if (*name) {
	if (!(leader = get_char_room_vis(ch, name))) {
	    cprintf(ch, "I see no person by that name here!\r\n");
	    return;
	}
    } else {
	cprintf(ch, "Who do you wish to follow?\r\n");
	return;
    }

    if (IS_AFFECTED(ch, AFF_GROUP)) {
	REMOVE_BIT(ch->specials.affected_by, AFF_GROUP);
    }
    if (IS_AFFECTED(ch, AFF_CHARM) && (ch->master)) {
	act("But you only feel like following $N!", FALSE, ch, 0, ch->master, TO_CHAR);
    } else {						       /* Not Charmed follow person */

	if (leader == ch) {
	    if (!ch->master) {
		cprintf(ch, "You are already following yourself.\r\n");
		return;
	    }
	    stop_follower(ch);
	} else {
	    if (circle_follow(ch, leader)) {
		act("Sorry, but following in 'loops' is not allowed", FALSE, ch, 0, 0, TO_CHAR);
		return;
	    }
	    if (ch->master)
		stop_follower(ch);

	    add_follower(ch, leader);
	}
    }
}