Пример #1
0
/*
 * 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 logname[MAX_INPUT_LENGTH];
   char log_buf[MAX_STRING_LENGTH];
   char *origarg = argument;
   char *buf;
   TIMER *timer = NULL;
   CMDTYPE *cmd = NULL;
   int trust;
   int loglvl;
   bool found;
   struct timeval time_used;
   long tmptime;

   if( !ch )
   {
      bug( "%s: null ch!", __FUNCTION__ );
      return;
   }

   if( !ch->in_room )
   {
      bug( "%s: null in_room!", __FUNCTION__ );
      return;
   }

   found = FALSE;
   if( ch->substate == SUB_REPEATCMD )
   {
      DO_FUN *fun;

      if( ( fun = ch->last_cmd ) == NULL )
      {
         ch->substate = SUB_NONE;
         bug( "%s: SUB_REPEATCMD with NULL last_cmd", __FUNCTION__ );
         return;
      }
      else
      {
         int x;

         /*
          * yes... we lose out on the hashing speediness here...
          * but the only REPEATCMDS are wizcommands (currently)
          */
         for( x = 0; x < 126; x++ )
         {
            for( cmd = command_hash[x]; cmd; cmd = cmd->next )
               if( cmd->do_fun == fun )
               {
                  found = TRUE;
                  break;
               }
            if( found )
               break;
         }
         if( !found )
         {
            cmd = NULL;
            bug( "%s: SUB_REPEATCMD: last_cmd invalid", __FUNCTION__ );
            return;
         }
         snprintf( logline, MAX_INPUT_LENGTH, "(%s) %s", cmd->name, argument );
      }
   }

   if( !cmd )
   {
      /*
       * Changed the order of these ifchecks to prevent crashing. 
       */
      if( !argument || !strcmp( argument, "" ) )
      {
         bug( "%s: null argument!", __FUNCTION__ );
         return;
      }

      /*
       * Strip leading spaces.
       */
      while( isspace( *argument ) )
         argument++;
      if( argument[0] == '\0' )
         return;

      /*
       * xREMOVE_BIT( ch->affected_by, AFF_HIDE ); 
       */

      /*
       * Implement freeze command.
       */
      if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_FREEZE ) )
      {
         send_to_char( "You're totally frozen!\r\n", ch );
         return;
      }

      /*
       * Grab the command word.
       * Special parsing so ' can be a command,
       *   also no spaces needed after punctuation.
       */
      mudstrlcpy( logline, argument, MAX_INPUT_LENGTH );
      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 );

      /*
       * Look for command in command table.
       * Check for council powers and/or bestowments
       */
      trust = get_trust( ch );
      for( cmd = command_hash[LOWER( command[0] ) % 126]; cmd; cmd = cmd->next )
         if( !str_prefix( command, cmd->name )
             && ( cmd->level <= trust
                  || ( !IS_NPC( ch ) && ch->pcdata->council
                       && is_name( cmd->name, ch->pcdata->council->powers )
                       && cmd->level <= ( trust + MAX_CPD ) )
                  || ( !IS_NPC( ch ) && ch->pcdata->bestowments && ch->pcdata->bestowments[0] != '\0'
                       && is_name( cmd->name, ch->pcdata->bestowments ) && cmd->level <= ( trust + sysdata.bestow_dif ) ) ) )
         {
            found = TRUE;
            break;
         }

      /*
       * Turn off afk bit when any command performed.
       */
      if( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_AFK ) && ( str_cmp( command, "AFK" ) ) )
      {
         xREMOVE_BIT( ch->act, PLR_AFK );
         act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_CANSEE );
      }
   }

   /*
    * Log and snoop.
    */
   snprintf( lastplayercmd, ( MAX_INPUT_LENGTH * 2 ), "%s used %s", ch->name, logline );

   if( found && cmd->log == LOG_NEVER )
      mudstrlcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX", MAX_INPUT_LENGTH );

   loglvl = found ? cmd->log : LOG_NORMAL;

   /*
    * Write input line to watch files if applicable
    */
   if( !IS_NPC( ch ) && ch->desc && valid_watch( logline ) )
   {
      if( found && IS_SET( cmd->flags, CMD_WATCH ) )
         write_watch_files( ch, cmd, logline );
      else if( IS_SET( ch->pcdata->flags, PCFLAG_WATCH ) )
         write_watch_files( ch, NULL, logline );
   }

   if( ( !IS_NPC( ch ) && xIS_SET( ch->act, PLR_LOG ) )
       || fLogAll || loglvl == LOG_BUILD || loglvl == LOG_HIGH || loglvl == LOG_ALWAYS )
   {
      /*
       * Added by Narn to show who is switched into a mob that executes
       * a logged command.  Check for descriptor in case force is used. 
       */
      if( ch->desc && ch->desc->original )
         snprintf( log_buf, MAX_STRING_LENGTH, "Log %s (%s): %s", ch->name, ch->desc->original->name, logline );
      else
         snprintf( log_buf, MAX_STRING_LENGTH, "Log %s: %s", ch->name, logline );

      /*
       * Make it so a 'log all' will send most output to the log
       * file only, and not spam the log channel to death   -Thoric
       */
      if( fLogAll && loglvl == LOG_NORMAL && ( IS_NPC( ch ) || !xIS_SET( ch->act, PLR_LOG ) ) )
         loglvl = LOG_ALL;

      log_string_plus( log_buf, loglvl, get_trust( ch ) );
   }

   if( ch->desc && ch->desc->snoop_by )
   {
      snprintf( logname, MAX_INPUT_LENGTH, "%s", ch->name );
      write_to_buffer( ch->desc->snoop_by, logname, 0 );
      write_to_buffer( ch->desc->snoop_by, "% ", 2 );
      write_to_buffer( ch->desc->snoop_by, logline, 0 );
      write_to_buffer( ch->desc->snoop_by, "\r\n", 2 );
   }

   /*
    * check for a timer delayed command (search, dig, detrap, etc) 
    */
   if( ( timer = get_timerptr( ch, TIMER_DO_FUN ) ) != NULL )
   {
      int tempsub;

      tempsub = ch->substate;
      ch->substate = SUB_TIMER_DO_ABORT;
      ( timer->do_fun ) ( ch, "" );
      if( char_died( ch ) )
         return;
      if( ch->substate != SUB_TIMER_CANT_ABORT )
      {
         ch->substate = tempsub;
         extract_timer( ch, timer );
      }
      else
      {
         ch->substate = tempsub;
         return;
      }
   }

   /*
    * Look for command in skill and socials table.
    */
   if( !found )
   {
      if( !check_skill( ch, command, argument ) && !check_ability( ch, command, argument )   // Racial Abilities Support - Kayle 7-8-07
          && !rprog_command_trigger( ch, origarg )
          && !mprog_command_trigger( ch, origarg )
          && !oprog_command_trigger( ch, origarg )
          && !check_social( ch, command, argument ) && !news_cmd_hook( ch, command, argument )
#ifdef IMC
          && !imc_command_hook( ch, command, argument )
#endif
          )
      {
         EXIT_DATA *pexit;

         /*
          * check for an auto-matic exit command 
          */
         if( ( pexit = find_door( ch, command, TRUE ) ) != NULL && IS_SET( pexit->exit_info, EX_xAUTO ) )
         {
            if( IS_SET( pexit->exit_info, EX_CLOSED )
                && ( !IS_AFFECTED( ch, AFF_PASS_DOOR ) || IS_SET( pexit->exit_info, EX_NOPASSDOOR ) ) )
            {
               if( !IS_SET( pexit->exit_info, EX_SECRET ) )
                  act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
               else
                  send_to_char( "You cannot do that here.\r\n", ch );
               return;
            }
            if( check_pos( ch, POS_STANDING ) )
               move_char( ch, pexit, 0 );
            return;
         }
         send_to_char( "Huh?\r\n", ch );
      }
      return;
   }

   /*
    * Character not in position for command?
    */
   if( !check_pos( ch, cmd->position ) )
      return;

   /*
    * Berserk check for flee.. maybe add drunk to this?.. but too much
    * hardcoding is annoying.. -- Altrag
    * This wasn't catching wimpy --- Blod
    * if ( !str_cmp(cmd->name, "flee") &&
    * IS_AFFECTED(ch, AFF_BERSERK) )
    * {
    * send_to_char( "You aren't thinking very clearly..\r\n", ch);
    * return;
    * } 
    */

   /*
    * So we can check commands for things like Posses and Polymorph
    * *  But still keep the online editing ability.  -- Shaddai
    * *  Send back the message to print out, so we have the option
    * *  this function might be usefull elsewhere.  Also using the
    * *  send_to_char_color so we can colorize the strings if need be. --Shaddai
    */

   buf = check_cmd_flags( ch, cmd );

   if( buf[0] != '\0' )
   {
      send_to_char_color( buf, ch );
      return;
   }

   /*
    * Nuisance stuff -- Shaddai
    */

   if( !IS_NPC( ch ) && ch->pcdata->nuisance && ch->pcdata->nuisance->flags > 9
       && number_percent(  ) < ( ( ch->pcdata->nuisance->flags - 9 ) * 10 * ch->pcdata->nuisance->power ) )
   {
      send_to_char( "You can't seem to do that just now.\r\n", ch );
      return;
   }

   /*
    * Dispatch the command.
    */
   ch->prev_cmd = ch->last_cmd;  /* haus, for automapping */
   ch->last_cmd = cmd->do_fun;
   start_timer( &time_used );
   ( *cmd->do_fun ) ( ch, argument );
   end_timer( &time_used );
   /*
    * Update the record of how many times this command has been used (haus)
    */
   update_userec( &time_used, &cmd->userec );
   tmptime = UMIN( time_used.tv_sec, 19 ) * 1000000 + time_used.tv_usec;

   /*
    * laggy command notice: command took longer than 1.5 seconds 
    */
   if( tmptime > 1500000 )
   {
      log_printf_plus( LOG_NORMAL, get_trust( ch ), "[*****] LAG: %s: %s %s (R:%d S:%ld.%06ld)", ch->name,
                       cmd->name, ( cmd->log == LOG_NEVER ? "XXX" : argument ),
                       ch->in_room ? ch->in_room->vnum : 0, time_used.tv_sec, time_used.tv_usec );
      cmd->lag_count++; /* count the lag flags */
   }

   tail_chain(  );
}
Пример #2
0
void do_pick (CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *gch;
    OBJ_DATA *obj;
    int door;

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
        send_to_char ("Pick what?\n\r", ch);
        return;
    }

    WAIT_STATE (ch, skill_table[gsn_pick_lock].beats);

    /* look for guards */
    for (gch = ch->in_room->people; gch; gch = gch->next_in_room)
    {
        if (IS_NPC (gch) && IS_AWAKE (gch) && ch->level + 5 < gch->level)
        {
            act ("$N is standing too close to the lock.",
                 ch, NULL, gch, TO_CHAR);
            return;
        }
    }

    if (!IS_NPC (ch) && number_percent () > get_skill (ch, gsn_pick_lock))
    {
        send_to_char ("You failed.\n\r", ch);
        return;
    }

    if ((obj = get_obj_here (ch, arg)) != NULL)
    {
        /* portal stuff */
        if (obj->item_type == ITEM_PORTAL)
        {
            if (!IS_SET (obj->value[1], EX_ISDOOR))
            {
                send_to_char ("You can't do that.\n\r", ch);
                return;
            }

            if (!IS_SET (obj->value[1], EX_CLOSED))
            {
                send_to_char ("It's not closed.\n\r", ch);
                return;
            }

            if (obj->value[4] < 0)
            {
                send_to_char ("It can't be unlocked.\n\r", ch);
                return;
            }

            if (IS_SET (obj->value[1], EX_PICKPROOF))
            {
                send_to_char ("You failed.\n\r", ch);
                return;
            }

            REMOVE_BIT (obj->value[1], EX_LOCKED);
            act ("You pick the lock on $p.", ch, obj, NULL, TO_CHAR);
            act ("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM);
            return;
        }





        /* 'pick object' */
        if (obj->item_type != ITEM_CONTAINER)
        {
            send_to_char ("That's not a container.\n\r", ch);
            return;
        }
        if (!IS_SET (obj->value[1], CONT_CLOSED))
        {
            send_to_char ("It's not closed.\n\r", ch);
            return;
        }
        if (obj->value[2] < 0)
        {
            send_to_char ("It can't be unlocked.\n\r", ch);
            return;
        }
        if (!IS_SET (obj->value[1], CONT_LOCKED))
        {
            send_to_char ("It's already unlocked.\n\r", ch);
            return;
        }
        if (IS_SET (obj->value[1], CONT_PICKPROOF))
        {
            send_to_char ("You failed.\n\r", ch);
            return;
        }

        REMOVE_BIT (obj->value[1], CONT_LOCKED);
        act ("You pick the lock on $p.", ch, obj, NULL, TO_CHAR);
        act ("$n picks the lock on $p.", ch, obj, NULL, TO_ROOM);
        return;
    }

    if ((door = find_door (ch, arg)) >= 0)
    {
        /* 'pick door' */
        ROOM_INDEX_DATA *to_room;
        EXIT_DATA *pexit;
        EXIT_DATA *pexit_rev;

        pexit = ch->in_room->exit[door];
        if (!IS_SET (pexit->exit_info, EX_CLOSED) && !IS_IMMORTAL (ch))
        {
            send_to_char ("It's not closed.\n\r", ch);
            return;
        }
        if (pexit->key < 0 && !IS_IMMORTAL (ch))
        {
            send_to_char ("It can't be picked.\n\r", ch);
            return;
        }
        if (!IS_SET (pexit->exit_info, EX_LOCKED))
        {
            send_to_char ("It's already unlocked.\n\r", ch);
            return;
        }
        if (IS_SET (pexit->exit_info, EX_PICKPROOF) && !IS_IMMORTAL (ch))
        {
            send_to_char ("You failed.\n\r", ch);
            return;
        }

        REMOVE_BIT (pexit->exit_info, EX_LOCKED);
        send_to_char ("*Click*\n\r", ch);
        act ("$n picks the $d.", ch, NULL, pexit->keyword, TO_ROOM);

        /* pick the other side */
        if ((to_room = pexit->u1.to_room) != NULL
            && (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
            && pexit_rev->u1.to_room == ch->in_room)
        {
            REMOVE_BIT (pexit_rev->exit_info, EX_LOCKED);
        }
    }

    return;
}
Пример #3
0
void do_unlock (CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int door;

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
        send_to_char ("Unlock what?\n\r", ch);
        return;
    }

    if ((obj = get_obj_here (ch, arg)) != NULL)
    {
        /* portal stuff */
        if (obj->item_type == ITEM_PORTAL)
        {
            if (!IS_SET (obj->value[1], EX_ISDOOR))
            {
                send_to_char ("You can't do that.\n\r", ch);
                return;
            }

            if (!IS_SET (obj->value[1], EX_CLOSED))
            {
                send_to_char ("It's not closed.\n\r", ch);
                return;
            }

            if (obj->value[4] < 0)
            {
                send_to_char ("It can't be unlocked.\n\r", ch);
                return;
            }

            if (!has_key (ch, obj->value[4]))
            {
                send_to_char ("You lack the key.\n\r", ch);
                return;
            }

            if (!IS_SET (obj->value[1], EX_LOCKED))
            {
                send_to_char ("It's already unlocked.\n\r", ch);
                return;
            }

            REMOVE_BIT (obj->value[1], EX_LOCKED);
            act ("You unlock $p.", ch, obj, NULL, TO_CHAR);
            act ("$n unlocks $p.", ch, obj, NULL, TO_ROOM);
            return;
        }

        /* 'unlock object' */
        if (obj->item_type != ITEM_CONTAINER)
        {
            send_to_char ("That's not a container.\n\r", ch);
            return;
        }
        if (!IS_SET (obj->value[1], CONT_CLOSED))
        {
            send_to_char ("It's not closed.\n\r", ch);
            return;
        }
        if (obj->value[2] < 0)
        {
            send_to_char ("It can't be unlocked.\n\r", ch);
            return;
        }
        if (!has_key (ch, obj->value[2]))
        {
            send_to_char ("You lack the key.\n\r", ch);
            return;
        }
        if (!IS_SET (obj->value[1], CONT_LOCKED))
        {
            send_to_char ("It's already unlocked.\n\r", ch);
            return;
        }

        REMOVE_BIT (obj->value[1], CONT_LOCKED);
        act ("You unlock $p.", ch, obj, NULL, TO_CHAR);
        act ("$n unlocks $p.", ch, obj, NULL, TO_ROOM);
        return;
    }

    if ((door = find_door (ch, arg)) >= 0)
    {
        /* 'unlock door' */
        ROOM_INDEX_DATA *to_room;
        EXIT_DATA *pexit;
        EXIT_DATA *pexit_rev;

        pexit = ch->in_room->exit[door];
        if (!IS_SET (pexit->exit_info, EX_CLOSED))
        {
            send_to_char ("It's not closed.\n\r", ch);
            return;
        }
        if (pexit->key < 0)
        {
            send_to_char ("It can't be unlocked.\n\r", ch);
            return;
        }
        if (!has_key (ch, pexit->key))
        {
            send_to_char ("You lack the key.\n\r", ch);
            return;
        }
        if (!IS_SET (pexit->exit_info, EX_LOCKED))
        {
            send_to_char ("It's already unlocked.\n\r", ch);
            return;
        }

        REMOVE_BIT (pexit->exit_info, EX_LOCKED);
        send_to_char ("*Click*\n\r", ch);
        act ("$n unlocks the $d.", ch, NULL, pexit->keyword, TO_ROOM);

        /* unlock the other side */
        if ((to_room = pexit->u1.to_room) != NULL
            && (pexit_rev = to_room->exit[rev_dir[door]]) != NULL
            && pexit_rev->u1.to_room == ch->in_room)
        {
            REMOVE_BIT (pexit_rev->exit_info, EX_LOCKED);
        }
    }

    return;
}
Пример #4
0
void do_close (CHAR_DATA * ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    int door;

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
        send_to_char ("Close what?\n\r", ch);
        return;
    }

    if ((obj = get_obj_here (ch, arg)) != NULL)
    {
        /* portal stuff */
        if (obj->item_type == ITEM_PORTAL)
        {

            if (!IS_SET (obj->value[1], EX_ISDOOR)
                || IS_SET (obj->value[1], EX_NOCLOSE))
            {
                send_to_char ("You can't do that.\n\r", ch);
                return;
            }

            if (IS_SET (obj->value[1], EX_CLOSED))
            {
                send_to_char ("It's already closed.\n\r", ch);
                return;
            }

            SET_BIT (obj->value[1], EX_CLOSED);
            act ("You close $p.", ch, obj, NULL, TO_CHAR);
            act ("$n closes $p.", ch, obj, NULL, TO_ROOM);
            return;
        }

        /* 'close object' */
        if (obj->item_type != ITEM_CONTAINER)
        {
            send_to_char ("That's not a container.\n\r", ch);
            return;
        }
        if (IS_SET (obj->value[1], CONT_CLOSED))
        {
            send_to_char ("It's already closed.\n\r", ch);
            return;
        }
        if (!IS_SET (obj->value[1], CONT_CLOSEABLE))
        {
            send_to_char ("You can't do that.\n\r", ch);
            return;
        }

        SET_BIT (obj->value[1], CONT_CLOSED);
        act ("You close $p.", ch, obj, NULL, TO_CHAR);
        act ("$n closes $p.", ch, obj, NULL, TO_ROOM);
        return;
    }

    if ((door = find_door (ch, arg)) >= 0)
    {
        /* 'close door' */
        ROOM_INDEX_DATA *to_room;
        EXIT_DATA *pexit;
        EXIT_DATA *pexit_rev;

        pexit = ch->in_room->exit[door];
        if (IS_SET (pexit->exit_info, EX_CLOSED))
        {
            send_to_char ("It's already closed.\n\r", ch);
            return;
        }

        SET_BIT (pexit->exit_info, EX_CLOSED);
        act ("$n closes the $d.", ch, NULL, pexit->keyword, TO_ROOM);
        send_to_char ("Ok.\n\r", ch);

        /* close the other side */
        if ((to_room = pexit->u1.to_room) != NULL
            && (pexit_rev = to_room->exit[rev_dir[door]]) != 0
            && pexit_rev->u1.to_room == ch->in_room)
        {
            CHAR_DATA *rch;

            SET_BIT (pexit_rev->exit_info, EX_CLOSED);
            for (rch = to_room->people; rch != NULL; rch = rch->next_in_room)
                act ("The $d closes.", rch, NULL, pexit_rev->keyword,
                     TO_CHAR);
        }
    }

    return;
}
Пример #5
0
/*
 * Generic use ranged attack function			-Thoric & Tricops
 */
