Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ SMAUG ➜ SMAUG coding ➜ Problems with "Skinning"

Problems with "Skinning"

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by RavenSavage   USA  (7 posts)  Bio
Date Sat 11 Aug 2007 08:48 AM (UTC)
Message
Howdy,

I'm trying to change the skin code around and have managed to compile my changes and whatnot, but when the skill is used, there is a crash. Below is the code with changes, I have a feeling I'm not freeing/allocating something properly, any help would be appreciated.


void do_skin( CHAR_DATA *ch, char *argument )
{
   OBJ_DATA *korps, *corpse, *obj, *skin;
   bool checkknife;
   char *name;
   char buf[MAX_STRING_LENGTH];
   int schance;
   
   switch ( ch->substate )
   {
      default:
            
        if( argument[0] == '\0' )
        {
          send_to_char( "What corpse do you wish to skin?\r\n", ch );
          return;
        }
   
        checkknife = FALSE;
          
   
        if( ( corpse = get_obj_here( ch, argument ) ) == NULL )
        {
          send_to_char( "You cannot find that here.\r\n", ch );
          return;
        }
         
     for ( obj = ch->last_carrying; obj; obj = obj->prev_content )
        {
          if ( obj->item_type == ITEM_SKNIFE && obj->wear_loc == WEAR_WIELD )
          checkknife = TRUE;
        }
        
        if ( !checkknife )
        {
          send_to_char( "You are not wielding a skinning knife.\r\n", ch );
          return;
        }

        if( corpse->value[4] == 25)
        {
          send_to_char( "There is no skin on this corpse.\r\n", ch );
          return;
        }
        if( get_obj_index( OBJ_VNUM_SKIN ) == NULL )
        {
          bug( "Vnum %d (OBJ_VNUM_SKIN) not found for do_skin!", OBJ_VNUM_SKIN );
          return;
        }
   
    schance = IS_NPC(ch) ? ch->level : (int) (ch->pcdata->learned[gsn_skin]) ;

        if ( number_percent( ) < schance )
        {
           send_to_char( "&GYou begin the process of skinning a corpse.\n\r", ch);
           act( AT_PLAIN, "$n takes $s knife and begins to skin a corpse.", ch, NULL, argument , TO_ROOM );
           add_timer ( ch , TIMER_DO_FUN , 2 , do_skin , 1 );
           ch->alloc_ptr = str_dup( buf );
           return;
         }
           send_to_char("&RYour knife slips and ruins the skin.\n\r",ch);
           learn_from_failure( ch, gsn_skin );
           corpse->value[4] = 25;
           return;
           
      case 1:
         if( !ch->alloc_ptr )
         return;
         mudstrlcpy( buf, ch->alloc_ptr, MAX_INPUT_LENGTH );
         DISPOSE( ch->alloc_ptr );
         break;
         
      case SUB_TIMER_DO_ABORT:
         DISPOSE( ch->alloc_ptr );
         ch->substate = SUB_NONE;
         send_to_char( "You carefully stop what you were doing.\r\n", ch );
         return;
   }

    ch->substate = SUB_NONE;           
   
   korps = create_object( get_obj_index( OBJ_VNUM_CORPSE_NPC ), 0 );
   skin = create_object( get_obj_index( OBJ_VNUM_SKIN ), 0 );
   name = IS_NPC( ch ) ? korps->short_descr : corpse->short_descr;
   snprintf( buf, MAX_STRING_LENGTH, skin->short_descr, name );
   STRFREE( skin->short_descr );
   skin->short_descr = STRALLOC( buf );
   snprintf( buf, MAX_STRING_LENGTH, skin->description, name );
   STRFREE( skin->description );
   skin->description = STRALLOC( buf );
   corpse->value[4] = 25;
   act( AT_BLOOD, "$n strips the skin from $p.", ch, corpse, NULL, TO_ROOM );
   act( AT_BLOOD, "You strip the skin from $p.", ch, corpse, NULL, TO_CHAR );
   obj_to_char( skin, ch );
   return;
}


