/* ************************************************************************
*  file: Interpreter.c , Command interpreter module.      Part of DIKUMUD *
*  Usage: Procedures interpreting user command                            *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */
/* This won't work */

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

#define COMMANDO(number,min_pos,pointer,min_level) {      \
  cmd_info[(number)].command_pointer = (pointer);         \
  cmd_info[(number)].minimum_position = (min_pos);        \
  cmd_info[(number)].minimum_level = (min_level); }

#define NOT !
#define AND &&
#define OR ||

#define STATE(d) ((d)->connected)
#define MAX_CMD_LIST 250

extern const struct title_type titles[4][25];
extern char motd[MAX_STRING_LENGTH];
extern struct char_data *character_list;
extern struct player_index_element *player_table;
extern int top_of_p_table;
extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern struct room_data *world;
struct command_info cmd_info[MAX_CMD_LIST];


/* external fcntls */

void set_title (struct char_data *ch);
void init_char (struct char_data *ch);
void store_to_char (struct char_file_u *st, struct char_data *ch);
int create_entry (char *name);
int special (struct char_data *ch, int cmd, char *arg);


void do_action (struct char_data *ch, char *arg, int cmd);
void do_practice (struct char_data *ch, char *arg, int cmd);


char *command[] = { "north",    /* 1 */
  "east",
  "south",
  "west",
  "up",
  "down",
  "enter",
  "exits",
  "kiss",
  "get",
  "drink",                      /* 11 */
  "eat",
  "wear",
  "wield",
  "look",
  "score",
  "say",
  "shout",
  "tell",
  "inventory",
  "qui",                        /* 21 */
  "bounce",
  "smile",
  "dance",
  "kill",
  "cackle",
  "laugh",
  "giggle",
  "shake",
  "puke",
  "growl",                      /* 31 */
  "scream",
  "insult",
  "comfort",
  "nod",
  "sigh",
  "sulk",
  "help",
  "who",
  "emote",
  "echo",                       /* 41 */
  "stand",
  "sit",
  "rest",
  "sleep",
  "wake",
  "force",
  "transfer",
  "hug",
  "snuggle",
  "cuddle",                     /* 51 */
  "nuzzle",
  "cry",
  "news",
  "equipment",
  "buy",
  "sell",
  "value",
  "list",
  "drop",
  "goto",                       /* 61 */
  "weather",
  "read",
  "pour",
  "grab",
  "remove",
  "put",
  "shutdow",
  "save",
  "hit",
  "string",                     /* 71 */
  "give",
  "quit",
  "stat",
  "set",
  "time",
  "load",
  "purge",
  "shutdown",
  "idea",
  "typo",                       /* 81 */
  "bug",
  "whisper",
  "cast",
  "at",
  "ask",
  "order",
  "sip",
  "taste",
  "snoop",
  "follow",                     /* 91 */
  "rent",
  "offer",
  "poke",
  "advance",
  "accuse",
  "grin",
  "bow",
  "open",
  "close",
  "lock",                       /* 101 */
  "unlock",
  "leave",
  "applaud",
  "blush",
  "burp",
  "chuckle",
  "clap",
  "cough",
  "curtsey",
  "fart",                       /* 111 */
  "flip",
  "fondle",
  "frown",
  "gasp",
  "glare",
  "groan",
  "grope",
  "hiccup",
  "lick",
  "love",                       /* 121 */
  "moan",
  "nibble",
  "pout",
  "purr",
  "ruffle",
  "shiver",
  "shrug",
  "sing",
  "slap",
  "smirk",                      /* 131 */
  "snap",
  "sneeze",
  "snicker",
  "sniff",
  "snore",
  "spit",
  "squeeze",
  "stare",
  "strut",
  "thank",                      /* 141 */
  "twiddle",
  "wave",
  "whistle",
  "wiggle",
  "wink",
  "yawn",
  "snowball",
  "write",
  "hold",
  "flee",                       /* 151 */
  "sneak",
  "hide",
  "backstab",
  "pick",
  "steal",
  "bash",
  "rescue",
  "kick",
  "french",
  "comb",                       /* 161 */
  "massage",
  "tickle",
  "practice",
  "pat",
  "examine",
  "take",
  "info",
  "'",
  "practise",
  "curse",                      /* 171 */
  "use",
  "where",
  "levels",
  "reroll",
  "pray",
  ",",
  "beg",
  "bleed",
  "cringe",
  "daydream",                   /* 181 */
  "fume",
  "grovel",
  "hop",
  "nudge",
  "peer",
  "point",
  "ponder",
  "punch",
  "snarl",
  "spank",                      /* 191 */
  "steam",
  "tackle",
  "taunt",
  "think",
  "whine",
  "worship",
  "yodel",
  "brief",
  "wiz",
  "consider",                   /* 201 */
  "group",
  "restore",
  "return",
  "switch",                     /* 205 */
  "quaff",
  "recite",
  "users",
  "pose",
  "noshout",
  "wizhelp",                    /* 211 */
  "credits",
  "compact",
  "wizlock",
  "notell",
  "noemote",                    /* 215 */
  "freeze",
  "gol",
  "wizlist",
  ";",
  "\n"
};


char *fill[] = { "in",
  "from",
  "with",
  "the",
  "on",
  "at",
  "to",
  "\n"
};

