For loop on obj and extract_obj specify

Posted by Zeno on Wed 19 May 2004 02:05 AM — 13 posts, 27,236 views.

USA #0
Eh, two things that I can't seem to figure out/remember how to do.

First, how would I do a for loop to check through all the players items, and containers? I know how do all items, just not through the containers.

Second, how would I specify what item extract_obj would extract? I did a for loop:

    for (shard = ch->first_carrying; shard; shard = shard->next_content)
    {
      if (shard->pIndexData->vnum == 91)
      {
        if ( arg[0] == '\0' )
          {
             send_to_char( "Where?\n\r", ch );
             return;
          }
      }


But when this is done:

extract_obj( shard );

It extracts the first obj in a players inven, instead of the item with vnum 91.
USA #1
You can't do it in a single loop. Well, you technically could, but you would need to use a stack or something. It's easier to do it recursively.

When are you calling extract_obj? You're probably not breaking out of the loop at the right spot or something like that.
USA #2
Think you could provide an example on the container loop, I've never done containers before. (I'll look over the structure though)

Uh, the for loop ending bracket at the end of the function.

    }
        send_to_char( Don't have any!\n\r", ch );
        return;
}
USA #3
Could you give the whole code for the for loop so I can be sure exactly what I'm looking at?


How to write the recursive function depends on what you're trying to do... are you trying to find a given item?
USA #4
Yeah, the full function would probably help, heh.

