Problems With Destroy Command

Posted by Kris on Sat 12 May 2001 10:28 PM — 19 posts, 68,646 views.

USA #0
The destroy command doesn't work. Everytime we attempt to use it, it says 'Player does not exist.' and disconnects the player we're trying to delete. However, it doesn't delete the pfile, nor does it save it to the backup directory. I checked the source code, and the mud.h file, and the path is correct. What do I need to change in the source code to get this built-in command to work as it's supposed to?
Australia Forum Administrator #1
Do you have a backup directory? In my case there isn't one (probably because it was initially empty and WinZip does not create empty directories). Try creating a directory called "backup" at the same level as the "player" directory.

However if you are using Cygwin, I found that the version of the source I had wanted the backup directory inside the player directory.

Also, make sure that you create subdirectories for each letter of the alphabet.

This file shows the location of the backup directory:


mud.h:#define BACKUP_DIR "../player/backup/"



eg.


$ ls player
a backup d f h j l n p r t v x z
b c e g i k m o q s u w y

$ ls player/backup
a b c d e f g h i j k l m n o p
q r s t u v w x y z


Once you have the directory set up, you should be able to do a destroy, like this:


destroy nick
Log: Lordrom: destroy nick
Player Nick destroyed. Pfile saved in backup directory.


Amended on Sun 13 May 2001 04:11 AM by Nick Gammon
USA #2
I'm trying to change the 'destroy' command so it can't be used on admins. Such deletions should be kept to the person who has direct server access, namely myself. I managed to put in a level ifcheck to check to see if the victim's level was >= 1000, and it worked. However, it only works if that person is online. How do I make it so it'll check when the person is offline or online? Also, how do I perform name-checking? I tried to just save the trouble and have it check for specific names, but I couldn't get that to work either. Nor could I figure out a way to check the victim's level if not online. How would I accomplish either one of these things?
Australia Forum Administrator #3
For checking the level of players that are not connected, see what the "loadup" command does. That loads a character so an admin can work on it even if they are not playing. I would do something like that, and check their level.
USA #4
I tried what you suggested, but I think I need more information. As a test, and hopefully as a solution to another problem we've been having, I tried using your loadup idea to make it so that 'whois' will work on a player even if they're not online. I tried everything from copying the do_loadup code into do_whois to simply putting a do_loadup call, both of which within an ifcheck to see if the player is online or not. However, I haven't even come close to successful. The thing is, I'd rather not have the Comm logs spammed up every time someone does a whois on an offline player, so I prefer to copy the loadup code directly into the function, but only what I need. If that would work, what would I have to do in order to accomplish this? Otherwise, how would I successfully implement a do_loadup function call within the do_whois function? If this eventually works, I'll use the same premise with do_destroy.
Australia Forum Administrator #5
It is very hard to answer this sort of question.

You haven't said:

* What you tried (eg. code snippet)

or