Any help is appreciated.
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #1 on Sat 11 Aug 2007 10:36 AM (UTC)
Message
Short of trying it myself, I suggest you fire up gdb and make it crash - at least that shows what line is responsible.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,133 posts)  Bio   Forum Administrator
Date Reply #2 on Sat 11 Aug 2007 10:45 AM (UTC)
Message
I can see one problem, you have introduced a switch statement, compared to the original. If the ch->substate is equal to 1, then the variable corpse is not defined, however you dereference it later on.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #3 on Sat 11 Aug 2007 11:55 AM (UTC)
Message
if ( number_percent( ) < schance )
{
  send_to_char( "&GYou begin the process of skinning a corpse.\n\r", ch);
  act( AT_PLAIN, "$n takes $s knife and begins to skin a corpse.", ch, NULL, argument , TO_ROOM );
  add_timer ( ch , TIMER_DO_FUN , 2 , do_skin , 1 );
  ch->alloc_ptr = str_dup( buf );
  return;
}


If I'm reading it correctly, buf hasn't been initialised at this point? So, if it doesn't contain a 0, str_dup will run off the end of the array and segfault.

What's supposed to happen to the korps object? It looks like it's being leaked at the end of the function?
Top

Posted by Gohan_TheDragonball   USA  (183 posts)  Bio
Date Reply #4 on Sun 12 Aug 2007 02:28 AM (UTC)
Message
move:
if( ( corpse = get_obj_here( ch, argument ) ) == NULL )
{
send_to_char( "You cannot find that here.\r\n", ch );
return;
}

to just before the substate switch statement. like nick said you are referencing its corpse->short_descr later when it is only being initialized when the command is first typed. moving that to before the switch statement should fix your problem, also it will prevent a crash if in the time it takes the timer to expire someone picks up the corpse.
Top

Posted by Gohan_TheDragonball   USA  (183 posts)  Bio
Date Reply #5 on Sun 12 Aug 2007 02:31 AM (UTC)
Message
and just as a possible catch:
STRFREE( skin->short_descr );
STRFREE( skin->description );

should be
if ( skin->short_descr )
STRFREE( skin->short_descr );
if ( skin->description )
STRFREE( skin->description );
Top

Posted by RavenSavage   USA  (7 posts)  Bio
Date Reply #6 on Sun 12 Aug 2007 05:16 AM (UTC)
Message
Moving the corpse check to before the switch statement does prevent a crash, but shorts out the timer (as in, when a character issues a command in the timer, the abort doesn't fire, it instantly completes the whole thing)

Also, it doesn't move past the corpse check, when the timer completes, it gives the "You cannot find that here" message, as per the check. So, the check apparently isn't working right. I'll fiddle with it some more. (though it's looking more appealing to kill the whole switch and just make it a delay)

I appreciate all the help.
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #7 on Sun 12 Aug 2007 06:23 AM (UTC)
Message
Quote:
should be
if ( skin->short_descr )
  STRFREE( skin->short_descr );
if ( skin->description )
  STRFREE( skin->description );


snprintf with a NULL cause a segfault before we reach the STRFREE. So, if you are going to add the sanity check (and how would short_descr or description end up NULL anyway?), it has to be added higher:
if (skin->short_descr) {
  snprintf( buf, MAX_STRING_LENGTH, skin->short_descr, name );
  STRFREE( skin->short_descr );
  skin->short_descr = STRALLOC( buf );
}
if (skin->description) {
  snprintf( buf, MAX_STRING_LENGTH, skin->description, name );
  STRFREE( skin->description );
  skin->description = STRALLOC( buf );
}

Top

Posted by Conner   USA  (381 posts)  Bio
Date Reply #8 on Sun 12 Aug 2007 10:18 PM (UTC)
Message
For what it's worth, this is how I made my do_skin work to my satisfaction (Thanks to Remcon for his help with this one) a couple of years ago, maybe it'll work for you too?