void do_embed( CHAR_DATA *ch, char *argument )
{
    char arg  [MAX_INPUT_LENGTH];
    OBJ_DATA *shard;
    char buf[MAX_STRING_LENGTH];

    one_argument( argument, arg );

    if ( IS_NPC(ch))
        return;

    for (shard = ch->first_carrying; shard; shard = shard->next_content)
    {
      if (shard->pIndexData->vnum == 91)
      {
        if ( arg[0] == '\0' )
          {
             send_to_char( "&wEmbed the Shikon Shard where?\n\r(arm, leg, head, neck, foot, hand, torso, shoulder)\n\r ", ch$
             return;
          }
      }

    if ( !str_cmp( arg, "arm" ) )
    {
          send_to_char( "&PYou embed a shard into your arm.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s arm.", ch, NULL, NULL, TO_CANSEE);
          ch->arm_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their arm", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "leg" ) )
        {
          send_to_char( "&PYou embed a shard into your leg.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s leg.", ch, NULL, NULL, TO_CANSEE);
          ch->leg_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their leg", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "head" ) )
        {
          send_to_char( "&PYou embed a shard into your head.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s head.", ch, NULL, NULL, TO_CANSEE);
          ch->head_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their head", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "neck" ) )
        {
          send_to_char( "&PYou embed a shard into your neck.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s neck.", ch, NULL, NULL, TO_CANSEE);
          ch->neck_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their neck", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "foot" ) )
        {
          send_to_char( "&PYou embed a shard into your foot.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s foot.", ch, NULL, NULL, TO_CANSEE);
          ch->feet_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their foot", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "hand" ) )
        {
          send_to_char( "&PYou embed a shard into your hand.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s hand.", ch, NULL, NULL, TO_CANSEE);
          ch->hand_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their hand", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "torso" ) )
        {
          send_to_char( "&PYou embed a shard into your torso.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s torso.", ch, NULL, NULL, TO_CANSEE);
          ch->torso_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their torso", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        if ( !str_cmp( arg, "shoulder" ) )
        {
          send_to_char( "&PYou embed a shard into your shoulder.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s shoulder.", ch, NULL, NULL, TO_CANSEE);
          ch->shoulder_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their shoulder", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }
        else
        {
        send_to_char( "&wThat is not a body part!\n\r", ch );
        return;
        }
    }
        send_to_char( "&wYou don't have any Shikon Shards!\n\r", ch );
        return;
}

(I'll probably redo this as a switch/case code)

And yes, I want to find a specific item on the player.
Amended on Wed 19 May 2004 04:06 AM by Zeno
USA #5
OK... here's your problem:

for (shard = ch->first_carrying; shard; shard = shard->next_content)
    {
      if (shard->pIndexData->vnum == 91)
      {
        if ( arg[0] == '\0' )
          {
             send_to_char( "&wEmbed the Shikon Shard where?\n\r(arm, leg, head, neck, foot, hand, torso, shoulder)\n\r ", ch$
             return;
          }
      }<---------

    if ( !str_cmp( arg, "arm" ) )
    {
          send_to_char( "&PYou embed a shard into your arm.\n\r", ch );
          act(AT_GREY,"&P$n embeds a shard into $s arm.", ch, NULL, NULL, TO_CANSEE);
          ch->arm_shards++;
          ch->hit -= ch->hit * 0.01;
          separate_obj ( shard );
          obj_from_char( shard );
          sprintf(buf, "%s embeded a shard into their arm", ch->name );
          to_channel( buf, CHANNEL_SHARDMONITOR, "ShardMonitor", LEVEL_IMMORTAL );
          extract_obj( shard );
          return;
        }


As you can see, your vnum check only checks the argument. When you then check for location, you are outside the vnum check and therefore are operating on whichever object it is.

Do you know how recursion works? It can be fairly complicated. For a simple example, you could check out get_obj_weight() (which is recursive if I remember correctly.) I'll write a recursive example to do this when I have a little more time... :)
USA #6
Fixed the first part, thanks.


int get_obj_weight( OBJ_DATA *obj )
{
    int weight;

    weight = obj->count * obj->weight;

    /* magic containers */
    if ( obj->item_type != ITEM_CONTAINER || !IS_OBJ_STAT(obj, ITEM_MAGIC) )
        for ( obj = obj->first_content; obj; obj = obj->next_content )
            weight += get_obj_weight(obj);

    return weight;
}

Although I've actually never done recursion, I can do it. But I don't want to count the number of objs, I want to show where the obj is, too.
USA #7
When you say where it is, you mean the tree path of containers followed to get there? Ungh... if only you were in C++. :)

Depending on why you need to know where it is, this might get a lot easier or a lot harder...
USA #8
Eh, all I really meant was where the obj is. Bah, I'll just explain what I want to do. I want to make a command that does this:
Quote:

"jstat zeno"
Zeno is carrying 4 objs
2 in their inventory
1 in small bag worn on hand
1 held


Heh, I do plan on creating a custom-codebase MUD in C++ sometime in the future.
USA #9
Ripped some stuff, looks like a workable model. I doubt its the most efficient way to do it, but hey, w/e
NOTE: THIS IS NOT TESTED

void do_jstat( CHAR_DATA *ch, char *argument )
{
  CHAR_DATA *victim;
  OBJECT_DATA *obj;
  OBJECT_DATA *container;
  char buf[MAX_STRING_LENGTH];
  int count, inventory, ammount;

   if ( !ch->desc )
   {
        send_to_char( "You have no descriptor\n\r", ch );
        return;
   }

   if ( ( victim = get_char_world( ch, argument ) ) == NULL )
   {
       send_to_char( "They aren't here.\n\r", ch );
       return;
   }

   for ( obj = victim->first_carrying; obj; obj = obj->next_content)
    count++;

   sprintf( buf, "%s is carrying %d object%s\n\r", victim->name, count, count == 1 ? "" : "s" );
   send_to_char( buf, ch );

  obj = NULL;
  inventory = 0;

  for ( obj = victim->first_carrying; obj; obj = obj->next_content )
    inventory++;

   sprintf( buf, "%d in their inventory\n\r", inventory );
   send_to_char( buf, ch );

  obj = NULL;
  ammount = 0;

 for ( obj = victim->first_carrying; obj; obj = obj->next_content )
   if ( obj->item_type == ITEM_CONTAINER )
   {
     ammount = 0;

     for ( container = obj->first_content; container; container = container->next_content ) 
      ammount++;

   sprintf( buf, "%d in %s\n\r", ammount, obj->short_descr  );
   send_to_char( buf, ch );
   }

 return;
}


Hoped that helpped.
~Odis
USA #10
No, that only goes one level deep, you need an arbitrary depth of recursion.

Let me explain the basic idea of what you're doing:

- you are traversing the tree of objects in a player's inventory
- at every level, you are counting how many objects there are
- you are printing a summary of results


The recursive function is, in pseudo-code:

int CountObjects(object * first-one)
{
   if ( !first-one )
       return 0;
   int count = 0;
   for every element object in list first-one
   {
      count++;
      for every child of object
         count += CountObjects(child);
   }
   return count;
}


That's pseudo-code off the top of my head. I think that should do it, but I'll add a little disclaimer about how I may be slightly off. :)

That count will count how many objects are on a given level. It acts on one sub-level at a time. You call it on person->first_carrying and it returns how many objects they have.

However things become more complicated if you want to print out the subresults as well. You need to pass around some more variables: a string to store the results (that you *must make sure* is large enough) and either the player's char_data* or the player's name. You just add those and that should do the trick.

Recusion is a very poweful but sometimes very complicated tool. :)
USA #11
Indeed. :)
USA #12
Hmm, a little more complicated then I expected. All I thought I needed to do was another loop. Well, I'll work some things over. Thanks.