* What went wrong. (Wouldn't compile? Crashed? Didn't crash but didn't work?)

I don't really have time to sit down and write code for everyone. I don't mind giving hints about where to look, but after that you are on your own a bit, sorry.
USA #6
Ok, how would I make a one-line function call into do_loadup from do_whois? Would I simply put:
do_loadup
or would I need to pass some argument, like do_loadup (victim) or something like that? That's what I can't seem to figure out, and I can't find anywhere in the source where it makes a specific call to do_loadup, so I don't have an example to work from.
USA #7
Would anybody know?
Australia Forum Administrator #8
Well, do_loadup has two arguments, a pointer to your player data, and an argument list. It expects one argument in that list, so something like this should work:


do_loadup(ch, "gandalf");
USA #9
In do_whois, victim stands for the person you're inquiring whois info on. Therefore, based on your last post, I attempted the following:

do_loadup2( ch, victim );

(I duplicated do_loadup, but got rid of echos and logs and stuff, so it won't spam up the mud whenever someone uses the whois command on an offline player).

However, in do_loadup2, it fails the ifcheck that determines if there's an argument given or not. Therefore, I'm assuming that I'm passing the victim's name over the wrong way. I tried changing it to:

do_loadup2( ch, victim->name );

But that just crashed the mud. How do I pass it through as whatever the person types in whois?
Australia Forum Administrator #10
I'm having to guess what you are doing because you are not providing any code, which makes debugging almost impossible, but I would guess that you are passing a NULL pointer as "victim", which would indeed crash the MUD.

The relevant code in do_whois is:


void do_whois( CHAR_DATA *ch, char *argument)
{
  CHAR_DATA *victim;
  char buf[MAX_STRING_LENGTH];
  char buf2[MAX_STRING_LENGTH];

  buf[0] = '\0';

  if(IS_NPC(ch))
    return;

  if(argument[0] == '\0')
  {
    send_to_pager("You must input the name of an online character.\n\r", ch);
    return;
  }

  strcat(buf, "0.");
  strcat(buf, argument);
  if( ( ( victim = get_char_world(ch, buf) ) == NULL ))
  {
// <--- is your code here ?? 
    send_to_pager("No such character online.\n\r", ch);
    return;
  }



If your call to do_loadup2 is where I marked, which I assume you are doing, otherwise the victim is online, then you are passing a NULL victim pointer to do_loadup, which then cannot dereference it to get the name.

Why not just pass the "argument" to do_whois, which is, after all, the person you are looking for.

eg.


do_loadup2 (ch, argument);



Amended on Tue 12 Jun 2001 03:05 AM by Nick Gammon
USA #11
I have since gotten the do_whois code to work for both online and offline players, thanks to your help :)
Now, I've been trying for several days to implement the same premise into do_destroy. Alas, no matter how many different approaches I take, my knowledge of C (and this source) is still very limited, and I'm at a loss. I apologize for the following lengthyness, but I feel it's necessary to post the relevant first 2/3 of the function code, so that you may be able to tell me what's wrong. In it also is the specific name-checks I attempted (unsuccessfully) to implement. I have documented key parts of the code with comment tags for your convenience. Here it is:


void do_destroy( CHAR_DATA *ch, char *argument )
{
CHAR_DATA *victim;
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];

/* My unsuccessful attempt to put in a specific name-check */
char admin1[MAX_STRING_LENGTH];
char admin2[MAX_STRING_LENGTH];
char admin3[MAX_STRING_LENGTH];
char admin4[MAX_STRING_LENGTH];
char admin5[MAX_STRING_LENGTH];
char admin6[MAX_STRING_LENGTH];
char admin7[MAX_STRING_LENGTH];
char admin8[MAX_STRING_LENGTH];
char admin9[MAX_STRING_LENGTH];
char admin10[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
char *name;

set_char_color( AT_RED, ch );

one_argument( argument, arg );
if ( arg[0] == '\0' )
{
send_to_char( "Destroy what player file?\n\r", ch );
return;
}

for ( victim = first_char; victim; victim = victim->next )
if ( !IS_NPC(victim) && !str_cmp(victim->name, arg) )
break;

if ( !victim )
{
DESCRIPTOR_DATA *d;

/* Make sure they aren't halfway logged in. */
for ( d = first_descriptor; d; d = d->next )
{

if ( (victim = d->character) && !IS_NPC(victim) &&
!str_cmp(victim->name, arg) )
break;
if ( d )
close_socket( d, TRUE );
}
}
else
{

int x, y;
if( ( ( victim = get_char_world(ch, argument) ) == NULL )) /* Same thing I used successfully in
do_whois, but I haven't even come close to success using it in this function */
{
do_loadup2( ch, argument );
if( ( ( victim = get_char_world(ch, argument) ) == NULL ))
return;
do_goto2 (victim, "1"); /* To protect the link-dead player from being tampered with --Kris */
}
if ( victim->level >= 1000 ) /* This ifcheck only seems to work if the player is online */
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
if ( !victim->desc ) /* Just in case the player was loaded-up */
do_quit2( victim, "" );
return;
}


quitting_char = victim;
save_char_obj( victim );
saving_char = NULL;
extract_char( victim, TRUE );
for ( x = 0; x < MAX_WEAR; x++ )
for ( y = 0; y < MAX_LAYERS; y++ )
save_equipment[x][y] = NULL;
}

name = capitalize( arg );

/* Again, more lousy attempts on my part for a specific name-check (I feel like a lost cause) */
sprintf( admin1, "Kris" );
sprintf( admin2, "Mccavity" );
sprintf( admin3, "Yoshi" );
sprintf( admin4, "Penwhale" );
sprintf( admin5, "Xcan" );
sprintf( admin6, "Malfalas" );
sprintf( admin7, "Argos" );
sprintf( admin8, "Cosmo" );
sprintf( admin9, "Lordrom" );
sprintf( admin10, "Admin" );

if ( name == admin1 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin2 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin3 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin4 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin5 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin6 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin7 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin8 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin9 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}
if ( name == admin10 )
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}

/* And the rest is as-is from here.... */


So, you can see how much of a mess this is I'm sure. I know the problem I present is very detailed, yet my question is vague. Still, ummm.... how do I get this to work? :P Thank you for your time and help =)
*sigh*
Australia Forum Administrator #12
Hmmm - if I may suggest this without giving offence - you really would be helped by reading a good book on C. An "Introduction to C" book would cover this sort of material, and would make it much easier for you to progress.

Your problem here is you are comparing pointers, not what the pointers are pointing to.


eg.


sprintf( admin1, "Kris" );
...
if ( name == admin1 )


"admin1" is an area of memory (say with address 0x0012FCD4) and "name" is another area of memory (say with address 0x00E42FFD). Comparing those two is asking:

Is 0x0012FCD4 the same as 0x00E42FFD?

Well, they're not. They are different memory locations, and thus the pointers will have different numbers in them.

What you want is this:


if (strcmp (name, admin1) == 0)
... error message ...


"strcmp" is a "string compare" routine that compares two strings, and returns 0 if they are the same. You pass two pointers to it.

You also don't need your ten fields "admin1" through to "admin10". That is very long-winded. All you need to do is this ( the symbol "||" means "or" ) :


if (strcmp (name, "Kris") == 0 ||
strcmp (name, "Mccavity") == 0 ||
strcmp (name, "Yoshi") == 0 ||
strcmp (name, "Penwhale") == 0 ||
strcmp (name, "Xcan") == 0 ||
strcmp (name, "Malfalas") == 0 ||
strcmp (name, "Argos") == 0 ||
strcmp (name, "Cosmo") == 0 ||
strcmp (name, "Lordrom") == 0 ||
strcmp (name, "Admin") == 0)
{
send_to_char( "You cannot destroy admins. Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
return;
}

Amended on Fri 15 Jun 2001 01:22 AM by Nick Gammon
USA #13
I've implemented the name check, and it works =)
However, I'm still having trouble with the basic ifcheck to see if a person is above level 1000 (the name check is just to ensure that, regardless of level, certain people can't be dested). It works just fine if the player is online, but when I tried to use the same premise that worked with do_whois (i.e. do_loadup2, etc), I've been having the runtime errors. Do you have any insight as to how I may resolve that problem as well? Thank you for all you help :)
USA #14
Does anybody have an answer to this and the WAIT_STATE problem I posted a few days ago in the "problems with source code" section?
USA #15
I've implemented the name check, and it works =)
However, I'm still having trouble with the basic ifcheck to see if a person is above level 1000 (the name check is just to ensure that, regardless of level, certain
people can't be dested). It works just fine if the player is online, but when I tried to use the same premise that worked with do_whois (i.e. do_loadup2, etc), I've
been having the runtime errors. Do you have any insight as to how I may resolve that problem as well? Thank you for all you help :)
Australia Forum Administrator #16
It really is impossible to debug your source code changes when I can't see what the source code is.
USA #17
I apologize for my lack of detail. An older version of this function is posted earlier in this subject, where my attempts to loadup the person to do the level check in the same manner as I did in do_whois are shown. Here is the most recent version of this function:


