nakedmudv3.6/
nakedmudv3.6/lib/
nakedmudv3.6/lib/help/A/
nakedmudv3.6/lib/help/B/
nakedmudv3.6/lib/help/C/
nakedmudv3.6/lib/help/D/
nakedmudv3.6/lib/help/G/
nakedmudv3.6/lib/help/H/
nakedmudv3.6/lib/help/J/
nakedmudv3.6/lib/help/L/
nakedmudv3.6/lib/help/M/
nakedmudv3.6/lib/help/O/
nakedmudv3.6/lib/help/P/
nakedmudv3.6/lib/help/R/
nakedmudv3.6/lib/help/S/
nakedmudv3.6/lib/help/W/
nakedmudv3.6/lib/logs/
nakedmudv3.6/lib/misc/
nakedmudv3.6/lib/players/
nakedmudv3.6/lib/txt/
nakedmudv3.6/lib/world/
nakedmudv3.6/lib/world/examples/
nakedmudv3.6/lib/world/examples/mproto/
nakedmudv3.6/lib/world/examples/oproto/
nakedmudv3.6/lib/world/examples/reset/
nakedmudv3.6/lib/world/examples/rproto/
nakedmudv3.6/lib/world/examples/trigger/
nakedmudv3.6/lib/world/limbo/
nakedmudv3.6/lib/world/limbo/room/
nakedmudv3.6/lib/world/limbo/rproto/
nakedmudv3.6/src/alias/
nakedmudv3.6/src/dyn_vars/
nakedmudv3.6/src/editor/
nakedmudv3.6/src/example_module/
nakedmudv3.6/src/help2/
nakedmudv3.6/src/set_val/
nakedmudv3.6/src/socials/
nakedmudv3.6/src/time/
/*
 * This file handles command interpreting
 */
#include <sys/types.h>
#include <stdio.h>

/* include main header file */
#include "mud.h"
#include "utils.h"
#include "character.h"
#include "socket.h"
#include "room.h"
#include "commands.h"
#include "action.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "scripts/scripts.h"



//*****************************************************************************
// optional modules
//*****************************************************************************
#ifdef MODULE_FACULTY
#include "faculty/faculty.h"
#endif
#ifdef MODULE_ALIAS
#include "alias/alias.h"
#endif



//*****************************************************************************
// local variables and functions
//*****************************************************************************
NEAR_MAP *cmd_table = NULL;

void init_commands() {
  cmd_table = newNearMap();

  //***************************************************************************
  // This is for core functions ONLY! If you have a module that adds new
  // functions to the MUD, they should be added in the init_xxx() function
  // associated with your module.
  //***************************************************************************
  add_cmd("back",       NULL, cmd_back,     "player", FALSE);
  add_cmd("commands",   NULL, cmd_commands, "player", FALSE);
  add_cmd("compress",   NULL, cmd_compress, "player", FALSE);
  add_cmd("groupcmds",  NULL, cmd_groupcmds,"player", FALSE);
  add_cmd("look",       "l",  cmd_look,     "player", FALSE);
  add_cmd("more",       NULL, cmd_more,     "player", FALSE);
  add_cmd_check("look", chk_conscious);
}

bool cmd_exists(const char *cmd) {
  return nearMapKeyExists(cmd_table, cmd);
}

void remove_cmd(const char *cmd) {
  CMD_DATA *old_cmd = nearMapRemove(cmd_table, cmd);
  if(old_cmd) deleteCmd(old_cmd);
}

void add_cmd(const char *cmd, const char *sort_by, COMMAND(func),
	     const char *user_group, bool interrupts) {
  // if we've already got a command named this, remove it
  remove_cmd(cmd);

  // add in the new command
  nearMapPut(cmd_table, cmd, sort_by, 
	     newCmd(cmd, func, user_group, interrupts));
}

void add_py_cmd(const char *cmd, const char *sort_by, void *pyfunc,
	     const char *user_group, bool interrupts) {
  // if we've already got a command named this, remove it
  remove_cmd(cmd);

  // add in the new command
  nearMapPut(cmd_table, cmd, sort_by, 
	     newPyCmd(cmd, pyfunc, user_group, interrupts));
}

void add_cmd_check(const char *cmd, CMD_CHK(func)) {
  CMD_DATA *data = nearMapGet(cmd_table, cmd, FALSE);
  if(data != NULL)
    cmdAddCheck(data, func);
}

void add_py_cmd_check(const char *cmd, void *pyfunc) {
  CMD_DATA *data = nearMapGet(cmd_table, cmd, FALSE);
  if(data != NULL)
    cmdAddPyCheck(data, pyfunc);
}

