Issues with mob index/snippet

Posted by Zeno on Mon 28 Aug 2006 11:37 PM — 30 posts, 90,375 views.

USA #0
This code:
     for (mcounter = 0; mcounter < 99999; mcounter ++)
       {
        mob_vnum = number_range(99, 6000);

        if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
        {
            level_diff = vsearch->level - ch->level;

                /* Level differences to search for. Moongate has 350
                   levels, so you will want to tweak these greater or
                   less than statements for yourself. - Vassago */


            if ( level_diff < 15
                && vsearch->pShop == NULL
                && vsearch->rShop == NULL
                && !xIS_SET(vsearch->act,ACT_PACIFIST)
                && !xIS_SET(vsearch->act,ACT_NOTARGET)
                && !xIS_SET(vsearch->act,ACT_PET)
                && !xIS_SET(vsearch->act,ACT_TRAIN)
                && !xIS_SET(vsearch->act,ACT_PRACTICE)
                && !xIS_SET(vsearch->act,ACT_PROTOTYPE)
                && !xIS_SET(vsearch->act,ACT_IMMORTAL)) break;
                else vsearch = NULL;
        }
    }

    if ( vsearch == NULL || ( victim = get_char_world( ch, vsearch->player_name ) ) == NULL || !IS_NPC(victim))
...


Once in a while, a pacifist mob will slip by somehow. It shouldn't, but it is. Any ideas what's wrong?

Debugging, I found this. The right mob index was selected, but in the get_char_world it selected the wrong mob due to similar mob name. "Panther Villager" was the mob index but it selected "Panther villager 2". Any ideas what I should do, to have it select the right one? Obviously getting by the mob name isn't gonna work.
Amended on Mon 28 Aug 2006 11:49 PM by Zeno
Australia Forum Administrator #1
According to the comments in get_char_world you can search by vnum. Why not use that?
USA #2
yeah, I had a similar problem using the same snippet.

Call the mob via vnum instead of by name. That should solve the problem :) I'm not near my MUD but I want to say it's get_char_index... something like that. If that's not it, I'll run to a machine that has SMAUG and repost with correct data :X
USA #3
heh, I post too slow :P. Anyway, I had an issue when I was calling via vnum. I dunno if stock is like this (too many mods) but get_char_world only allows you to search by vnum if the person requesting that data is a certain level or higher. Removing that little bit allowing all to search also screws it up pretty bad.
USA #4
get_char_world takes vnums? Hrm, it must have to be a string then right?

Tzaro, anything else you found in this snippet needing fixing? I hate to install snippets, but right now it's faster than coding in my own system instead of tweaking this snippet for what I need.
USA #5
First, I remember what I did... I made a new function that specifically called the mobs by vnum for that piece of code. It really wasn't that much so you could probably add it in that function anyway.

That was the only real issue I had with the code. The whole checking whether or not to assign a mob or an object is a little hairy though. Might want to find a better way to divide up which one it gives.

Also, I ended up having to add an entirely new flag... I just called it no_quest. Some mobs just shouldn't be chosen as a quest mob... some of our areas shouldn't be either (we have an area that only a mage can grant access to. We left it off limits to that snippet since it's impossible to get to unless you're good friends with a mage online, ect) You might want to consider doing the same.
USA #6
Well I found another issue.
    if ( ( room = find_location( ch, victim->name ) ) == NULL )


Same as above, has issues with mobs having similar names.

I would think you should just use victim->in_room instead.
Amended on Tue 29 Aug 2006 03:38 AM by Zeno
USA #7
Zeno, I used this same aquest snippet in my mud, and by the time we (I had help on it from Rogue, Remcon, and several others - it was a pretty frustrating snippet) got it working right (the way Dragona and I wanted it to work) it was almost completely rewritten.

I can show you what I ended up with, but as was already mentioned by another, I also ended up adding a new noquest area flag, mob flag, and several other changes to other parts of code. For example, I had to make all the travel spells (like astral, portal, etc) not work for anyone who was on a quest, and had to make it understand that dropping an object into a random room for a quest was fine, if the room was player accessible and not a death trap... and so on.