int search_block (char *arg, char **list, bool exact)
{
  register int i, l;

  /* Make into lower case, and get length of string */
  for (l = 0; *(arg + l); l++)
    *(arg + l) = LOWER (*(arg + l));

  if (exact) {
    for (i = 0; **(list + i) != '\n'; i++)
      if (!strcmp (arg, *(list + i)))
        return (i);
  } else {
    if (!l)
      l = 1;                    /* Avoid "" to match the first available string */
    for (i = 0; **(list + i) != '\n'; i++)
      if (!strncmp (arg, *(list + i), l))
        return (i);
  }

  return (-1);
}


int old_search_block (char *argument, int begin, int length, char **list,
  int mode)
{
  int guess, found, search;

  /* If the word contain 0 letters, then a match is already found */
  found = (length < 1);

  guess = 0;

  /* Search for a match */

  if (mode)
    while (NOT found AND * (list[guess]) != '\n') {
      found = (length == (int)strlen (list[guess]));
      for (search = 0; (search < length AND found); search++)
        found = (*(argument + begin + search) == *(list[guess] + search));
      guess++;
  } else {
    while (NOT found AND * (list[guess]) != '\n') {
      found = 1;
      for (search = 0; (search < length AND found); search++)
        found = (*(argument + begin + search) == *(list[guess] + search));
      guess++;
    }
  }

  return (found ? guess : -1);
}

void command_interpreter (struct char_data *ch, char *argument)
{
  int look_at, cmd, begin;
  extern int no_specials;

  REMOVE_BIT (ch->specials.affected_by, AFF_HIDE);

  /* Find first non blank */
  for (begin = 0; (*(argument + begin) == ' '); begin++);

  /* Find length of first word */
  for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++)

    /* Make all letters lower case AND find length */
    *(argument + begin + look_at) = LOWER (*(argument + begin + look_at));


  cmd = old_search_block (argument, begin, look_at, command, 0);


  if (!cmd)
    return;

  if (cmd > 0 && GET_LEVEL (ch) < cmd_info[cmd].minimum_level) {
    send_to_char ("Arglebargle, glop-glyf!?!\n\r", ch);
    return;
  }

  if (cmd > 0 && (cmd_info[cmd].command_pointer != 0)) {
    if (GET_POS (ch) < cmd_info[cmd].minimum_position)
      switch (GET_POS (ch)) {
      case POSITION_DEAD:
        send_to_char ("Lie still; you are DEAD!!! :-( \n\r", ch);
        break;
      case POSITION_INCAP:
      case POSITION_MORTALLYW:
        send_to_char
          ("You are in a pretty bad shape, unable to do anything!\n\r", ch);
        break;

      case POSITION_STUNNED:
        send_to_char
          ("All you can do right now, is think about the stars!\n\r", ch);
        break;
      case POSITION_SLEEPING:
        send_to_char ("In your dreams, or what?\n\r", ch);
        break;
      case POSITION_RESTING:
        send_to_char ("Nah... You feel too relaxed to do that..\n\r", ch);
        break;
      case POSITION_SITTING:
        send_to_char ("Maybe you should get on your feet first?\n\r", ch);
        break;
      case POSITION_FIGHTING:
        send_to_char ("No way! You are fighting for your life!\n\r", ch);
        break;
    } else {
      if (IS_SET (ch->specials.act, PLR_FREEZE) && !IS_NPC (ch)) {
        send_to_char ("You're totally frozen!\n\r", ch);
        return;
      }

      if (!no_specials && special (ch, cmd, argument + begin + look_at))
        return;

      ((*cmd_info[cmd].command_pointer)
        (ch, argument + begin + look_at, cmd));
    }
    return;
  }
  if (cmd > 0 && (cmd_info[cmd].command_pointer == 0))
    send_to_char ("Sorry, but that command has yet to be implemented...\n\r",
      ch);
  else
    send_to_char ("Arglebargle, glop-glyf!?!\n\r", ch);
}

void argument_interpreter (char *argument, char *first_arg, char *second_arg)
{
  int look_at, found, begin;

  found = begin = 0;

  do {
    /* Find first non blank */
    for (; *(argument + begin) == ' '; begin++);

    /* Find length of first word */
    for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++)

      /* Make all letters lower case,
         AND copy them to first_arg */
      *(first_arg + look_at) = LOWER (*(argument + begin + look_at));

    *(first_arg + look_at) = '\0';
    begin += look_at;

  }
  while (fill_word (first_arg));

  do {
    /* Find first non blank */
    for (; *(argument + begin) == ' '; begin++);

    /* Find length of first word */
    for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++)

      /* Make all letters lower case,
         AND copy them to second_arg */
      *(second_arg + look_at) = LOWER (*(argument + begin + look_at));

    *(second_arg + look_at) = '\0';
    begin += look_at;

  }
  while (fill_word (second_arg));
}

int is_number (char *str)
{
  int look_at;

  if (*str == '\0')
    return (0);

  for (look_at = 0; *(str + look_at) != '\0'; look_at++)
    if ((*(str + look_at) < '0') || (*(str + look_at) > '9'))
      return (0);
  return (1);
}