void do_destroy( CHAR_DATA *ch, char *argument )
{
  CHAR_DATA *victim;
  char buf[MAX_STRING_LENGTH];
  char buf2[MAX_STRING_LENGTH];
  char arg[MAX_INPUT_LENGTH];
  char *name;

  set_char_color( AT_RED, ch );

  one_argument( argument, arg );
  if ( arg[0] == '\0' )
  {
      send_to_char( "Destroy what player file?\n\r", ch );
      return;
  }

  for ( victim = first_char; victim; victim = victim->next )
    if ( !IS_NPC(victim) && !str_cmp(victim->name, arg) )
      break;
    
  if ( !victim )
  {
    DESCRIPTOR_DATA *d;
    
    /* Make sure they aren't halfway logged in. */
    for ( d = first_descriptor; d; d = d->next )
      if ( (victim = d->character) && !IS_NPC(victim) &&
          !str_cmp(victim->name, arg) )
        break;
    if ( d )
      close_socket( d, TRUE );
  }
  else       
  {
    int x, y;

    if ( victim->level >= 1000 )  /* This ifcheck only seems to work if the player is online */
    {
     sprintf( buf, "<FYI> %s has attempted to **ILLEGALLY** destroy an admin!!", ch->name ); 
      echo_to_all( AT_IMMORT, buf, ECHOTAR_ALL );
     send_to_char( "You cannot destroy admins.  Such action requires direct server file access.\nThis attept has been logged.\n\n", ch );
     return;
    }
    

    quitting_char = victim;
    save_char_obj( victim );
    saving_char = NULL;
    extract_char( victim, TRUE );
    for ( x = 0; x < MAX_WEAR; x++ )
	for ( y = 0; y < MAX_LAYERS; y++ )
	    save_equipment[x][y] = NULL;
  }
  
  name = capitalize( arg );


if (strcmp (name, "Kris") == 0 || 
 strcmp (name, "Mccavity") == 0 || 
 strcmp (name, "Yoshi") == 0 || 
 strcmp (name, "Penwhale") == 0 || 
 strcmp (name, "Xcan") == 0 || 
 strcmp (name, "Malfalas") == 0 || 
 strcmp (name, "Argos") == 0 || 
 strcmp (name, "Cosmo") == 0 || 
 strcmp (name, "Alquerian") == 0 || 
 strcmp (name, "Lordrom") == 0 || 
 strcmp (name, "Admin") == 0) 
 { 
  sprintf( buf, "<FYI> %s has attempted to **ILLEGALLY** destroy an admin!!", ch->name ); 
   echo_to_all( AT_IMMORT, buf, ECHOTAR_ALL );
  ch_printf( ch, "You cannot destroy %s. Such action requires direct server file access.\nThis attept has been logged.\n\n", name ); 
  return; 
 } 
        
  sprintf( buf, "%s%c/%s", PLAYER_DIR, tolower(arg[0]), name );
  ch_printf( ch, "Destroying %s%c/%s.... \n", PLAYER_DIR, tolower(arg[0]), name );
  sprintf( buf2, "%s%c/%s", BACKUP_DIR, tolower(arg[0]), name );
  if ( !rename( buf, buf2 ) )
  {
    AREA_DATA *pArea;
    
    sprintf( buf, "<FYI> %s has been destroyed by an immortal!", name ); 
     echo_to_all( AT_IMMORT, buf, ECHOTAR_ALL );
    set_char_color( AT_RED, ch );
    ch_printf(ch, "Player %s destroyed.  Pfile saved in backup directory.\n\r", 
		name );
    sprintf( buf, "%s%s", GOD_DIR, name );
    if ( !remove( buf ) )
      send_to_char( "Player's immortal data destroyed.\n\r", ch );
    else if ( errno != ENOENT )
    {
      ch_printf( ch, "Unknown error #%d - %s (immortal data).  Report to Kris.\n\r",
              errno, strerror( errno ) );
      sprintf( buf2, "%s destroying %s", ch->name, buf );
      perror( buf2 );
    }

    sprintf( buf2, "%s.are", name );
    for ( pArea = first_build; pArea; pArea = pArea->next )
      if ( !str_cmp( pArea->filename, buf2 ) )
      {
        sprintf( buf, "%s%s", BUILD_DIR, buf2 );
        if ( IS_SET( pArea->status, AREA_LOADED ) )
          fold_area( pArea, buf, FALSE );
        close_area( pArea );
        sprintf( buf2, "%s.bak", buf );
        set_char_color( AT_RED, ch ); /* Log message changes colors */
        if ( !rename( buf, buf2 ) )
          send_to_char( "Player's area data destroyed.  Area saved as backup.\n\r", ch );
        else if ( errno != ENOENT )
        {
          ch_printf( ch, "Unknown error #%d - %s (area data).  Report to Kris.\n\r",
                  errno, strerror( errno ) );
          sprintf( buf2, "%s destroying %s", ch->name, buf );
          perror( buf2 );
        }
	break;
      }
  }
  else if ( errno == ENOENT )
  {
    set_char_color( AT_PLAIN, ch );
    send_to_char( "Player does not exist.\n\r", ch );
  }
  else
  {
    set_char_color( AT_WHITE, ch );
    ch_printf( ch, "Unknown error #%d - %s.  Report to Kris.\n\r",
            errno, strerror( errno ) );
    sprintf( buf, "%s destroying %s", ch->name, arg );
    perror( buf );
  }
  return;
}


I can't get the level check to work for someone who is offline. The earlier version of the function shown has my attempts in it.
Amended on Wed 27 Jun 2001 08:42 AM by Nick Gammon
Australia Forum Administrator #18
Hard to say. I'm not going to spend hours debugging your code here. I suggest some debugging displays, eg printf so you can see if "victim" is NULL or not.