void do_skin( CHAR_DATA * ch, char *argument )
{
   OBJ_DATA *corpse, *obj, *skin;
   char buf[MAX_STRING_LENGTH], *temp;
   if( !IS_PKILL( ch ) && !IS_IMMORTAL( ch ) )
   {
      send_to_char( "Leave the hideous defilings to the killers!\n", ch );
      return;
   }
   if( !argument || argument[0] == '\0' )
   {
      send_to_char( "Whose corpse do you wish to skin?\r\n", ch );
      return;
   }
   if( ( corpse = get_obj_here( ch, argument ) ) == NULL )
   {
      send_to_char( "You cannot find that here.\r\n", ch );
      return;
   }
   if( !IS_IMMORTAL( ch ) )
   {
      /* This is restrictions for mortals only 
       * They have to hold a weapon and of a certian type
       * They can only skin other player corpses and thats if they got final blow
       * And the corpse can only be skinned once       */
      if( ( obj = get_eq_char( ch, WEAR_WIELD ) ) == NULL )
      {
         send_to_char( "You have no weapon with which to perform this deed.\r\n", ch );
         return;
      }
      if( obj->value[3] != 1 && obj->value[3] != 2 && obj->value[3] != 3 && obj->value[3] != 11 )
      {
         send_to_char( "You're not holding the right kind of weapon to skin a corpse.\r\n", ch );
         return;
      }
      if( corpse->item_type != ITEM_CORPSE_PC )
      {
         send_to_char( "You can only skin the bodies of player characters.\r\n", ch );
         return;
      }
      if( !corpse->action_desc || str_cmp( corpse->action_desc, ch->name ) )
      {
         send_to_char( "You can't skin a corpse if you didn't get the final blow on the player.\r\n", ch );
         return;
      }
      if( corpse->value[5] >= 1 )
      {
         send_to_char( "That corpse has already been skinned.\r\n", ch );
         return;
      }
   }
   /* Immortals can skin npc and pc corpses */
   else if( corpse->item_type != ITEM_CORPSE_PC && corpse->item_type != ITEM_CORPSE_NPC )
   {
      send_to_char( "You can only skin corpses.\r\n", ch );
      return;
   }
   if( !get_obj_index( OBJ_VNUM_SKIN ) )
   {
      bug( "%s: Vnum %d (OBJ_VNUM_SKIN) not found!", __FUNCTION__, OBJ_VNUM_SKIN );
      send_to_char( "The skin object couldn't be found.\r\n", ch );
      return;
   }
   if( !( skin = create_object( get_obj_index( OBJ_VNUM_SKIN ), 0 ) ) )
   {
      bug( "%s: couldn't create skin [%d]", __FUNCTION__, OBJ_VNUM_SKIN );
      send_to_char( "A skin object couldn't be created.\r\n", ch );
      return;
   }
   temp = corpse->short_descr;
   temp = one_argument( temp, buf );
   temp = one_argument( temp, buf );
   temp = one_argument( temp, buf );
   if( skin->short_descr )
   {
      snprintf( buf, MAX_STRING_LENGTH, skin->short_descr, temp );
      STRFREE( skin->short_descr );
      skin->short_descr = STRALLOC( buf );
   }
   if( skin->description )
   {
      snprintf( buf, MAX_STRING_LENGTH, skin->description, temp );
      STRFREE( skin->description );
      skin->description = STRALLOC( buf );
   }
   corpse->value[5] = 1;
   act( AT_BLOOD, "$n strips the skin from $p.", ch, corpse, NULL, TO_ROOM );
   act( AT_BLOOD, "You strip the skin from $p.", ch, corpse, NULL, TO_CHAR );
   obj_to_char( skin, ch );
   return;
}

-=Conner=-
--
Come test your mettle in the Land of Legends at telnet://tcdbbs.zapto.org:4000
or, for a little family oriented medieval fun, come join us at The Castle's Dungeon BBS at telnet://tcdbbs.zapto.org
or, if you just want information about either, check our web page at http://tcdbbs.zapto.org
Top

Posted by Gohan_TheDragonball   USA  (183 posts)  Bio
Date Reply #9 on Mon 13 Aug 2007 02:54 AM (UTC)
Message
sorry i guess i should have mentioned a couple things. it makes sense that when the timer expires, it does not find the corpse anywhere since you are not storing the argument. also when i went to check if you were storing the argument, i found this:

        if ( number_percent( ) < schance )
        {
           send_to_char( "&GYou begin the process of skinning a corpse.\n\r", ch);
           act( AT_PLAIN, "$n takes $s knife and begins to skin a corpse.", ch, NULL, argument , TO_ROOM );
           add_timer ( ch , TIMER_DO_FUN , 2 , do_skin , 1 );
           ch->alloc_ptr = str_dup( buf );
           return;
         }