/*  Quinn substituted a new one-arg for the old one.. I thought returning a
    char pointer would be neat, and avoiding the func-calls would save a
    little time... If anyone feels pissed, I'm sorry.. Anyhow, the code is
    snatched from the old one, so it outta work..

void one_argument(char *argument,char *first_arg )
{
  static char dummy[MAX_STRING_LENGTH];

  argument_interpreter(argument,first_arg,dummy);
}

*/


/* find the first sub-argument of a string, return pointer to first char in
   primary argument, following the sub-arg                  */
char *one_argument (char *argument, char *first_arg)
{
  int found, begin, look_at;

  found = begin = 0;

  do {
    /* Find first non blank */
    for (; isspace ((int)*(argument + begin)); begin++);

    /* Find length of first word */
    for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++)

      /* Make all letters lower case,
         AND copy them to first_arg */
      *(first_arg + look_at) = LOWER (*(argument + begin + look_at));

    *(first_arg + look_at) = '\0';
    begin += look_at;
  }
  while (fill_word (first_arg));

  return (argument + begin);
}








int fill_word (char *argument)
{
  return (search_block (argument, fill, TRUE) >= 0);
}





/* determine if a given string is an abbreviation of another */
int is_abbrev (char *arg1, char *arg2)
{
  if (!*arg1)
    return (0);

  for (; *arg1; arg1++, arg2++)
    if (LOWER (*arg1) != LOWER (*arg2))
      return (0);

  return (1);
}




/* return first 'word' plus trailing substring of input string */
void half_chop (char *string, char *arg1, char *arg2)
{
  for (; isspace ((int)*string); string++);

  for (; !isspace ((int)(*arg1 = *string)) && *string; string++, arg1++);

  *arg1 = '\0';

  for (; isspace ((int)*string); string++);

  for (; *arg2 = *string; string++, arg2++);
}



int special (struct char_data *ch, int cmd, char *arg)
{
  register struct obj_data *i;
  register struct char_data *k;
  int j;

  /* special in room? */
  if (world[ch->in_room].funct)
    if ((*world[ch->in_room].funct) (ch, cmd, arg))
      return (1);

  /* special in equipment list? */
  for (j = 0; j <= (MAX_WEAR - 1); j++)
    if (ch->equipment[j] && ch->equipment[j]->item_number >= 0)
      if (obj_index[ch->equipment[j]->item_number].func)
        if ((*obj_index[ch->equipment[j]->item_number].func)
          (ch, cmd, arg))
          return (1);

  /* special in inventory? */
  for (i = ch->carrying; i; i = i->next_content)
    if (i->item_number >= 0)
      if (obj_index[i->item_number].func)
        if ((*obj_index[i->item_number].func) (ch, cmd, arg))
          return (1);

  /* special in mobile present? */
  for (k = world[ch->in_room].people; k; k = k->next_in_room)
    if (IS_MOB (k))
      if (mob_index[k->nr].func)
        if ((*mob_index[k->nr].func) (ch, cmd, arg))
          return (1);

  /* special in object present? */
  for (i = world[ch->in_room].contents; i; i = i->next_content)
    if (i->item_number >= 0)
      if (obj_index[i->item_number].func)
        if ((*obj_index[i->item_number].func) (ch, cmd, arg))
          return (1);


  return (0);
}