// show the character all of the commands in the specified group(s).
void show_commands(CHAR_DATA *ch, const char *user_groups) {
  BUFFER           *buf = newBuffer(MAX_BUFFER);
  NEAR_ITERATOR *near_i = newNearIterator(cmd_table);
  const char    *abbrev = NULL;
  CMD_DATA         *cmd = NULL;
  int               col = 0;

  // go over all of our buckets
  ITERATE_NEARMAP(abbrev, cmd, near_i) {
    if(is_keyword(user_groups, cmdGetUserGroup(cmd), FALSE)) {
      bprintf(buf, "%-13.13s", cmdGetName(cmd));
      if (!(++col % 6))
	bufferCat(buf, "\r\n");
    }
  } deleteNearIterator(near_i);

  // do room commands as well
  if(roomGetCmdTable(charGetRoom(ch)) != NULL) {
    near_i = newNearIterator(roomGetCmdTable(charGetRoom(ch)));
    abbrev = NULL;
    cmd    = NULL;
    bufferCat(buf, "{c");
    ITERATE_NEARMAP(abbrev, cmd, near_i) {
      if(is_keyword(user_groups, cmdGetUserGroup(cmd), FALSE)) {
	bprintf(buf, "%-13.13s", cmdGetName(cmd));
	if (!(++col % 6))
	  bufferCat(buf, "\r\n");
      }
    } deleteNearIterator(near_i);
    bufferCat(buf, "{n");
  }

  // tag on our last newline if neccessary, and show commands
  if (col % 6) bprintf(buf, "\r\n");
  text_to_char(ch, bufferString(buf));
  deleteBuffer(buf);
}


// tries to pull a usable command from the near-table and use it. Returns
// TRUE if a usable command was found (even if it failed) and false otherwise.
bool try_use_cmd_table(CHAR_DATA *ch, NEAR_MAP *table, const char *command, 
		       char *arg, bool abbrev_ok) {
  if(abbrev_ok == FALSE) {
    CMD_DATA *cmd = nearMapGet(table, command, FALSE);
    if(cmd == NULL || !is_keyword(bitvectorGetBits(charGetUserGroups(ch)),
				  cmdGetUserGroup(cmd), FALSE))
      return FALSE;
    else {
      charTryCmd(ch, cmd, arg); 
      return TRUE;
    }
  }
  else {
    // try to look up the possible commands
    LIST *cmd_list = nearMapGetAllMatches(table, command);
    bool cmd_found = FALSE;
    if(cmd_list != NULL) {
      LIST_ITERATOR *cmd_i = newListIterator(cmd_list);
      CMD_DATA        *cmd = NULL;
      ITERATE_LIST(cmd, cmd_i) {
	if(is_keyword(bitvectorGetBits(charGetUserGroups(ch)), 
		      cmdGetUserGroup(cmd), FALSE)) {
	  charTryCmd(ch, cmd, arg); 
	  cmd_found = TRUE;
	  break;
	}
      } deleteListIterator(cmd_i);
      deleteList(cmd_list);
    }
    return cmd_found;
  }
}


void handle_cmd_input(SOCKET_DATA *dsock, char *arg) {
  CHAR_DATA *ch;
  if ((ch = socketGetChar(dsock)) == NULL)
    return;
  do_cmd(ch, arg, TRUE);
}


void do_cmd(CHAR_DATA *ch, char *arg, bool aliases_ok)  {
  char command[MAX_BUFFER];

  // make sure we've got a command to try
  if(!arg || !*arg)
    return;

  // if we are leading with a non-character, we are trying to do a short-form
  // command (e.g. ' for say, " for gossip). Just take the first character
  // and use the rest as the arg
  if(isalpha(*arg) || isdigit(*arg))
    arg = one_arg(arg, command);
  else {
    *command     = *arg;
    *(command+1) = '\0';
    arg++;
    // and skip all spaces
    while(isspace(*arg))
      arg++;
  }

#ifdef MODULE_ALIAS
  if(aliases_ok && try_alias(ch, command, arg))
    return;
#endif

  // check to see if it's a faculty command
#ifdef MODULE_FACULTY
  if(try_use_faculty(ch, command))
    return;
#endif

  // first try room commands then world commands
  if(!charGetRoom(ch) || 
     !try_use_cmd_table(ch,roomGetCmdTable(charGetRoom(ch)),command,arg,FALSE))
    if(!try_use_cmd_table(ch, cmd_table, command, arg, TRUE))
      text_to_char(ch, "No such command.\r\n");
}