ch_ret ranged_attack( char_data * ch, string argument, obj_data * weapon, obj_data * projectile, short dt, short range )
{
   string arg, arg1, temp;

   if( !argument.empty(  ) && argument[0] == '\'' )
   {
      one_argument( argument, temp );
      argument = temp;
   }

   argument = one_argument( argument, arg );
   argument = one_argument( argument, arg1 );

   if( arg.empty(  ) )
   {
      ch->print( "Where?  At who?\r\n" );
      return rNONE;
   }

   /*
    * get an exit or a victim 
    */
   short dir = -1;
   exit_data *pexit;
   char_data *victim = nullptr;
   if( !( pexit = find_door( ch, arg, true ) ) )
   {
      if( !( victim = ch->get_char_room( arg ) ) )
      {
         ch->print( "Aim in what direction?\r\n" );
         return rNONE;
      }
      else
      {
         if( ch->who_fighting(  ) == victim )
         {
            ch->print( "They are too close to release that type of attack!\r\n" );
            return rNONE;
         }
      }
   }
   else
      dir = pexit->vdir;

   /*
    * check for ranged attacks from private rooms, etc 
    */
   if( !victim )
   {
      if( ch->in_room->flags.test( ROOM_PRIVATE ) || ch->in_room->flags.test( ROOM_SOLITARY ) )
      {
         ch->print( "You cannot perform a ranged attack from a private room.\r\n" );
         return rNONE;
      }
      if( ch->in_room->tunnel > 0 )
      {
         if( ( int )ch->in_room->people.size(  ) >= ch->in_room->tunnel )
         {
            ch->print( "This room is too cramped to perform such an attack.\r\n" );
            return rNONE;
         }
      }
   }

   skill_type *skill = nullptr;
   if( IS_VALID_SN( dt ) )
      skill = skill_table[dt];

   if( pexit && !pexit->to_room )
   {
      ch->print( "Are you expecting to fire through a wall!?\r\n" );
      return rNONE;
   }

   /*
    * Check for obstruction 
    */
   if( pexit && IS_EXIT_FLAG( pexit, EX_CLOSED ) )
   {
      if( IS_EXIT_FLAG( pexit, EX_SECRET ) || IS_EXIT_FLAG( pexit, EX_DIG ) )
         ch->print( "Are you expecting to fire through a wall!?\r\n" );
      else
         ch->print( "Are you expecting to fire through a door!?\r\n" );
      return rNONE;
   }

   /*
    * Keeps em from firing through a wall but can still fire through an arrow slit or window, Marcus 
    */
   if( pexit )
   {
      if( ( IS_EXIT_FLAG( pexit, EX_FORTIFIED ) || IS_EXIT_FLAG( pexit, EX_HEAVY )
            || IS_EXIT_FLAG( pexit, EX_MEDIUM ) || IS_EXIT_FLAG( pexit, EX_LIGHT ) || IS_EXIT_FLAG( pexit, EX_CRUMBLING ) )
          && !IS_EXIT_FLAG( pexit, EX_WINDOW ) && !IS_EXIT_FLAG( pexit, EX_ASLIT ) )
      {
         ch->print( "Are you expecting to fire through a wall!?\r\n" );
         return rNONE;
      }
   }

   char_data *vch = nullptr;
   if( pexit && !arg1.empty(  ) )
   {
      if( !( vch = scan_for_vic( ch, pexit, arg1 ) ) )
      {
         ch->print( "You cannot see your target.\r\n" );
         return rNONE;
      }

      /*
       * don't allow attacks on mobs that are in a no-missile room --Shaddai 
       */
      if( vch->in_room->flags.test( ROOM_NOMISSILE ) )
      {
         ch->print( "You can't get a clean shot off.\r\n" );
         return rNONE;
      }

      /*
       * can't properly target someone heavily in battle 
       */
      if( vch->num_fighting > MAX_FIGHT )
      {
         ch->print( "There is too much activity there for you to get a clear shot.\r\n" );
         return rNONE;
      }
   }

   if( vch )
   {
      if( !vch->CAN_PKILL(  ) || !ch->CAN_PKILL(  ) )
      {
         ch->print( "You can't do that!\r\n" );
         return rNONE;
      }
      if( vch && is_safe( ch, vch ) )
         return rNONE;
   }

   room_index *was_in_room = ch->in_room;
   const char *stxt = "burst of energy";
   if( projectile )
   {
      projectile->separate(  );
      if( pexit )
      {
         if( weapon )
         {
            act( AT_GREY, "You fire $p $T.", ch, projectile, dir_name[dir], TO_CHAR );
            act( AT_GREY, "$n fires $p $T.", ch, projectile, dir_name[dir], TO_ROOM );
         }
         else
         {
            act( AT_GREY, "You throw $p $T.", ch, projectile, dir_name[dir], TO_CHAR );
            act( AT_GREY, "$n throw $p $T.", ch, projectile, dir_name[dir], TO_ROOM );
         }
      }
      else
      {
         if( weapon )
         {
            act( AT_GREY, "You fire $p at $N.", ch, projectile, victim, TO_CHAR );
            act( AT_GREY, "$n fires $p at $N.", ch, projectile, victim, TO_NOTVICT );
            act( AT_GREY, "$n fires $p at you!", ch, projectile, victim, TO_VICT );
         }
         else
         {
            act( AT_GREY, "You throw $p at $N.", ch, projectile, victim, TO_CHAR );
            act( AT_GREY, "$n throws $p at $N.", ch, projectile, victim, TO_NOTVICT );
            act( AT_GREY, "$n throws $p at you!", ch, projectile, victim, TO_VICT );
         }
      }
   }
   else if( skill )
   {
      if( skill->noun_damage && skill->noun_damage[0] != '\0' )
         stxt = skill->noun_damage;
      else
         stxt = skill->name;
      /*
       * a plain "spell" flying around seems boring 
       */
      if( !str_cmp( stxt, "spell" ) )
         stxt = "magical burst of energy";
      if( skill->type == SKILL_SPELL )
      {
         if( pexit )
         {
            act( AT_MAGIC, "You release $t $T.", ch, aoran( stxt ), dir_name[dir], TO_CHAR );
            act( AT_MAGIC, "$n releases $s $t $T.", ch, stxt, dir_name[dir], TO_ROOM );
         }
         else
         {
            act( AT_MAGIC, "You release $t at $N.", ch, aoran( stxt ), victim, TO_CHAR );
            act( AT_MAGIC, "$n releases $s $t at $N.", ch, stxt, victim, TO_NOTVICT );
            act( AT_MAGIC, "$n releases $s $t at you!", ch, stxt, victim, TO_VICT );
         }
      }
   }
   else
   {
      bug( "%s: no projectile, no skill dt %d", __func__, dt );
      return rNONE;
   }

   /*
    * victim in same room 
    */
   if( victim )
   {
      check_illegal_pk( ch, victim );
      check_attacker( ch, victim );
      return ranged_got_target( ch, victim, weapon, projectile, 0, dt, stxt, AT_MAGIC );
   }

   /*
    * assign scanned victim 
    */
   victim = vch;

   /*
    * reverse direction text from move_char 
    */
   const char *dtxt = rev_exit( pexit->vdir );
   int dist = 0;

   while( dist <= range )
   {
      ch->from_room(  );
      if( !ch->to_room( pexit->to_room ) )
         log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ );

      if( IS_EXIT_FLAG( pexit, EX_CLOSED ) )
      {
         /*
          * whadoyahknow, the door's closed 
          */
         if( projectile )
            ch->printf( "&wYou see your %s pierce a door in the distance to the %s.", projectile->myobj(  ).c_str(  ), dir_name[dir] );
         else
            ch->printf( "&wYou see your %s hit a door in the distance to the %s.", stxt, dir_name[dir] );
         if( projectile )
            act_printf( AT_GREY, ch, projectile, nullptr, TO_ROOM, "$p flies in from %s and implants itself solidly in the %sern door.", dtxt, dir_name[dir] );
         else
            act_printf( AT_GREY, ch, nullptr, nullptr, TO_ROOM, "%s flies in from %s and implants itself solidly in the %sern door.", aoran( stxt ), dtxt, dir_name[dir] );
         break;
      }

      /*
       * no victim? pick a random one 
       */
      if( !victim )
      {
         list < char_data * >::iterator ich;
         for( ich = ch->in_room->people.begin(  ); ich != ch->in_room->people.end(  ); ++ich )
         {
            vch = *ich;

            if( ( ( ch->isnpc(  ) && !vch->isnpc(  ) ) || ( !ch->isnpc(  ) && vch->isnpc(  ) ) ) && number_bits( 1 ) == 0 )
            {
               victim = vch;
               break;
            }
         }
         if( victim && is_safe( ch, victim ) )
         {
            ch->from_room(  );
            if( !ch->to_room( was_in_room ) )
               log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ );
            return rNONE;
         }
      }

      /*
       * In the same room as our victim? 
       */
      if( victim && ch->in_room == victim->in_room )
      {
         if( projectile )
            act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM );
         else
            act( AT_GREY, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM );

         /*
          * get back before the action starts 
          */
         ch->from_room(  );
         if( !ch->to_room( was_in_room ) )
            log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ );

         check_illegal_pk( ch, victim );
         check_attacker( ch, victim );
         return ranged_got_target( ch, victim, weapon, projectile, dist, dt, stxt, AT_GREY );
      }

      if( dist == range )
      {
         if( projectile )
         {
            act( AT_GREY, "Your $t falls harmlessly to the ground to the $T.", ch, projectile->myobj(  ).c_str(  ), dir_name[dir], TO_CHAR );
            act( AT_GREY, "$p flies in from $T and falls harmlessly to the ground here.", ch, projectile, dtxt, TO_ROOM );
            if( projectile->in_obj )
               projectile->from_obj(  );
            if( projectile->carried_by )
               projectile->from_char(  );
            projectile->to_room( ch->in_room, ch );
         }
         else
         {
            act( AT_MAGIC, "Your $t fizzles out harmlessly to the $T.", ch, stxt, dir_name[dir], TO_CHAR );
            act( AT_MAGIC, "$t flies in from $T and fizzles out harmlessly.", ch, aoran( stxt ), dtxt, TO_ROOM );
         }
         break;
      }

      if( !( pexit = ch->in_room->get_exit( dir ) ) )
      {
         if( projectile )
         {
            act( AT_GREY, "Your $t hits a wall and bounces harmlessly to the ground to the $T.", ch, projectile->myobj(  ).c_str(  ), dir_name[dir], TO_CHAR );
            act( AT_GREY, "$p strikes the $Tsern wall and falls harmlessly to the ground.", ch, projectile, dir_name[dir], TO_ROOM );
            if( projectile->in_obj )
               projectile->from_obj(  );
            if( projectile->carried_by )
               projectile->from_char(  );
            projectile->to_room( ch->in_room, ch );
         }
         else
         {
            act( AT_MAGIC, "Your $t harmlessly hits a wall to the $T.", ch, stxt, dir_name[dir], TO_CHAR );
            act( AT_MAGIC, "$t strikes the $Tsern wall and falls harmlessly to the ground.", ch, aoran( stxt ), dir_name[dir], TO_ROOM );
         }
         break;
      }
      if( projectile )
         act( AT_GREY, "$p flies in from $T.", ch, projectile, dtxt, TO_ROOM );
      else
         act( AT_MAGIC, "$t flies in from $T.", ch, aoran( stxt ), dtxt, TO_ROOM );
      ++dist;
   }

   ch->from_room(  );
   if( !ch->to_room( was_in_room ) )
      log_printf( "char_to_room: %s:%s, line %d.", __FILE__, __func__, __LINE__ );

   if( projectile->carried_by == ch )
      projectile->extract(  );
   return rNONE;
}
Пример #6
0
/*
 * The main entry point for executing commands.
 * Can be recursively called from 'at', 'order', 'force'.
 */