void assign_command_pointers (void)
{
  int position;

  for (position = 0; position < MAX_CMD_LIST; position++)
    cmd_info[position].command_pointer = 0;

  COMMANDO (1, POSITION_STANDING, do_move, 0);
  COMMANDO (2, POSITION_STANDING, do_move, 0);
  COMMANDO (3, POSITION_STANDING, do_move, 0);
  COMMANDO (4, POSITION_STANDING, do_move, 0);
  COMMANDO (5, POSITION_STANDING, do_move, 0);
  COMMANDO (6, POSITION_STANDING, do_move, 0);
  COMMANDO (7, POSITION_STANDING, do_enter, 0);
  COMMANDO (8, POSITION_RESTING, do_exits, 0);
  COMMANDO (9, POSITION_RESTING, do_action, 0);
  COMMANDO (10, POSITION_RESTING, do_get, 0);
  COMMANDO (11, POSITION_RESTING, do_drink, 0);
  COMMANDO (12, POSITION_RESTING, do_eat, 0);
  COMMANDO (13, POSITION_RESTING, do_wear, 0);
  COMMANDO (14, POSITION_RESTING, do_wield, 0);
  COMMANDO (15, POSITION_RESTING, do_look, 0);
  COMMANDO (16, POSITION_DEAD, do_score, 0);
  COMMANDO (17, POSITION_RESTING, do_say, 0);
  COMMANDO (18, POSITION_RESTING, do_shout, 0);
  COMMANDO (19, POSITION_DEAD, do_tell, 0);
  COMMANDO (20, POSITION_DEAD, do_inventory, 0);
  COMMANDO (21, POSITION_DEAD, do_qui, 0);
  COMMANDO (22, POSITION_STANDING, do_action, 0);
  COMMANDO (23, POSITION_RESTING, do_action, 0);
  COMMANDO (24, POSITION_STANDING, do_action, 0);
  COMMANDO (25, POSITION_FIGHTING, do_kill, 0);
  COMMANDO (26, POSITION_RESTING, do_action, 0);
  COMMANDO (27, POSITION_RESTING, do_action, 0);
  COMMANDO (28, POSITION_RESTING, do_action, 0);
  COMMANDO (29, POSITION_RESTING, do_action, 0);
  COMMANDO (30, POSITION_RESTING, do_action, 0);
  COMMANDO (31, POSITION_RESTING, do_action, 0);
  COMMANDO (32, POSITION_RESTING, do_action, 0);
  COMMANDO (33, POSITION_RESTING, do_insult, 0);
  COMMANDO (34, POSITION_RESTING, do_action, 0);
  COMMANDO (35, POSITION_RESTING, do_action, 0);
  COMMANDO (36, POSITION_RESTING, do_action, 0);
  COMMANDO (37, POSITION_RESTING, do_action, 0);
  COMMANDO (38, POSITION_DEAD, do_help, 0);
  COMMANDO (39, POSITION_DEAD, do_who, 0);
  COMMANDO (40, POSITION_SLEEPING, do_emote, 1);
  COMMANDO (41, POSITION_SLEEPING, do_echo, 21);
  COMMANDO (42, POSITION_RESTING, do_stand, 0);
  COMMANDO (43, POSITION_RESTING, do_sit, 0);
  COMMANDO (44, POSITION_RESTING, do_rest, 0);
  COMMANDO (45, POSITION_SLEEPING, do_sleep, 0);
  COMMANDO (46, POSITION_SLEEPING, do_wake, 0);
  COMMANDO (47, POSITION_SLEEPING, do_force, 22);
  COMMANDO (48, POSITION_SLEEPING, do_trans, 22);
  COMMANDO (49, POSITION_RESTING, do_action, 0);
  COMMANDO (50, POSITION_RESTING, do_action, 0);
  COMMANDO (51, POSITION_RESTING, do_action, 0);
  COMMANDO (52, POSITION_RESTING, do_action, 0);
  COMMANDO (53, POSITION_RESTING, do_action, 0);
  COMMANDO (54, POSITION_SLEEPING, do_news, 0);
  COMMANDO (55, POSITION_SLEEPING, do_equipment, 0);
  COMMANDO (56, POSITION_STANDING, do_not_here, 0);
  COMMANDO (57, POSITION_STANDING, do_not_here, 0);
  COMMANDO (58, POSITION_STANDING, do_not_here, 0);
  COMMANDO (59, POSITION_STANDING, do_not_here, 0);
  COMMANDO (60, POSITION_RESTING, do_drop, 0);
  COMMANDO (61, POSITION_SLEEPING, do_goto, 21);
  COMMANDO (62, POSITION_RESTING, do_weather, 0);
  COMMANDO (63, POSITION_RESTING, do_read, 0);
  COMMANDO (64, POSITION_STANDING, do_pour, 0);
  COMMANDO (65, POSITION_RESTING, do_grab, 0);
  COMMANDO (66, POSITION_RESTING, do_remove, 0);
  COMMANDO (67, POSITION_RESTING, do_put, 0);
  COMMANDO (68, POSITION_DEAD, do_shutdow, 24);
  COMMANDO (69, POSITION_SLEEPING, do_save, 0);
  COMMANDO (70, POSITION_FIGHTING, do_hit, 0);
  COMMANDO (71, POSITION_SLEEPING, do_string, 23);
  COMMANDO (72, POSITION_RESTING, do_give, 0);
  COMMANDO (73, POSITION_DEAD, do_quit, 0);
  COMMANDO (74, POSITION_DEAD, do_stat, 21);
  COMMANDO (75, POSITION_SLEEPING, do_set, 23);
  COMMANDO (76, POSITION_DEAD, do_time, 0);
  COMMANDO (77, POSITION_DEAD, do_load, 22);
  COMMANDO (78, POSITION_DEAD, do_purge, 22);
  COMMANDO (79, POSITION_DEAD, do_shutdown, 24);
  COMMANDO (80, POSITION_DEAD, do_idea, 0);
  COMMANDO (81, POSITION_DEAD, do_typo, 0);
  COMMANDO (82, POSITION_DEAD, do_bug, 0);
  COMMANDO (83, POSITION_RESTING, do_whisper, 0);
  COMMANDO (84, POSITION_SITTING, do_cast, 1);
  COMMANDO (85, POSITION_DEAD, do_at, 21);
  COMMANDO (86, POSITION_RESTING, do_ask, 0);
  COMMANDO (87, POSITION_RESTING, do_order, 1);
  COMMANDO (88, POSITION_RESTING, do_sip, 0);
  COMMANDO (89, POSITION_RESTING, do_taste, 0);
  COMMANDO (90, POSITION_DEAD, do_snoop, 21);
  COMMANDO (91, POSITION_RESTING, do_follow, 0);
  COMMANDO (92, POSITION_STANDING, do_not_here, 1);
  COMMANDO (93, POSITION_STANDING, do_not_here, 1);
  COMMANDO (94, POSITION_RESTING, do_action, 0);
  COMMANDO (95, POSITION_DEAD, do_advance, 23);
  COMMANDO (96, POSITION_SITTING, do_action, 0);
  COMMANDO (97, POSITION_RESTING, do_action, 0);
  COMMANDO (98, POSITION_STANDING, do_action, 0);
  COMMANDO (99, POSITION_SITTING, do_open, 0);
  COMMANDO (100, POSITION_SITTING, do_close, 0);
  COMMANDO (101, POSITION_SITTING, do_lock, 0);
  COMMANDO (102, POSITION_SITTING, do_unlock, 0);
  COMMANDO (103, POSITION_STANDING, do_leave, 0);
  COMMANDO (104, POSITION_RESTING, do_action, 0);
  COMMANDO (105, POSITION_RESTING, do_action, 0);
  COMMANDO (106, POSITION_RESTING, do_action, 0);
  COMMANDO (107, POSITION_RESTING, do_action, 0);
  COMMANDO (108, POSITION_RESTING, do_action, 0);
  COMMANDO (109, POSITION_RESTING, do_action, 0);
  COMMANDO (110, POSITION_STANDING, do_action, 0);
  COMMANDO (111, POSITION_RESTING, do_action, 0);
  COMMANDO (112, POSITION_STANDING, do_action, 0);
  COMMANDO (113, POSITION_RESTING, do_action, 0);
  COMMANDO (114, POSITION_RESTING, do_action, 0);
  COMMANDO (115, POSITION_RESTING, do_action, 0);
  COMMANDO (116, POSITION_RESTING, do_action, 0);
  COMMANDO (117, POSITION_RESTING, do_action, 0);
  COMMANDO (118, POSITION_RESTING, do_action, 0);
  COMMANDO (119, POSITION_RESTING, do_action, 0);
  COMMANDO (120, POSITION_RESTING, do_action, 0);
  COMMANDO (121, POSITION_RESTING, do_action, 0);
  COMMANDO (122, POSITION_RESTING, do_action, 0);
  COMMANDO (123, POSITION_RESTING, do_action, 0);
  COMMANDO (124, POSITION_RESTING, do_action, 0);
  COMMANDO (125, POSITION_RESTING, do_action, 0);
  COMMANDO (126, POSITION_STANDING, do_action, 0);
  COMMANDO (127, POSITION_RESTING, do_action, 0);
  COMMANDO (128, POSITION_RESTING, do_action, 0);
  COMMANDO (129, POSITION_RESTING, do_action, 0);
  COMMANDO (130, POSITION_RESTING, do_action, 0);
  COMMANDO (131, POSITION_RESTING, do_action, 0);
  COMMANDO (132, POSITION_RESTING, do_action, 0);
  COMMANDO (133, POSITION_RESTING, do_action, 0);
  COMMANDO (134, POSITION_RESTING, do_action, 0);
  COMMANDO (135, POSITION_RESTING, do_action, 0);
  COMMANDO (136, POSITION_SLEEPING, do_action, 0);
  COMMANDO (137, POSITION_STANDING, do_action, 0);
  COMMANDO (138, POSITION_RESTING, do_action, 0);
  COMMANDO (139, POSITION_RESTING, do_action, 0);
  COMMANDO (140, POSITION_STANDING, do_action, 0);
  COMMANDO (141, POSITION_RESTING, do_action, 0);
  COMMANDO (142, POSITION_RESTING, do_action, 0);
  COMMANDO (143, POSITION_RESTING, do_action, 0);
  COMMANDO (144, POSITION_RESTING, do_action, 0);
  COMMANDO (145, POSITION_STANDING, do_action, 0);
  COMMANDO (146, POSITION_RESTING, do_action, 0);
  COMMANDO (147, POSITION_RESTING, do_action, 0);
  COMMANDO (148, POSITION_STANDING, do_action, 22);
  COMMANDO (149, POSITION_STANDING, do_write, 1);
  COMMANDO (150, POSITION_RESTING, do_grab, 1);
  COMMANDO (151, POSITION_FIGHTING, do_flee, 1);
  COMMANDO (152, POSITION_STANDING, do_sneak, 1);
  COMMANDO (153, POSITION_RESTING, do_hide, 1);
  COMMANDO (154, POSITION_STANDING, do_backstab, 1);
  COMMANDO (155, POSITION_STANDING, do_pick, 1);
  COMMANDO (156, POSITION_STANDING, do_steal, 1);
  COMMANDO (157, POSITION_FIGHTING, do_bash, 1);
  COMMANDO (158, POSITION_FIGHTING, do_rescue, 1);
  COMMANDO (159, POSITION_FIGHTING, do_kick, 1);
  COMMANDO (160, POSITION_RESTING, do_action, 0);
  COMMANDO (161, POSITION_RESTING, do_action, 0);
  COMMANDO (162, POSITION_RESTING, do_action, 0);
  COMMANDO (163, POSITION_RESTING, do_action, 0);
  COMMANDO (164, POSITION_RESTING, do_practice, 1);
  COMMANDO (165, POSITION_RESTING, do_action, 0);
  COMMANDO (166, POSITION_SITTING, do_examine, 0);
  COMMANDO (167, POSITION_RESTING, do_get, 0);  /* TAKE */
  COMMANDO (168, POSITION_SLEEPING, do_info, 0);
  COMMANDO (169, POSITION_RESTING, do_say, 0);
  COMMANDO (170, POSITION_RESTING, do_practice, 1);
  COMMANDO (171, POSITION_RESTING, do_action, 0);
  COMMANDO (172, POSITION_SITTING, do_use, 1);
  COMMANDO (173, POSITION_DEAD, do_where, 1);
  COMMANDO (174, POSITION_DEAD, do_levels, 0);
  COMMANDO (175, POSITION_DEAD, do_reroll, 24);
  COMMANDO (176, POSITION_SITTING, do_action, 0);
  COMMANDO (177, POSITION_SLEEPING, do_emote, 1);
  COMMANDO (178, POSITION_RESTING, do_action, 0);
  COMMANDO (179, POSITION_RESTING, do_action, 0);
  COMMANDO (180, POSITION_RESTING, do_action, 0);
  COMMANDO (181, POSITION_SLEEPING, do_action, 0);
  COMMANDO (182, POSITION_RESTING, do_action, 0);
  COMMANDO (183, POSITION_RESTING, do_action, 0);
  COMMANDO (184, POSITION_RESTING, do_action, 0);
  COMMANDO (185, POSITION_RESTING, do_action, 0);
  COMMANDO (186, POSITION_RESTING, do_action, 0);
  COMMANDO (187, POSITION_RESTING, do_action, 0);
  COMMANDO (188, POSITION_RESTING, do_action, 0);
  COMMANDO (189, POSITION_RESTING, do_action, 0);
  COMMANDO (190, POSITION_RESTING, do_action, 0);
  COMMANDO (191, POSITION_RESTING, do_action, 0);
  COMMANDO (192, POSITION_RESTING, do_action, 0);
  COMMANDO (193, POSITION_RESTING, do_action, 0);
  COMMANDO (194, POSITION_RESTING, do_action, 0);
  COMMANDO (195, POSITION_RESTING, do_action, 0);
  COMMANDO (196, POSITION_RESTING, do_action, 0);
  COMMANDO (197, POSITION_RESTING, do_action, 0);
  COMMANDO (198, POSITION_RESTING, do_action, 0);
  COMMANDO (199, POSITION_DEAD, do_brief, 0);
  COMMANDO (200, POSITION_DEAD, do_wiz, 21);
  COMMANDO (201, POSITION_RESTING, do_consider, 0);
  COMMANDO (202, POSITION_RESTING, do_group, 1);
  COMMANDO (203, POSITION_DEAD, do_restore, 22);
  COMMANDO (204, POSITION_DEAD, do_return, 0);
  COMMANDO (205, POSITION_DEAD, do_switch, 23);
  COMMANDO (206, POSITION_RESTING, do_quaff, 0);
  COMMANDO (207, POSITION_RESTING, do_recite, 0);
  COMMANDO (208, POSITION_DEAD, do_users, 21);
  COMMANDO (209, POSITION_STANDING, do_pose, 0);
  COMMANDO (210, POSITION_SLEEPING, do_noshout, 22);
  COMMANDO (211, POSITION_SLEEPING, do_wizhelp, 21);
  COMMANDO (212, POSITION_DEAD, do_credits, 0);
  COMMANDO (213, POSITION_DEAD, do_compact, 0);
  COMMANDO (214, POSITION_DEAD, do_wizlock, 24);
  COMMANDO (215, POSITION_DEAD, do_notell, 22);
  COMMANDO (216, POSITION_DEAD, do_noemote, 22);
  COMMANDO (217, POSITION_DEAD, do_freeze, 23);
  COMMANDO (218, POSITION_DEAD, do_log, 24);
  COMMANDO (219, POSITION_DEAD, do_wizlist, 0);
  COMMANDO (220, POSITION_DEAD, do_wiz, 21);

}

