/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include "merc.h" #include "interp.h" #include "olc.h" #include "recycle.h" #include "const.h" bool check_social args( ( CHAR_DATA *ch, char *command, char *argument ) ); bool check_disabled (CMD_DATA *command); struct wizcommand_type *wizcommand_table[9]; #define END_MARKER "END" /* for load_disabled() and save_disabled() */ void gen_wiz_table (void); /* * Command logging types. */ #define LOG_NORMAL 0 #define LOG_ALWAYS 1 #define LOG_NEVER 2 /* * Log-all switch. */ bool fLogAll = FALSE; /* * The main entry point for executing commands. * Can be recursively called from 'at', 'order', 'force'. */ void interpret( CHAR_DATA *ch, char *argument ) { char command[MAX_INPUT_LENGTH]; char logline[MAX_INPUT_LENGTH]; char *allowed_commands = "say inv who score quit"; int trust; bool found; CMD_DATA *pCmd; OBJ_DATA *pObj; /* * Strip leading spaces. */ while ( isspace(*argument) ) argument++; if ( argument[0] == '\0' ) return; /* * No hiding. */ REMOVE_BIT( ch->affected_by, AFF_HIDE ); if (IS_SET( ch->comm2, COMM_AUTO_AFK ) ) set_auto_afk( ch ); /* * Implement freeze command. */ if ( !IS_NPC(ch) && IS_SET(ch->act, PLR_FREEZE) ) { send_to_char( "You're totally frozen!\n\r", ch ); return; } /* * Grab the command word. * Special parsing so ' can be a command, * also no spaces needed after punctuation. */ if(!IS_NPC(ch) ) ch->pcdata->last_typed = current_time; strcpy( logline, argument ); if ( !isalpha(argument[0]) && !isdigit(argument[0]) ) { command[0] = argument[0]; command[1] = '\0'; argument++; while ( isspace(*argument) ) argument++; } else { argument = one_argument( argument, command ); } if (!is_full_name(command, allowed_commands) && IS_SET( ch->act, PLR_TIMEOUT ) ) { printf_to_char(ch, "You can only execute following commands: %s.\n", allowed_commands); return; } /* * Look for command in command table. */ if(HAS_TRIGGER_ROOM(ch->in_room,TRIG_ALIAS ) ) { if( p_alias_trigger(ch, command, NULL, PRG_RPROG, argument) ) return; } for( pObj = ch->in_room->contents ; pObj ; pObj = pObj->next_content ) { if(HAS_TRIGGER_OBJ(pObj, TRIG_ALIAS ) ) if( p_alias_trigger(ch, command, pObj, PRG_OPROG, argument ) ) return; } for ( pObj = ch->carrying; pObj; pObj = pObj->next_content ) { if(HAS_TRIGGER_OBJ(pObj, TRIG_ALIAS ) ) if( p_alias_trigger(ch, command, pObj, PRG_OPROG, argument ) ) return; } found = FALSE; trust = get_trust( ch ); for ( pCmd = cmd_first; pCmd ; pCmd = pCmd->next ) { if ( command[0] == pCmd->name[0] && !str_prefix( command, pCmd->name ) && pCmd->level <= trust ) { found = TRUE; break; } } if ( !found ) { /* * Look for command in socials table. */ if ( !check_social( ch, command, argument ) ) send_to_char( "That command doesn't exist type help for a list of valid commands.\n\r", ch ); return; } /* * Log and snoop. */ if ( pCmd->log == LOG_NEVER ) strcpy( logline, "" ); if ( ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG) ) || fLogAll || pCmd->log == LOG_ALWAYS ) { sprintf( log_buf, "Log %s: %s", ch->name, logline ); wiznet(log_buf,ch,NULL,WIZ_SECURE,0,get_trust(ch)); log_string( log_buf ); } if ( ch->desc != NULL && ch->desc->snoop_by != NULL ) { write_to_buffer( ch->desc->snoop_by, "% ", 2 ); write_to_buffer( ch->desc->snoop_by, logline, 0 ); write_to_buffer( ch->desc->snoop_by, "\n\r", 2 ); } if ( IS_SET(ch->act, PLR_IMPLAG ) ) { WAIT_STATE(ch,2*PULSE_VIOLENCE); } else /* a normal valid command.. check if it is disabled */ if (check_disabled (pCmd)) { send_to_char ("This command has been temporarily disabled.\n\r",ch); return; } /* * Character not in position for command? */ if ( ch->position < pCmd->position ) { switch( ch->position ) { case POS_DEAD: send_to_char( "Lie still; you are DEAD.\n\r", ch ); break; case POS_MORTAL: case POS_INCAP: send_to_char( "You are hurt far too bad for that.\n\r", ch ); break; case POS_STUNNED: send_to_char( "You are too stunned to do that.\n\r", ch ); break; case POS_SLEEPING: send_to_char( "In your dreams, or what?\n\r", ch ); break; case POS_RESTING: send_to_char( "Nah... You feel too relaxed...\n\r", ch); break; case POS_SITTING: send_to_char( "Better stand up first.\n\r",ch); break; case POS_FIGHTING: send_to_char( "No way! You are still fighting!\n\r", ch); break; } return; } /* * Dispatch the command. */ (*pCmd->do_fun) ( ch, argument ); tail_chain( ); return; } /* function to keep argument safe in all commands -- no static strings */ void do_function (CHAR_DATA *ch, DO_FUN *do_fun, char *argument) { char *command_string; /* copy the string */ command_string = str_dup(argument); /* dispatch the command */ (*do_fun) (ch, command_string); /* free the string */ free_string(command_string); } bool check_social( CHAR_DATA *ch, char *command, char *argument ) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; int cmd; bool found; found = FALSE; for ( cmd = 0; social_table[cmd].name[0] != '\0'; cmd++ ) { if ( command[0] == social_table[cmd].name[0] && !str_prefix( command, social_table[cmd].name ) ) { found = TRUE; break; } } if ( !found ) return FALSE; if ( !IS_NPC(ch) && IS_SET(ch->comm, COMM_NOEMOTE) ) { send_to_char( "You are anti-social!\n\r", ch ); return TRUE; } switch ( ch->position ) { case POS_DEAD: send_to_char( "Lie still; you are DEAD.\n\r", ch ); return TRUE; case POS_INCAP: case POS_MORTAL: send_to_char( "You are hurt far too bad for that.\n\r", ch ); return TRUE; case POS_STUNNED: send_to_char( "You are too stunned to do that.\n\r", ch ); return TRUE; case POS_SLEEPING: /* * I just know this is the path to a 12" 'if' statement. :( * But two players asked for it already! -- Furey */ if ( !str_cmp( social_table[cmd].name, "snore" ) ) break; send_to_char( "In your dreams, or what?\n\r", ch ); return TRUE; } one_argument( argument, arg ); victim = NULL; if ( arg[0] == '\0' ) { act( social_table[cmd].others_no_arg, ch, NULL, victim, TO_ROOM ); act( social_table[cmd].char_no_arg, ch, NULL, victim, TO_CHAR ); } else if ( ( victim = get_char_room( ch, NULL, arg ) ) == NULL ) { send_to_char( "They aren't here.\n\r", ch ); } else if ( victim == ch ) { act( social_table[cmd].others_auto, ch, NULL, victim, TO_ROOM ); act( social_table[cmd].char_auto, ch, NULL, victim, TO_CHAR ); } else { act( social_table[cmd].others_found, ch, NULL, victim, TO_NOTVICT ); act( social_table[cmd].char_found, ch, NULL, victim, TO_CHAR ); act( social_table[cmd].vict_found, ch, NULL, victim, TO_VICT ); if ( !IS_NPC(ch) && IS_NPC(victim) && !IS_AFFECTED(victim, AFF_CHARM) && IS_AWAKE(victim) && victim->desc == NULL) { switch ( number_bits( 4 ) ) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: act( social_table[cmd].others_found, victim, NULL, ch, TO_NOTVICT ); act( social_table[cmd].char_found, victim, NULL, ch, TO_CHAR ); act( social_table[cmd].vict_found, victim, NULL, ch, TO_VICT ); break; case 9: case 10: case 11: case 12: act( "$n slaps $N.", victim, NULL, ch, TO_NOTVICT ); act( "You slap $N.", victim, NULL, ch, TO_CHAR ); act( "$n slaps you.", victim, NULL, ch, TO_VICT ); break; } } } return TRUE; } /* * Return true if an argument is completely numeric. */ bool is_number ( char *arg ) { if ( *arg == '\0' ) return FALSE; if ( *arg == '+' || *arg == '-' ) arg++; for ( ; *arg != '\0'; arg++ ) { if ( !isdigit( *arg ) ) return FALSE; } return TRUE; } /* * Given a string like 14.foo, return 14 and 'foo' */ int number_argument( char *argument, char *arg ) { char *pdot; int number; for ( pdot = argument; *pdot != '\0'; pdot++ ) { if ( *pdot == '.' ) { *pdot = '\0'; number = atoi( argument ); *pdot = '.'; strcpy( arg, pdot+1 ); return number; } } strcpy( arg, argument ); return 1; } /* * Given a string like 14*foo, return 14 and 'foo' */ int mult_argument(char *argument, char *arg) { char *pdot; int number; for ( pdot = argument; *pdot != '\0'; pdot++ ) { if ( *pdot == '*' ) { *pdot = '\0'; number = atoi( argument ); *pdot = '*'; strcpy( arg, pdot+1 ); return number; } } strcpy( arg, argument ); return 1; } /* * Pick off one argument from a string and return the rest. * Understands quotes. */ char *one_argument( char *argument, char *arg_first ) { char cEnd; while ( isspace(*argument) ) argument++; cEnd = ' '; if ( *argument == '\'' || *argument == '"' ) cEnd = *argument++; while ( *argument != '\0' ) { if ( *argument == cEnd ) { argument++; break; } *arg_first = LOWER(*argument); arg_first++; argument++; } *arg_first = '\0'; while ( isspace(*argument) ) argument++; return argument; } /* * Contributed by Alander. * Modified to sort by category by Atlas of One Percent MUD. 1mud.org port 9000 * Please read and follow the DIKU license, as this modification is a derivative work! */ void do_commands( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; BUFFER *output; CMD_DATA * cmd; int col; int category; col = 0; output = new_buf(); /* I had to categorize the immortal commands, but not print them to mortals, * so immortal commands are category 0, and I started the loop with category * 1 commands. There's probably a better way to do this, but hey, it works! * I also have the commands that I felt were most important in the higher * categories, which print out last. The more useless commands are in lower * categories so they might scroll off the screen. * Wondering who made it so that nothing will scroll off the screen? Why, it * was Laeseah! Sorry, but it was driving me nuts. ;) */ for( category = 1; category < 8; category++ ) { switch(category) { case 1: add_buf(output, "*** {CConfiguration Commands{x ***\n\r"); break; case 2: add_buf(output, "*** {BCommon Commands{x ***\n\r"); break; case 3: add_buf(output, "*** {WCommunication Commands{x ***\n\r"); break; case 4: add_buf(output, "*** {rInformational Commands{x ***\n\r"); break; case 5: add_buf(output, "*** {YObject Manipulation Commands{x ***\n\r"); break; case 6: add_buf(output, "*** {mMovement Commands{x ***\n\r"); break; case 7: add_buf(output, "*** {rCombat Commands{x ***\n\r"); break; } for ( cmd = cmd_first ; cmd ; cmd = cmd->next ) { if ( cmd->level < LEVEL_HERO && cmd->level <= get_trust( ch ) && cmd->show && cmd->cat == category) /* <--- this ensures the category equals the current category loop value */ { sprintf( buf, " [{c%-11s{x]", cmd->name ); add_buf(output, buf ); if ( ++col % 5 == 0 ) add_buf(output, "\n\r"); } } if (col % 5 != 0 ) { add_buf(output, "\n\r"); col = 0; } } if ( col % 5 != 0 ) add_buf(output, "\n\r"); page_to_char(buf_string(output), ch); free_buf(output); return; } void do_wizhelp( CHAR_DATA *ch, char *argument ) { char buf[MAX_STRING_LENGTH]; int col; int counter; int level; int v_level; struct wizcommand_type *tmp; v_level = UMAX (ch->level, get_trust(ch)); for (counter = MAX_LEVEL-v_level; counter < 9; counter++) { level = MAX_LEVEL-counter; col = 0; if (level % 2 == 0) sprintf (buf, "{BLevel %3d:{x ", level); if (col % 5) send_to_char("\n\r",ch); else sprintf (buf, "{CLevel %3d:{x ", level); send_to_char(buf, ch); if (col % 5) send_to_char("\n\r",ch); for (tmp = wizcommand_table[counter]; tmp != NULL ; tmp = tmp->next) { sprintf( buf, "%-13s", tmp->name ); send_to_char( buf, ch ); if ( ++col % 5 == 0 ) send_to_char( "\n\r ", ch ); } send_to_char ("\n\r",ch); } return; } void gen_wiz_table (void) { CMD_DATA * cmd; int level; struct wizcommand_type *tmp; bool show; for ( cmd = cmd_first; cmd; cmd = cmd->next) { level = cmd->level; show = cmd->show == 1 ? TRUE : FALSE; if (level >= HE && show) { if (wizcommand_table[MAX_LEVEL-level] == NULL) { tmp = (struct wizcommand_type *) malloc (sizeof (struct wizcommand_type)); tmp->name = strdup (cmd->name); tmp->next = NULL; wizcommand_table[MAX_LEVEL-level] = tmp; } else { for (tmp = wizcommand_table[MAX_LEVEL-level] ; tmp->next != NULL ; tmp = tmp->next); tmp->next = (struct wizcommand_type *) malloc (sizeof (struct wizcommand_type)); tmp->next->name = strdup(cmd->name); tmp->next->next = NULL; } } } } void do_disable (CHAR_DATA *ch, char *argument) { CMD_DATA *pCmd; if(argument[0] == '\0' ) { send_to_char("{DDisabled Commands{r:\n\r",ch); for(pCmd = cmd_first ; pCmd ; pCmd = pCmd->next ) if(pCmd->disabled) printf_to_char(ch, "\t{W%s{x\n\r", pCmd->name ); return; } if( ( pCmd = cmd_lookup(argument ) ) == NULL ) { send_to_char("You cannot disable a command that doesn't exist!\n\r",ch); return; } if(pCmd->disabled ) { send_to_char("Command enabled!\n\r",ch); pCmd->disabled = FALSE; return; } else { send_to_char("Command disabled!\n\r",ch); pCmd->disabled = TRUE; return; } return; } bool check_disabled (CMD_DATA *command) { return command->disabled; }