Anyway, by the time I was done with it, my quest code has bits and pieces all over the place throughout the rest of my code. ...suffice it to say, in this case, using a snippet may not be faster than writing your own. :(
USA #8
Actually I think we're just about done finishing it up for the initial system for now. We don't see any more problems right now, but if we continue to see more maybe we'll just ask to see your end result. Thanks.
USA #9
ah ha... I found a different snippet than the one I ended up using (and editing massively to have it work exactly how I wanted). Though the one I used didn't have too many issues other than those already listed.

I guess I'll just write a new snippet for the next batch of folks that want to use it... hmm, time for me to put up a new posting :)
USA #10
Just let me know, Zeno. In my case, we found even after we got it to "work" that it was still really badly buggy. *shrug*

Hopefully you'll have better luck with it than I did, it was the very bane of my existance for months... :(
USA #11
Does this make any sense? This code:
void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman)
{
    CHAR_DATA *victim;
    MOB_INDEX_DATA *vsearch;
    ROOM_INDEX_DATA *room;
    OBJ_DATA *questitem;
    char buf[MAX_STRING_LENGTH];
    long mcounter;
    int level_diff, mob_vnum;

    /*  Randomly selects a mob from the world mob list. If you don't
        want a mob to be selected, make sure it is immune to summon.
        Or, you could add a new mob flag called ACT_NOQUEST. The mob
        is selected for both mob and obj quests, even tho in the obj
        quest the mob is not used. This is done to assure the level
        of difficulty for the area isn't too great for the player. */

     for (mcounter = 0; mcounter < 99999; mcounter ++)
       {
        mob_vnum = number_range(99, 6000);

        if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
        {
            level_diff = vsearch->level - ch->level;

                /* Level differences to search for. Moongate has 350
                   levels, so you will want to tweak these greater or
                   less than statements for yourself. - Vassago */


            if ( level_diff < 15


Crashed:
#0  0x081ac1c9 in generate_quest (ch=0x96e2f20, questman=0x9456f38) at quest.c:596
596                 if ( level_diff < 15
(gdb) p level_diff
No symbol "level_diff" in current context.
(gdb)


How can there not be a level_diff? It was cleary defined.
Australia Forum Administrator #12
Did you change frames? (like, type "up" or "down", or something)?
USA #13
(gdb) f 0
#0  0x081ac1c9 in generate_quest (ch=0x96e2f20, questman=0x9456f38)
    at quest.c:596
596                 if ( level_diff < 15
(gdb) p level_diff
No symbol "level_diff" in current context.
Australia Forum Administrator #14
I strongly suspect in this case that you have corrupted the stack. For one thing, a statement like "if ( level_diff < 15" shouldn't fail under any circumstances, and for another, not finding the variable is suspicious.

Try doing "break generate_quest" and then stepping through the function.

Also try: 'info args' and 'info local'.

Since that is a local variable it should show up in 'info local'.
Amended on Sun 03 Sep 2006 05:05 AM by Nick Gammon
USA #15
Well it's worked fine every other time. This has been the only crash so far. Reproducing it might be hard.
Australia Forum Administrator #16
If you have the core file, which I suspect you have to be able to answer those questions, you can still do 'info local'.
USA #17
Oh right, I tried that already. Got something odd.

(gdb) f 0
#0  0x081ac1c9 in generate_quest (ch=0x96e2f20, questman=0x9456f38)
    at quest.c:596
596                 if ( level_diff < 15
(gdb) info locals
victim = Variable "victim" is not available.


I don't think victim has anything to do with that code.
Australia Forum Administrator #18
Yes, that sort of confirms the stack is corrupted. As your function randomly picks a MOB I suspect that one of them is causing it.

One approach is to change the random choice to a sequence number passed down as an argument (from 99 to 6000 judging by your code), and then make a small function that repeatedly calls it, noting somewhere what one it is up to. Then when it crashes you will see which mob causes it.

Then step through it with that mob chosen.

As described on my page for gdb debugging, you could even script a simple loop like that in gdb itself.
USA #19
Well I can find out what mob it is by printing vsearch->vnum, but how would that help? Do you think it would crash everytime with that mob?

[EDIT] Okay, I can reproduce it on the same mob. What does that mean? What's wrong with the mob?

Stepping through:
(gdb) next
588             if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
(gdb) p vsearch
$1 = (MOB_INDEX_DATA *) 0xa03b4c0
(gdb) p vsearch->vnum
$2 = 0
(gdb) p mob_vnum
No symbol "mob_vnum" in current context.
(gdb) list
583          for (mcounter = 0; mcounter < 99999; mcounter ++)
584            {
585             //mob_vnum = number_range(99, 6000);
586             mob_vnum = 2110;
587
588             if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
589             {
590                 level_diff = vsearch->level - ch->level;
591
592                     /* Level differences to search for. Moongate has 350


Er, mob_vnum has issues now?
Amended on Sun 03 Sep 2006 09:46 PM by Zeno
Australia Forum Administrator #20
Looks like vsearch is wrong, try stepping into the get_mob_index(mob_vnum) code with that vnum.
USA #21
What am I looking for when I step into the function?

Breakpoint 1, generate_quest (ch=0x9852dd0, questman=0x97d44c0) at quest.c:567
567     {
(gdb) list
562         send_to_char("Job decline - Declines your current job.\n\r",ch);
563         return;
564     }
565
566     void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman)
567     {
568         CHAR_DATA *victim;
569         MOB_INDEX_DATA *vsearch;
570         ROOM_INDEX_DATA *room;
571         OBJ_DATA *questitem;
(gdb) step
588             if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
(gdb) list
583          for (mcounter = 0; mcounter < 99999; mcounter ++)
584            {
585             //mob_vnum = number_range(99, 6000);
586             mob_vnum = 2110;
587
588             if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
589             {
590                 level_diff = vsearch->level - ch->level;
591
592                     /* Level differences to search for. Moongate has 350
(gdb) p mob_vnum
No symbol "mob_vnum" in current context.
(gdb) step
get_mob_index (vnum=2110) at db.c:3212
3212    {
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
(gdb) step
3218        for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
(gdb) step
3219              pMobIndex;
(gdb) info locals
pMobIndex = (MOB_INDEX_DATA *) 0x985d9b0
(gdb) step
3221            if ( pMobIndex->vnum == vnum )
(gdb) info locals
pMobIndex = (MOB_INDEX_DATA *) 0x985d9b0
(gdb) p pMobIndex->vnum
$1 = 2110
(gdb) step
3228    }
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
Amended on Sun 03 Sep 2006 10:14 PM by Zeno
Australia Forum Administrator #22
In my code I have this:


 if( pMobIndex->vnum == vnum )
         return pMobIndex;


I didn't see the "return pMobIndex;" in your stepping. Since the vnum was correct we should be back at line 589.
USA #23
This is what I have:
MOB_INDEX_DATA *get_mob_index( int vnum )
{
    MOB_INDEX_DATA *pMobIndex;

    if ( vnum < 0 )
      vnum = 0;

    for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
          pMobIndex;
          pMobIndex  = pMobIndex->next )
        if ( pMobIndex->vnum == vnum )
            return pMobIndex;

    if ( fBootDb )
        bug( "Get_mob_index: bad vnum %d.", vnum );

    return NULL;
}


I'll try stepping through again.
USA #24
Breakpoint 1, generate_quest (ch=0x9418570, questman=0x9398900) at quest.c:567
567     {
(gdb) list
562         send_to_char("Job decline - Declines your current job.\n\r",ch);
563         return;
564     }
565
566     void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman)
567     {
568         CHAR_DATA *victim;
569         MOB_INDEX_DATA *vsearch;
570         ROOM_INDEX_DATA *room;
571         OBJ_DATA *questitem;
(gdb) info locals
victim = Variable "victim" is not available.
(gdb) step
588             if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
(gdb) info locals
victim = Variable "victim" is not available.
(gdb) step
get_mob_index (vnum=2110) at db.c:3212
3212    {
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
(gdb) step
3218        for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
(gdb) list
3213        MOB_INDEX_DATA *pMobIndex;
3214
3215        if ( vnum < 0 )
3216          vnum = 0;
3217
3218        for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
3219              pMobIndex;
3220              pMobIndex  = pMobIndex->next )
3221            if ( pMobIndex->vnum == vnum )
3222                return pMobIndex;
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
(gdb) step
3219              pMobIndex;
(gdb) list
3214
3215        if ( vnum < 0 )
3216          vnum = 0;
3217
3218        for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
3219              pMobIndex;
3220              pMobIndex  = pMobIndex->next )
3221            if ( pMobIndex->vnum == vnum )
3222                return pMobIndex;
3223
(gdb) info locals
pMobIndex = (MOB_INDEX_DATA *) 0x94335c8
(gdb) step
3221            if ( pMobIndex->vnum == vnum )
(gdb) p vnum
$1 = 2110
(gdb) p pMobIndex->vnum
$2 = 2110
(gdb) step
3228    }
(gdb) list
3223
3224        if ( fBootDb )
3225            bug( "Get_mob_index: bad vnum %d.", vnum );
3226
3227        return NULL;
3228    }
3229
3230
3231
3232    /*
(gdb) p pMobIndex
Variable "pMobIndex" is not available.
(gdb) info locals
pMobIndex = Variable "pMobIndex" is not available.
(gdb) step
generate_quest (ch=0x9418570, questman=0x9398900) at quest.c:597
597                 if ( level_diff < 15
(gdb) info locals
victim = Variable "victim" is not available.
(gdb) list
592                     /* Level differences to search for. Moongate has 350
593                        levels, so you will want to tweak these greater or
594                        less than statements for yourself. - Vassago */
595
596
597                 if ( level_diff < 15
598                     && vsearch->pShop == NULL
599                     && vsearch->rShop == NULL
600                     && !str_cmp(get_area_by_m_vnum(vsearch->vnum)->era, ch->in_room->area->era)
601                     && !xIS_SET(vsearch->act,ACT_PACIFIST)
(gdb) p vsearch
$3 = (MOB_INDEX_DATA *) 0x94335c8
(gdb) p vsearch->level
$4 = 1
(gdb) p vsearch->vnum
$5 = 2110


vsearch looks fine to me.

It looks like it crashes on any prototype mob. Why? I have no idea. It doesn't even get to the proto ifcheck before it crashes.
Amended on Mon 04 Sep 2006 02:54 AM by Zeno
Australia Forum Administrator #25
All I can suggest is doing this:

p *vsearch


Then see if any values look odd.
USA #26
(gdb) p *vsearch
$1 = {next = 0x0, next_sort = 0x0, spec_fun = 0, pShop = 0x0, rShop = 0x0, mudprogs = 0x92fb018, progtypes = {bits = {128,
      0, 0, 0}}, player_name = 0x929a348 "Boy", short_descr = 0x92fb008 "A Boy",
  long_descr = 0x929a230 "A young boy is here dancing around\n\r", description = 0x8ea9a80 "", vnum = 2110, count = 1,
  killed = 0, sex = 1, level = 1, act = {bits = {1140850689, 0, 0, 0}}, affected_by = {bits = {4194304, 0, 0, 0}},
  alignment = 0, mobthac0 = 0, ac = 0, hitnodice = 0, hitsizedice = 0, hitplus = 0, damnodice = 0, damsizedice = 0,
  damplus = 0, numattacks = 0, gold = 0, exp = 0, xflags = 0, immune = 0, resistant = 0, susceptible = 0, attacks = {
    bits = {0, 0, 0, 0}}, defenses = {bits = {0, 0, 0, 0}}, speaks = 0, speaking = 0, position = 12, defposition = 12,
  height = 0, weight = 0, race = 0, class = 3, hitroll = 0, damroll = 0, perm_vig = 13, perm_int = 13, perm_wis = 13,
  perm_dex = 13, perm_end = 13, perm_cha = 13, perm_lck = 13, saving_poison_death = 0, saving_wand = 0,
  saving_para_petri = 0, saving_breath = 0, saving_spell_staff = 0, hp_from_gain = 0}


Looks okay to me, I think.
Amended on Mon 04 Sep 2006 05:27 AM by Zeno
Australia Forum Administrator #27
I'd like to see the whole generate_quest function. I can't help thinking something is overflowing somewhere in it.
USA #28
void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman)
{
    CHAR_DATA *victim;
    MOB_INDEX_DATA *vsearch;
    ROOM_INDEX_DATA *room;
    OBJ_DATA *questitem;
    char buf[MAX_STRING_LENGTH];
    long mcounter;
    int level_diff, mob_vnum;

    /*  Randomly selects a mob from the world mob list. If you don't
        want a mob to be selected, make sure it is immune to summon.
        Or, you could add a new mob flag called ACT_NOQUEST. The mob
        is selected for both mob and obj quests, even tho in the obj
        quest the mob is not used. This is done to assure the level
        of difficulty for the area isn't too great for the player. */

     for (mcounter = 0; mcounter < 99999; mcounter ++)
       {
        mob_vnum = number_range(99, 6000);

        if ( (vsearch = get_mob_index(mob_vnum) ) != NULL )
        {
            level_diff = vsearch->level - ch->level;

                /* Level differences to search for. Moongate has 350
                   levels, so you will want to tweak these greater or
                   less than statements for yourself. - Vassago */


            if ( level_diff < 15
                && vsearch->pShop == NULL
                && vsearch->rShop == NULL
                && !str_cmp(get_area_by_m_vnum(vsearch->vnum)->era, ch->in_room->area->era)
                && !xIS_SET(vsearch->act,ACT_PACIFIST)
                && !xIS_SET(vsearch->act,ACT_NOTARGET)
                && !xIS_SET(vsearch->act,ACT_PET)
                && !xIS_SET(vsearch->act,ACT_TRAIN)
                && !xIS_SET(vsearch->act,ACT_PRACTICE)
                && !xIS_SET(vsearch->act,ACT_PROTOTYPE)
                && !xIS_SET(vsearch->act,ACT_IMMORTAL)) break;
                else vsearch = NULL;
        }
    }

    if ( vsearch == NULL || ( victim = get_mob_by_vnum( vsearch->vnum )) == NULL || !IS_NPC(victim))
    {
        sprintf(buf, "%s Sorry, but I don't have any jobs for you right now.", ch->name);
        do_say_to_char(questman, buf);
        sprintf(buf, "%s Try again later.", ch->name);
        do_say_to_char(questman, buf);
        ch->nextquest = 5;
        ch->questmob = 0;
        ch->quest_mob = NULL;
        ch->quest_item = NULL;
        ch->questobj = 0;
        return;
    }

    if ( ( room = victim->in_room ) == NULL )
    {
        sprintf(buf, "%s Sorry, but I don't have any jobs for you right now.", ch->name);
        do_say_to_char(questman, buf);
        sprintf(buf, "%s Try again later.", ch->name);
        do_say_to_char(questman, buf);
        ch->nextquest = 5;
        ch->questmob = 0;
        ch->quest_mob = NULL;
        ch->quest_item = NULL;
        ch->questobj = 0;
        return;
    }

That's the loop and a little more. If you need the rest, let me know.
Australia Forum Administrator #29
I can't see the problem, but as you can reproduce it, it must be a case of using gdb to narrow down the block of code that leads up to the corrupted variables.