/*
* 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");
}