/* *************************************************************************
*  Stuff for controlling the non-playing sockets (get name, pwd etc)       *
************************************************************************* */




/* locate entry in p_table with entry->name == name. -1 mrks failed search */
int find_name (char *name)
{
  int i;

  for (i = 0; i <= top_of_p_table; i++) {
    if (!str_cmp ((player_table + i)->name, name))
      return (i);
  }

  return (-1);
}


int _parse_name (char *arg, char *name)
{
  int i;

  /* skip whitespaces */
  for (; isspace ((int)*arg); arg++);

  for (i = 0; *name = *arg; arg++, i++, name++)
    if ((*arg < 0) || !isalpha ((int)*arg) || i > 15)
      return (1);

  if (!i)
    return (1);

  return (0);
}





/* deal with newcomers and other non-playing sockets */
void nanny (struct descriptor_data *d, char *arg)
{
  char buf[100];
  int player_i;
  char tmp_name[20];
  struct char_file_u tmp_store;
  struct char_data *ch, *tmp_ch;
  struct descriptor_data *k;
  extern struct descriptor_data *descriptor_list;

  void do_look (struct char_data *ch, char *argument, int cmd);
  void load_char_objs (struct char_data *ch);
  int load_char (char *name, struct char_file_u *char_element);


  switch (STATE (d)) {
  case CON_NME:                /* wait for input of name */
    if (!d->character) {
      CREATE (d->character, struct char_data, 1);
      clear_char (d->character);
      d->character->desc = d;
    }

    for (; isspace ((int)*arg); arg++);
    if (!*arg)
      close_socket (d);
    else {

      if (_parse_name (arg, tmp_name)) {
        SEND_TO_Q ("Illegal name, please try another.", d);
        SEND_TO_Q ("Name: ", d);
        return;
      }


      /* Check if already playing */
      for (k = descriptor_list; k; k = k->next) {
        if ((k->character != d->character) && k->character) {
          if (k->original) {
            if (GET_NAME (k->original) &&
              (str_cmp (GET_NAME (k->original), tmp_name) == 0)) {
              SEND_TO_Q ("Already playing, cannot connect\n\r", d);
              SEND_TO_Q ("Name: ", d);
              return;
            }
          } else {              /* No switch has been made */
            if (GET_NAME (k->character) &&
              (str_cmp (GET_NAME (k->character), tmp_name) == 0)) {
              SEND_TO_Q ("Already playing, cannot connect\n\r", d);
              SEND_TO_Q ("Name: ", d);
              return;
            }
          }
        }
      }


      if ((player_i = load_char (tmp_name, &tmp_store)) > -1) {
        store_to_char (&tmp_store, d->character);

        strcpy (d->pwd, tmp_store.pwd);
        d->pos = player_table[player_i].nr;

        SEND_TO_Q ("Password: ", d);

        STATE (d) = CON_PWDNRM;
      } else {
        /* player unknown gotta make a new */
        CREATE (GET_NAME (d->character), char, strlen (tmp_name) + 1);
        strcpy (GET_NAME (d->character), CAP (tmp_name));

        sprintf (buf, "Did I get that right, %s (Y/N)? ", tmp_name);

        SEND_TO_Q (buf, d);

        STATE (d) = CON_NMECNF;
      }
    }
    break;

  case CON_NMECNF:             /* wait for conf. of new name */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);

    if (*arg == 'y' || *arg == 'Y') {
      SEND_TO_Q ("New character.\n\r", d);

      sprintf (buf, "Give me a password for %s: ", GET_NAME (d->character));

      SEND_TO_Q (buf, d);

      STATE (d) = CON_PWDGET;
    } else {
      if (*arg == 'n' || *arg == 'N') {
        SEND_TO_Q ("Ok, what IS it, then? ", d);
        free (GET_NAME (d->character));
        STATE (d) = CON_NME;
      } else {                  /* Please do Y or N */
        SEND_TO_Q ("Please type Yes or No? ", d);
      }
    }
    break;

  case CON_PWDNRM:             /* get pwd for known player */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);
    if (!*arg)
      close_socket (d);
    else {
      if (strncmp (crypt (arg, d->pwd), d->pwd, 10)) {
        SEND_TO_Q ("Wrong password.\n\r", d);
        SEND_TO_Q ("Password: ", d);
        return;
      }

      for (tmp_ch = character_list; tmp_ch; tmp_ch = tmp_ch->next)
        if (!str_cmp (GET_NAME (d->character), GET_NAME (tmp_ch)) &&
          !tmp_ch->desc && !IS_NPC (tmp_ch)) {
          SEND_TO_Q ("Reconnecting.\n\r", d);
          free_char (d->character);
          tmp_ch->desc = d;
          d->character = tmp_ch;
          tmp_ch->specials.timer = 0;
          STATE (d) = CON_PLYNG;
          act ("$n has reconnected.", TRUE, tmp_ch, 0, 0, TO_ROOM);
          sprintf (buf, "%s[%s] has reconnected.", GET_NAME (d->character),
            d->host);
          log (buf);
          return;
        }


      sprintf (buf, "%s[%s] has connected.", GET_NAME (d->character),
        d->host);
      log (buf);

      SEND_TO_Q (motd, d);
      SEND_TO_Q ("\n\r\n*** PRESS RETURN: ", d);

      STATE (d) = CON_RMOTD;
    }
    break;

  case CON_PWDGET:             /* get pwd for new player */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);

    if (!*arg || strlen (arg) > 10) {
      SEND_TO_Q ("Illegal password.\n\r", d);
      SEND_TO_Q ("Password: ", d);
      return;
    }

    strncpy (d->pwd, crypt (arg, d->character->player.name), 10);
    *(d->pwd + 10) = '\0';

    SEND_TO_Q ("Please retype password: ", d);

    STATE (d) = CON_PWDCNF;
    break;

  case CON_PWDCNF:             /* get confirmation of new pwd  */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);

    if (strncmp (crypt (arg, d->pwd), d->pwd, 10)) {
      SEND_TO_Q ("Passwords don't match.\n\r", d);
      SEND_TO_Q ("Retype password: ", d);
      STATE (d) = CON_PWDGET;
      return;
    }

    SEND_TO_Q ("What is your sex (M/F) ? ", d);
    STATE (d) = CON_QSEX;
    break;

  case CON_QSEX:               /* query sex of new user  */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);
    switch (*arg) {
    case 'm':
    case 'M':
      /* sex MALE */
      d->character->player.sex = SEX_MALE;
      break;

    case 'f':
    case 'F':
      /* sex FEMALE */
      d->character->player.sex = SEX_FEMALE;
      break;

    default:
      SEND_TO_Q ("That's not a sex..\n\r", d);
      SEND_TO_Q ("What IS your sex? :", d);
      return;
      break;
    }

    SEND_TO_Q
      ("\n\rSelect a class:\n\rCleric\n\rThief\n\rWarrior\n\rMagic-user", d);
    SEND_TO_Q ("\n\rClass :", d);
    STATE (d) = CON_QCLASS;
    break;

  case CON_QCLASS:{
      /* skip whitespaces */
      for (; isspace ((int)*arg); arg++);
      switch (*arg) {
      case 'm':
      case 'M':{
          GET_CLASS (d->character) = CLASS_MAGIC_USER;
          init_char (d->character);
          /* create an entry in the file */
          d->pos = create_entry (GET_NAME (d->character));
          save_char (d->character, NOWHERE);
          SEND_TO_Q (motd, d);
          SEND_TO_Q ("\n\r\n*** PRESS RETURN: ", d);
          STATE (d) = CON_RMOTD;
        }
        break;
      case 'c':
      case 'C':{
          GET_CLASS (d->character) = CLASS_CLERIC;
          init_char (d->character);
          /* create an entry in the file */
          d->pos = create_entry (GET_NAME (d->character));
          save_char (d->character, NOWHERE);
          SEND_TO_Q (motd, d);
          SEND_TO_Q ("\n\r\n*** PRESS RETURN: ", d);
          STATE (d) = CON_RMOTD;
        }
        break;
      case 'w':
      case 'W':{
          GET_CLASS (d->character) = CLASS_WARRIOR;
          init_char (d->character);
          /* create an entry in the file */
          d->pos = create_entry (GET_NAME (d->character));
          save_char (d->character, NOWHERE);
          SEND_TO_Q (motd, d);
          SEND_TO_Q ("\n\r\n*** PRESS RETURN: ", d);
          STATE (d) = CON_RMOTD;
        }
        break;
      case 't':
      case 'T':{
          GET_CLASS (d->character) = CLASS_THIEF;
          init_char (d->character);
          /* create an entry in the file */
          d->pos = create_entry (GET_NAME (d->character));
          save_char (d->character, NOWHERE);
          SEND_TO_Q (motd, d);
          SEND_TO_Q ("\n\r\n*** PRESS RETURN: ", d);
          STATE (d) = CON_RMOTD;
        }
        break;

      default:{
          SEND_TO_Q ("\n\rThat's not a class.\n\rClass:", d);
          STATE (d) = CON_QCLASS;
        }
        break;

      }                         /* End Switch */
      if (STATE (d) != CON_QCLASS) {
        sprintf (buf, "%s [%s] new player.", GET_NAME (d->character),
          d->host);
        log (buf);
      }
    }
    break;

  case CON_RMOTD:              /* read CR after printing motd  */
    SEND_TO_Q (MENU, d);
    STATE (d) = CON_SLCT;
    break;

  case CON_SLCT:               /* get selection from main menu */
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);
    switch (*arg) {
    case '0':
      close_socket (d);
      break;

    case '1':
      reset_char (d->character);
      if (d->character->in_room != NOWHERE) {
        log ("Loading chars equipment and transferring to room.");
        load_char_objs (d->character);
        save_char (d->character, NOWHERE);
      }
      send_to_char (WELC_MESSG, d->character);
      d->character->next = character_list;
      character_list = d->character;
      if (d->character->in_room == NOWHERE)
        char_to_room (d->character, real_room (3001));
      else {
        if (real_room (d->character->in_room) > -1)
          char_to_room (d->character, real_room (d->character->in_room));
        else
          char_to_room (d->character, real_room (3001));
      }

      act ("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
      STATE (d) = CON_PLYNG;
      if (!GET_LEVEL (d->character))
        do_start (d->character);
      do_look (d->character, "", 15);
      d->prompt_mode = 1;
      break;

    case '2':
      SEND_TO_Q
        ("Enter a text you'd like others to see when they look at you.\n\r",
        d);
      SEND_TO_Q ("Terminate with a '@'.\n\r", d);
      if (d->character->player.description) {
        SEND_TO_Q ("Old description :\n\r", d);
        SEND_TO_Q (d->character->player.description, d);
        free (d->character->player.description);
        d->character->player.description = 0;
      }
      d->str = &d->character->player.description;
      d->max_str = 240;
      STATE (d) = CON_EXDSCR;
      break;

    case '3':
      SEND_TO_Q (STORY, d);
      STATE (d) = CON_RMOTD;
      break;
    case '4':
      SEND_TO_Q ("Enter a new password: ", d);
      STATE (d) = CON_PWDNEW;
      break;
    default:
      SEND_TO_Q ("Wrong option.\n\r", d);
      SEND_TO_Q (MENU, d);
      break;
    }
    break;
  case CON_PWDNEW:
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);

    if (!*arg || strlen (arg) > 10) {
      SEND_TO_Q ("Illegal password.\n\r", d);
      SEND_TO_Q ("Password: ", d);
      return;
    }

    strncpy (d->pwd, crypt (arg, d->character->player.name), 10);
    *(d->pwd + 10) = '\0';

    SEND_TO_Q ("Please retype password: ", d);

    STATE (d) = CON_PWDNCNF;
    break;
  case CON_PWDNCNF:
    /* skip whitespaces */
    for (; isspace ((int)*arg); arg++);

    if (strncmp (crypt (arg, d->pwd), d->pwd, 10)) {
      SEND_TO_Q ("Passwords don't match.\n\r", d);
      SEND_TO_Q ("Retype password: ", d);
      STATE (d) = CON_PWDNEW;
      return;
    }
    SEND_TO_Q
      ("\n\rDone. You must enter the game to make the change final\n\r", d);
    SEND_TO_Q (MENU, d);
    STATE (d) = CON_SLCT;
    break;
  default:
    log ("Nanny: illegal state of con'ness");
    abort ();
    break;
  }
}