/*************************************************************************** * file: interp.c , Command interpreter module. Part of DIKUMUD * * Usage: Procedures interpreting user command * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * * * * Copyright (C) 1992, 1993 Michael Chastain, Michael Quan, Mitchell Tse * * Performance optimization and bug fixes by MERC Industries. * * You can use our stuff in any way you like whatsoever so long as this * * copyright notice remains intact. If you like it please drop a line * * to mec@garnet.berkeley.edu. * * * * This is free software and you are benefitting. We hope that you * * share your changes too. What goes around, comes around. * ***************************************************************************/ #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdio.h> #include <memory.h> #include "structs.h" #include "mob.h" #include "obj.h" #include "interp.h" #include "db.h" #include "utils.h" #include "limits.h" extern bool check_social( struct char_data *ch, char *pcomm, int length, char *arg ); extern struct index_data *mob_index; extern struct index_data *obj_index; extern struct room_data *world; struct command_info { char *command_name; /* Name of this command */ DO_FUN *command_pointer; /* Function that does it */ byte minimum_position; /* Position commander must be in */ byte minimum_level; /* Minimum level needed */ ubyte command_number; /* Passed to function as argument */ }; /* * Note that command number is always non-zero for user commands. * Various spec_proc.c functions impose ICKY requirements. * Someday I'll NUKE the arg and pass the command name instead. * * Spec_procs that need fixing: * shop_keeper */ struct command_info cmd_info[] = { /* * Common movement commands. */ { "north", do_move, POSITION_STANDING, 0, 1 }, { "east", do_move, POSITION_STANDING, 0, 2 }, { "south", do_move, POSITION_STANDING, 0, 3 }, { "west", do_move, POSITION_STANDING, 0, 4 }, { "up", do_move, POSITION_STANDING, 0, 5 }, { "down", do_move, POSITION_STANDING, 0, 6 }, /* * Common other commands. * Placed here so one and two letter abbreviations work. */ { "cast", do_cast, POSITION_SITTING, 0, 9 }, { "exits", do_exits, POSITION_RESTING, 0, 9 }, { "get", do_get, POSITION_RESTING, 0, 9 }, { "inventory", do_inventory, POSITION_DEAD, 0, 9 }, { "kill", do_kill, POSITION_FIGHTING, 0, 9 }, { "look", do_look, POSITION_RESTING, 0, 9 }, { "order", do_order, POSITION_RESTING, 0, 9 }, { "rest", do_rest, POSITION_RESTING, 0, 9 }, { "stand", do_stand, POSITION_RESTING, 0, 9 }, { "tell", do_tell, POSITION_RESTING, 0, 9 }, { "wield", do_wield, POSITION_RESTING, 0, 9 }, { "wizhelp", do_wizhelp, POSITION_DEAD, 31, 9 }, /* * Informational commands. */ { "brief", do_brief, POSITION_DEAD, 0, 9 }, { "bug", do_bug, POSITION_DEAD, 0, 9 }, { "compact", do_compact, POSITION_DEAD, 0, 9 }, { "credits", do_credits, POSITION_DEAD, 0, 9 }, { "equipment", do_equipment, POSITION_DEAD, 0, 9 }, { "help", do_help, POSITION_DEAD, 0, 9 }, { "idea", do_idea, POSITION_DEAD, 0, 9 }, { "info", do_info, POSITION_DEAD, 0, 9 }, /* { "inventory", do_inventory, POSITION_DEAD, 0, 9 }, */ { "levels", do_levels, POSITION_DEAD, 0, 9 }, { "news", do_news, POSITION_DEAD, 0, 9 }, { "score", do_score, POSITION_DEAD, 0, 9 }, { "story", do_story, POSITION_DEAD, 0, 9 }, { "tick", do_tick, POSITION_DEAD, 0, 9 }, { "time", do_time, POSITION_DEAD, 0, 9 }, { "title", do_title, POSITION_DEAD, 0, 9 }, { "typo", do_typo, POSITION_DEAD, 0, 9 }, { "weather", do_weather, POSITION_DEAD, 0, 9 }, { "who", do_who, POSITION_DEAD, 0, 9 }, { "wizlist", do_wizlist, POSITION_DEAD, 0, 9 }, /* * Communication commands. */ { "ask", do_ask, POSITION_RESTING, 0, 9 }, { "emote", do_emote, POSITION_RESTING, 0, 9 }, { ",", do_emote, POSITION_RESTING, 0, 9 }, { "gtell", do_grouptell, POSITION_DEAD, 0, 9 }, { ";", do_grouptell, POSITION_DEAD, 0, 9 }, { "insult", do_insult, POSITION_RESTING, 0, 9 }, /* { "order", do_order, POSITION_RESTING, 0, 9 }, */ { "pose", do_pose, POSITION_RESTING, 0, 9 }, { "report", do_report, POSITION_DEAD, 0, 9 }, { "say", do_say, POSITION_RESTING, 0, 9 }, { "'", do_say, POSITION_RESTING, 0, 9 }, { "shout", do_shout, POSITION_RESTING, 0, 9 }, /* { "tell", do_tell, POSITION_RESTING, 0, 9 }, */ { "whisper", do_whisper, POSITION_RESTING, 0, 9 }, /* * Object manipulation commands. */ { "close", do_close, POSITION_RESTING, 0, 9 }, { "drink", do_drink, POSITION_RESTING, 0, 9 }, { "drop", do_drop, POSITION_RESTING, 0, 9 }, { "eat", do_eat, POSITION_RESTING, 0, 9 }, { "fill", do_fill, POSITION_RESTING, 0, 9 }, /* { "get", do_get, POSITION_RESTING, 0, 9 }, */ { "give", do_give, POSITION_RESTING, 0, 9 }, { "grab", do_grab, POSITION_RESTING, 0, 9 }, { "hold", do_grab, POSITION_RESTING, 0, 9 }, { "lock", do_lock, POSITION_RESTING, 0, 9 }, { "open", do_open, POSITION_RESTING, 0, 9 }, { "pour", do_pour, POSITION_RESTING, 0, 9 }, { "put", do_put, POSITION_RESTING, 0, 9 }, { "quaff", do_quaff, POSITION_RESTING, 0, 9 }, { "read", do_read, POSITION_RESTING, 0, 9 }, { "recite", do_recite, POSITION_RESTING, 0, 9 }, { "remove", do_remove, POSITION_RESTING, 0, 9 }, { "sip", do_sip, POSITION_RESTING, 0, 9 }, { "take", do_get, POSITION_RESTING, 0, 9 }, { "junk", do_tap, POSITION_RESTING, 0, 9 }, { "sacrifice", do_tap, POSITION_RESTING, 0, 9 }, { "tap", do_tap, POSITION_RESTING, 0, 9 }, { "taste", do_taste, POSITION_RESTING, 0, 9 }, { "unlock", do_unlock, POSITION_RESTING, 0, 9 }, { "use", do_use, POSITION_RESTING, 0, 9 }, { "wear", do_wear, POSITION_RESTING, 0, 9 }, /* { "wield", do_wield, POSITION_RESTING, 0, 9 }, */ /* * Combat commands. */ { "bash", do_bash, POSITION_FIGHTING, 0, 9 }, { "disarm", do_disarm, POSITION_FIGHTING, 0, 9 }, { "flee", do_flee, POSITION_FIGHTING, 0, 9 }, { "hit", do_hit, POSITION_FIGHTING, 0, 9 }, { "kick", do_kick, POSITION_FIGHTING, 0, 9 }, /* { "kill", do_kill, POSITION_FIGHTING, 0, 9 }, */ { "murder", do_murder, POSITION_FIGHTING, 5, 9 }, { "rescue", do_rescue, POSITION_FIGHTING, 0, 9 }, { "trip", do_trip, POSITION_FIGHTING, 0, 9 }, /* * Position commands. */ /* { "rest", do_rest, POSITION_RESTING, 0, 9 }, */ { "sit", do_sit, POSITION_RESTING, 0, 9 }, { "sleep", do_sleep, POSITION_SLEEPING, 0, 9 }, /* { "stand", do_stand, POSITION_RESTING, 0, 9 }, */ { "wake", do_wake, POSITION_SLEEPING, 0, 9 }, /* * Miscellaneous commands. */ { "backstab", do_backstab, POSITION_STANDING, 0, 9 }, { "bs", do_backstab, POSITION_STANDING, 0, 9 }, /* { "cast", do_cast, POSITION_SITTING, 0, 9 }, */ { "consider", do_consider, POSITION_RESTING, 0, 9 }, { "enter", do_enter, POSITION_STANDING, 0, 9 }, { "examine", do_examine, POSITION_RESTING, 0, 9 }, /* { "exits", do_exits, POSITION_RESTING, 0, 9 }, */ { "follow", do_follow, POSITION_RESTING, 0, 9 }, { "group", do_group, POSITION_RESTING, 0, 9 }, { "hide", do_hide, POSITION_RESTING, 0, 9 }, { "leave", do_leave, POSITION_STANDING, 0, 9 }, /* { "look", do_look, POSITION_RESTING, 0, 9 }, */ { "pick", do_pick, POSITION_STANDING, 0, 9 }, { "qui", do_qui, POSITION_DEAD, 0, 9 }, { "quit", do_quit, POSITION_DEAD, 0, 9 }, { "recall", do_recall, POSITION_FIGHTING, 0, 9 }, { "/", do_recall, POSITION_FIGHTING, 0, 9 }, { "return", do_return, POSITION_DEAD, 0, 9 }, { "save", do_save, POSITION_DEAD, 0, 9 }, { "sneak", do_sneak, POSITION_STANDING, 1, 9 }, { "split", do_split, POSITION_RESTING, 0, 9 }, { "steal", do_steal, POSITION_STANDING, 1, 9 }, { "where", do_where, POSITION_RESTING, 0, 9 }, { "wimpy", do_wimpy, POSITION_DEAD, 0, 9 }, { "write", do_write, POSITION_STANDING, 0, 9 }, /* * Special procedure commands. */ { "buy", do_not_here, POSITION_STANDING, 0, 56 }, { "sell", do_not_here, POSITION_STANDING, 0, 57 }, { "value", do_not_here, POSITION_STANDING, 0, 58 }, { "list", do_not_here, POSITION_STANDING, 0, 59 }, { "practice", do_practice, POSITION_RESTING, 1, 164 }, { "practise", do_practice, POSITION_RESTING, 1, 164 }, { "train", do_not_here, POSITION_RESTING, 1, 165 }, /* * Immortal commands. */ { "advance", do_advance, POSITION_DEAD, 35, 9 }, { "allow", do_allow, POSITION_DEAD, 34, 9 }, { "ban", do_ban, POSITION_DEAD, 34, 9 }, { "disconnect", do_disconnect, POSITION_DEAD, 34, 9 }, { "freeze", do_freeze, POSITION_DEAD, 34, 9 }, { "log", do_log, POSITION_DEAD, 34, 9 }, { "purge", do_purge, POSITION_DEAD, 34, 9 }, { "reroll", do_reroll, POSITION_DEAD, 34, 9 }, { "reset", do_reroll, POSITION_DEAD, 34, 9 }, { "set", do_set, POSITION_DEAD, 34, 9 }, { "shutdow", do_shutdow, POSITION_DEAD, 34, 9 }, { "shutdown", do_shutdown, POSITION_DEAD, 34, 9 }, { "sockets", do_sockets, POSITION_DEAD, 34, 9 }, { "string", do_string, POSITION_DEAD, 34, 9 }, { "wizlock", do_wizlock, POSITION_DEAD, 34, 9 }, { "force", do_force, POSITION_DEAD, 33, 9 }, { "load", do_load, POSITION_DEAD, 33, 9 }, { "noemote", do_noemote, POSITION_DEAD, 33, 9 }, { "nosocial", do_noemote, POSITION_DEAD, 33, 9 }, { "noshout", do_noshout, POSITION_DEAD, 33, 9 }, { "notell", do_notell, POSITION_DEAD, 33, 9 }, { "pardon", do_pardon, POSITION_DEAD, 33, 9 }, { "restore", do_restore, POSITION_DEAD, 33, 9 }, { "teleport", do_teleport, POSITION_DEAD, 33, 9 }, { "trans", do_trans, POSITION_DEAD, 33, 9 }, { "at", do_at, POSITION_DEAD, 32, 9 }, { "echo", do_echo, POSITION_DEAD, 32, 9 }, { "goto", do_goto, POSITION_DEAD, 32, 9 }, { "snoop", do_snoop, POSITION_DEAD, 32, 9 }, { "stat", do_stat, POSITION_DEAD, 32, 9 }, { "switch", do_switch, POSITION_DEAD, 32, 9 }, { "invis", do_wizinvis, POSITION_DEAD, 32, 9 }, { "wizinvis", do_wizinvis, POSITION_DEAD, 32, 9 }, { "holylite", do_holylite, POSITION_DEAD, 31, 9 }, { "immortal", do_wiz, POSITION_DEAD, 31, 9 }, { ":", do_wiz, POSITION_DEAD, 31, 9 }, /* { "wizhelp", do_wizhelp, POSITION_DEAD, 31, 9 }, */ /* * End of list. */ { "", do_not_here, POSITION_DEAD, 0, 9 } }; char *fill[]= { "in", "from", "with", "the", "on", "at", "to", "\n" }; void command_interpreter( struct char_data *ch, char *pcomm ) { int look_at; int cmd; /* * No hiding. */ REMOVE_BIT( ch->specials.affected_by, AFF_HIDE ); /* * Log players. */ if ( !IS_NPC(ch) && IS_SET(ch->specials.act, PLR_LOG) ) { sprintf( log_buf, "Log %s: %s", GET_NAME(ch), pcomm ); log( log_buf ); } /* * Implement freeze command. */ if ( !IS_NPC(ch) && IS_SET(ch->specials.act, PLR_FREEZE) ) { send_to_char( "You're totally frozen!\n\r", ch ); return; } /* * Strip initial spaces and parse command word. * Translate to lower case. */ while ( *pcomm == ' ' ) pcomm++; for ( look_at = 0; pcomm[look_at] > ' '; look_at++ ) pcomm[look_at] = LOWER(pcomm[look_at]); if ( look_at == 0 ) return; /* * Look for command in command table. */ for ( cmd = 0; cmd < sizeof(cmd_info)/sizeof(cmd_info[0]); cmd++ ) { if ( GET_LEVEL(ch) < cmd_info[cmd].minimum_level ) continue; if ( cmd_info[cmd].command_pointer == NULL ) continue; if ( memcmp( pcomm, cmd_info[cmd].command_name, look_at ) == 0 ) goto LCmdFound; } /* * Look for command in socials table. */ if ( check_social( ch, pcomm, look_at, &pcomm[look_at] ) ) return; /* * Unknown command (or char too low level). */ send_to_char( "Huh?\n\r", ch ); return; LCmdFound: /* * Character not in position for command? */ 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 hurt far too bad for that.\n\r", ch ); break; case POSITION_STUNNED: send_to_char( "You are too stunned to do that.\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...\n\r", ch); break; case POSITION_SITTING: send_to_char( "Maybe you should stand up first?\n\r", ch); break; case POSITION_FIGHTING: send_to_char( "No way! You are still fighting!\n\r", ch); break; } return; } /* * We're gonna execute it. * First look for usable special procedure. */ if ( special( ch, cmd_info[cmd].command_number, &pcomm[look_at] ) ) return; /* * Normal dispatch. */ (*cmd_info[cmd].command_pointer) (ch, &pcomm[look_at], cmd_info[cmd].command_number); /* * This call is here to prevent gcc from tail-chaining the * previous call, which screws up the debugger call stack. * -- Furey */ number( 0, 0 ); return; } 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 ( !found && *(list[guess]) != '\n' ) { found = (length==strlen(list[guess])); for ( search = 0; search < length && found; search++ ) found=(*(argument+begin+search)== *(list[guess]+search)); guess++; } else { while ( !found && *(list[guess]) != '\n' ) { found=1; for(search=0;( search < length && found );search++) found=(*(argument+begin+search)== *(list[guess]+search)); guess++; } } return ( found ? guess : -1 ); } 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); } /* 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(*(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(*string); string++); for (; !isspace(*arg1 = *string) && *string; string++, arg1++); *arg1 = '\0'; for (; isspace(*string); string++); for (; ( *arg2 = *string ) != '\0'; 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 do_wizhelp(struct char_data *ch, char *argument, int cmd_arg) { char buf[MAX_STRING_LENGTH]; int cmd; int no; if (IS_NPC(ch)) return; send_to_char( "The following privileged comands are available:\n\r\n\r", ch); buf[0] = '\0'; for ( cmd = 0, no = 0; cmd_info[cmd].command_name[0] != '\0'; cmd++ ) { if ( cmd_info[cmd].minimum_level <= 30 ) continue; if ( cmd_info[cmd].minimum_level > GET_LEVEL(ch) ) continue; sprintf( buf + strlen(buf), "%-10s", cmd_info[cmd].command_name ); if ( no % 7 == 0 ) strcat(buf, "\n\r"); no++; } strcat(buf, "\n\r"); page_string(ch->desc, buf, 1); }