void interpret( CHAR_DATA * ch, const char *argument )
{
   char command[MAX_INPUT_LENGTH];
   char logline[MAX_INPUT_LENGTH];
   char logname[MAX_INPUT_LENGTH];
   TIMER *timer = NULL;
   CMDTYPE *cmd = NULL;
   int trust;
   int loglvl;
   bool found;
   struct timeval time_used;
   long tmptime;


   if( !ch )
   {
      bug( "interpret: null ch!", 0 );
      return;
   }

   found = FALSE;
   if( ch->substate == SUB_REPEATCMD )
   {
      DO_FUN *fun;

      if( ( fun = ch->last_cmd ) == NULL )
      {
         ch->substate = SUB_NONE;
         bug( "interpret: SUB_REPEATCMD with NULL last_cmd", 0 );
         return;
      }
      else
      {
         int x;

         /*
          * yes... we lose out on the hashing speediness here...
          * but the only REPEATCMDS are wizcommands (currently)
          */
         for( x = 0; x < 126; x++ )
         {
            for( cmd = command_hash[x]; cmd; cmd = cmd->next )
               if( cmd->do_fun == fun )
               {
                  found = TRUE;
                  break;
               }
            if( found )
               break;
         }
         if( !found )
         {
            cmd = NULL;
            bug( "interpret: SUB_REPEATCMD: last_cmd invalid", 0 );
            return;
         }
         sprintf( logline, "(%s) %s", cmd->name, argument );
      }
   }

   if( !cmd )
   {
      /*
       * Changed the order of these ifchecks to prevent crashing. 
       */
      if( !argument || !strcmp( argument, "" ) )
      {
         bug( "interpret: null argument!", 0 );
         return;
      }

      /*
       * Strip leading spaces.
       */
      while( isspace( *argument ) )
         argument++;
      if( argument[0] == '\0' )
         return;

      timer = get_timerptr( ch, TIMER_DO_FUN );

      /*
       * REMOVE_BIT( ch->affected_by, AFF_HIDE ); 
       */

      /*
       * Implement freeze command.
       */
      if( !IS_NPC( ch ) && IS_SET( ch->act, PLR_FREEZE ) )
      {
         send_to_char( "You're totally frozen!\r\n", ch );
         return;
      }

      /*
       * Grab the command word.
       * Special parsing so ' can be a command,
       *   also no spaces needed after punctuation.
       */
      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 );

      /*
       * Look for command in command table.
       * Check for council powers and/or bestowments
       */
      trust = get_trust( ch );
      for( cmd = command_hash[LOWER( command[0] ) % 126]; cmd; cmd = cmd->next )
         if( !str_prefix( command, cmd->name )
             && ( cmd->level <= trust
                  || ( !IS_NPC( ch ) && ch->pcdata->bestowments && ch->pcdata->bestowments[0] != '\0'
                       && is_name( cmd->name, ch->pcdata->bestowments ) && cmd->level <= ( trust + 5 ) ) ) )
         {
            found = TRUE;
            break;
         }

      /*
       * Turn off afk bit when any command performed.
       */
      if( !IS_NPC( ch ) && IS_SET( ch->act, PLR_AFK ) && ( str_cmp( command, "AFK" ) ) )
      {
         REMOVE_BIT( ch->act, PLR_AFK );
         act( AT_GREY, "$n is no longer afk.", ch, NULL, NULL, TO_ROOM );
      }
   }

   /*
    * Log and snoop.
    */
   sprintf( lastplayercmd, "** %s: %s", ch->name, logline );

   if( found && cmd->log == LOG_NEVER )
      strcpy( logline, "XXXXXXXX XXXXXXXX XXXXXXXX" );

   loglvl = found ? cmd->log : LOG_NORMAL;

   if( ( !IS_NPC( ch ) && IS_SET( ch->act, PLR_LOG ) )
       || fLogAll || loglvl == LOG_BUILD || loglvl == LOG_HIGH || loglvl == LOG_ALWAYS )
   {
      /*
       * Added by Narn to show who is switched into a mob that executes
       * a logged command.  Check for descriptor in case force is used. 
       */
      if( ch->desc && ch->desc->original )
         sprintf( log_buf, "Log %s (%s): %s", ch->name, ch->desc->original->name, logline );
      else
         sprintf( log_buf, "Log %s: %s", ch->name, logline );

      /*
       * Make it so a 'log all' will send most output to the log
       * file only, and not spam the log channel to death   -Thoric
       */
      if( fLogAll && loglvl == LOG_NORMAL && ( IS_NPC( ch ) || !IS_SET( ch->act, PLR_LOG ) ) )
         loglvl = LOG_ALL;

      /*
       * This is handled in get_trust already 
       */
/*	if ( ch->desc && ch->desc->original )
	  log_string_plus( log_buf, loglvl,
		ch->desc->original->level );
	else*/
      log_string_plus( log_buf, loglvl, get_trust( ch ) );
   }

   if( ch->desc && ch->desc->snoop_by )
   {
      sprintf( logname, "%s", ch->name );
      write_to_buffer( ch->desc->snoop_by, logname, 0 );
      write_to_buffer( ch->desc->snoop_by, "% ", 2 );
      write_to_buffer( ch->desc->snoop_by, logline, 0 );
      write_to_buffer( ch->desc->snoop_by, "\r\n", 2 );
   }



   if( timer )
   {
      int tempsub;

      tempsub = ch->substate;
      ch->substate = SUB_TIMER_DO_ABORT;
      ( timer->do_fun ) ( ch, "" );
      if( char_died( ch ) )
         return;
      if( ch->substate != SUB_TIMER_CANT_ABORT )
      {
         ch->substate = tempsub;
         extract_timer( ch, timer );
      }
      else
      {
         ch->substate = tempsub;
         return;
      }
   }

   /*
    * Look for command in skill and socials table.
    */
   if( !found )
   {
      if( !check_skill( ch, command, argument ) && !check_social( ch, command, argument )
#ifdef IMC
          && !imc_command_hook( ch, command, argument )
#endif
          )
      {
         EXIT_DATA *pexit;

         /*
          * check for an auto-matic exit command 
          */
         if( ( pexit = find_door( ch, command, TRUE ) ) != NULL && IS_SET( pexit->exit_info, EX_xAUTO ) )
         {
            if( IS_SET( pexit->exit_info, EX_CLOSED )
                && ( !IS_AFFECTED( ch, AFF_PASS_DOOR ) || IS_SET( pexit->exit_info, EX_NOPASSDOOR ) ) )
            {
               if( !IS_SET( pexit->exit_info, EX_SECRET ) )
                  act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
               else
                  send_to_char( "You cannot do that here.\r\n", ch );
               return;
            }
            move_char( ch, pexit, 0 );
            return;
         }
         send_to_char( "Huh?\r\n", ch );
      }
      return;
   }

   /*
    * Character not in position for command?
    */
   if( !check_pos( ch, cmd->position ) )
      return;

   /*
    * Berserk check for flee.. maybe add drunk to this?.. but too much
    * hardcoding is annoying.. -- Altrag 
    */
   if( !str_cmp( cmd->name, "flee" ) && IS_AFFECTED( ch, AFF_BERSERK ) )
   {
      send_to_char( "You aren't thinking very clearly..\r\n", ch );
      return;
   }

   /*
    * Dispatch the command.
    */
   ch->prev_cmd = ch->last_cmd;  /* haus, for automapping */
   ch->last_cmd = cmd->do_fun;
   start_timer( &time_used );
   ( *cmd->do_fun ) ( ch, argument );
   end_timer( &time_used );
   /*
    * Update the record of how many times this command has been used (haus)
    */
   update_userec( &time_used, &cmd->userec );
   tmptime = UMIN( time_used.tv_sec, 19 ) * 1000000 + time_used.tv_usec;

   /*
    * laggy command notice: command took longer than 1.5 seconds 
    */
   if( tmptime > 1500000 )
   {
      sprintf( log_buf, "[*****] LAG: %s: %s %s (R:%d S:%d.%06d)", ch->name,
               cmd->name, ( cmd->log == LOG_NEVER ? "XXX" : argument ),
               ch->in_room ? ch->in_room->vnum : 0, ( int )( time_used.tv_sec ), ( int )( time_used.tv_usec ) );
      log_string_plus( log_buf, LOG_NORMAL, get_trust( ch ) );
   }

   tail_chain(  );
}