as of this point you have yet to set buf to anything, i assume you meant:
ch->alloc_ptr = str_dup( argument );

so try the following:

void do_skin( CHAR_DATA *ch, char *argument )
{
   OBJ_DATA *korps, *corpse, *obj, *skin;
   bool checkknife;
   char *name;
   char buf[MAX_STRING_LENGTH];
   int schance;
   
   switch ( ch->substate )
   {
      default:
            
        if( argument[0] == '\0' )
        {
          send_to_char( "What corpse do you wish to skin?\r\n", ch );
          return;
        }
   
        checkknife = FALSE;
          
        if( ( corpse = get_obj_here( ch, argument ) ) == NULL )
        {
          send_to_char( "You cannot find that here.\r\n", ch );
          return;
        }
         
     	for ( obj = ch->last_carrying; obj; obj = obj->prev_content )
        {
          if ( obj->item_type == ITEM_SKNIFE && obj->wear_loc == WEAR_WIELD )
          checkknife = TRUE;
        }
        
        if ( !checkknife )
        {
          send_to_char( "You are not wielding a skinning knife.\r\n", ch );
          return;
        }

        if( corpse->value[4] == 25)
        {
          send_to_char( "There is no skin on this corpse.\r\n", ch );
          return;
        }
        if( get_obj_index( OBJ_VNUM_SKIN ) == NULL )
        {
          bug( "Vnum %d (OBJ_VNUM_SKIN) not found for do_skin!", OBJ_VNUM_SKIN );
          return;
        }
   
    	schance = IS_NPC(ch) ? ch->level : (int) (ch->pcdata->learned[gsn_skin]) ;

        if ( number_percent( ) < schance )
        {
           send_to_char( "&GYou begin the process of skinning a corpse.\n\r", ch);
           act( AT_PLAIN, "$n takes $s knife and begins to skin a corpse.", ch, NULL, argument , TO_ROOM );
           add_timer ( ch , TIMER_DO_FUN , 2 , do_skin , 1 );
           ch->alloc_ptr = str_dup( argument );
           return;
         }
           send_to_char("&RYour knife slips and ruins the skin.\n\r",ch);
           learn_from_failure( ch, gsn_skin );
           corpse->value[4] = 25;
           return;
           
      case 1:
         if( !ch->alloc_ptr )
         return;
         mudstrlcpy( buf, ch->alloc_ptr, MAX_INPUT_LENGTH );
         DISPOSE( ch->alloc_ptr );
         break;
         
      case SUB_TIMER_DO_ABORT:
         DISPOSE( ch->alloc_ptr );
         ch->substate = SUB_NONE;
         send_to_char( "You carefully stop what you were doing.\r\n", ch );
         return;
   }

    ch->substate = SUB_NONE; 
          
    if( ( corpse = get_obj_here( ch, buf ) ) == NULL )
    {
      send_to_char( "You cannot find that here.\r\n", ch );
      return;
    }

   korps = create_object( get_obj_index( OBJ_VNUM_CORPSE_NPC ), 0 );
   skin = create_object( get_obj_index( OBJ_VNUM_SKIN ), 0 );
   name = IS_NPC( ch ) ? korps->short_descr : corpse->short_descr;
   snprintf( buf, MAX_STRING_LENGTH, skin->short_descr, name );
   STRFREE( skin->short_descr );
   skin->short_descr = STRALLOC( buf );
   snprintf( buf, MAX_STRING_LENGTH, skin->description, name );
   STRFREE( skin->description );
   skin->description = STRALLOC( buf );
   corpse->value[4] = 25;
   act( AT_BLOOD, "$n strips the skin from $p.", ch, corpse, NULL, TO_ROOM );
   act( AT_BLOOD, "You strip the skin from $p.", ch, corpse, NULL, TO_CHAR );
   obj_to_char( skin, ch );
   return;
}
Top

Posted by RavenSavage   USA  (7 posts)  Bio
Date Reply #10 on Mon 13 Aug 2007 04:23 AM (UTC)
Message
Beautiful, works like a charm.

Much thanks to all.
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


28,781 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.