Getting MOBprograms installed and bug-free

This is a collection of items on getting MOBprograms to work in Merc 2.2 and Envy 1.0. I put it together to be able to have something to respond with when people tell me that they pulled MOBprograms out of their server because of bugs. These notes are incomplete because I lost my Envy 1.0 MOBprogram implementation due to a disk crash (unrelated to MOBprograms... I was running Windows.)
in act(), add
*point = '\0';
one line before
buf[0] = UPPER(buf[0]);
Without this, stuff left in the player's buffer can fire mobprogs. This is particularly bad when a player enters the game and gets greet_proc over and over again.
The cause of the famous 'memory leak' I believe I have tracked down. The stock MOBprogram code loses memory when there are zones with MOBprograms on the mobiles and no players.

Under Envy 1.0, I put this code into aggr_update(), after the descriptor loop was done. This goes through all of the characters looking for MOBprograms. I believe the 'optimization' not to do the actions when no players were in the zone was the cause of people's 'memory leaks', the line '(wch->in_room->area->nplayer > 0)' in the if(). See, if "the kobold leaves north" every minute that is 25 bytes * 60min/hour or 1.5k per hour times say 10 mobiles times 100 mobprogrammed mobiles in zones without players is 1.5megs/hour of leaks. All of these mobprograms are going to fire, too, the first time a player enters the zone, which is probably not what was intended.

     
   // Now respond to MOBprograms--Slash
   for ( ch = char_list; ch != NULL; ch = wch_next )
      {
      wch_next = ch->next;

      /* MOBProgram ACT_PROG trigger */
      if ( IS_NPC( ch ) && ch->mpactnum > 0)
         // Merc 2.2 only freed this memory when a player was in the zone, I see
         // no reason to wait for that to happen--Slash
         //     && wch->in_room->area->nplayer > 0 )
         {
         // Examine everything the mobile heard since the last aggr_update(), and
         // respond to it
         MPROG_ACT_LIST * tmp_act, *tmp2_act;
         for ( tmp_act = ch->mpact; tmp_act != NULL; tmp_act = tmp_act->next )
            {
            mprog_wordlist_check( tmp_act->buf, ch, tmp_act->ch, tmp_act->obj, tmp_act->vo, 
               ACT_PROG );
            free_string( tmp_act->buf );
            }
     
         // Free the memory allocated to the 'act() memory'
         for ( tmp_act = ch->mpact; tmp_act != NULL; tmp_act = tmp2_act )
            {
            tmp2_act = tmp_act->next;
            free_mem( tmp_act, sizeof( MPROG_ACT_LIST ) );
            }
     
         // Zap the pointer to the memory
         ch->mpactnum = 0;
         ch->mpact = NULL;
         }
      }

This isn't an actual problem, it's just a piece of code I had to put back into Envy 1.0 from Merc 2.2 to get MOBprograms to work. In act(), there is some code like this:
        if ( ( to->deleted )
                 || ( !to->desc && IS_NPC( to ) )
                 || !IS_AWAKE( to ) )
                 continue;
the purpose of this is to not send act() messages to not send act() messages to deleted characters, sleepers, or mobiles with no one switched into them. But mobiles with ACT_PROG triggers still need to see the actions, so make the second line:
     || ( !to->desc && IS_NPC( to ) && !(to->pIndexData->progtypes & ACT_PROG ) )

The speech trigger can cause crashes due to recursion and stack fault if the mobiles aren't programmed well. For example, if a mobile always says 'Hello' to anyone who says anything to it is in the same room with a mobile that always says 'Hello yourself' when it hears hello then the game crashes. The solution is to add a static variable into mprog_speech_trigger. Here I have renamed the old mprog_speech_trigger() to old_speec_trigger and written a new one.
     
     void mprog_speech_trigger( char *txt, CHAR_DATA *mob )
     {
        static depth = 0;
        if (depth++ < 3)
                old_speech_trigger(txt, mob);
        depth--;
     }
(You can change the max depth (3) to anything you want. I believe 3 is what I used (this is one of the pieces of code I lost.) The idea is to allow a mobile to speak, another mobile to respond, and then the first to say the final thing, allow mini conversations.)
There is an error messages that seemed to make no sense. In the function do_mpkill(), there is a block of code:
     
     if ( ch->position == POS_FIGHTING ) {
        bug( "MpKill - Already fighting from vnum %d",
                ch->pIndexData->vnum );
        return;
     }
This is a bad thing if you use the 'mpkill' command in your scripts. For example, if the executioner is fighting someone and and an evil character says 'looking at?' using the stock Merc 2.2 MOBprogs then bug() will be called.

MOBprogram enhancement ideas

in mobile_update(), there is a check for the random trigger. Note that this doesn't fire when there are no players in the zone with the mobs, which keeps them idle. Eliminate this if you want your zones to look 'lived in'.
I wrote a function, check_arrival() which fires MOBprograms. I call it everywhere I think the mobs should see the player arrive, including after newbie and mortal char_to_room() calls in nanny(). I also call this in spell_summon(), spell_teleport(), in extract_char() when you arrive in purgatory and the healer, do_transfer(), do_goto(), do_mload() !!!, do_recall(). The function looks like this:
     
     void check_arrival(CHAR_DATA *ch, bool f)
     {
         if ( (f || !IS_AFFECTED(ch, AFF_SNEAK))
                        && ( IS_NPC(ch) || !IS_SET(ch->act, PLR_WIZINVIS) ) 
     )
                 {
                 mprog_entry_trigger(ch);
                 mprog_greet_trigger(ch);
                 }
     }
The boolean is used for controlling the SNEAK skill. If a player has sneak he avoids the mprog_entry and greet triggers walking, but not necessarily when being summoned or teleporting. It is up to the imp to call this with or without the ability to sneak past mobiles after calls to char_to_room().
One really cool thing is to have a 'mprog_pop_trigger' for when the mobile pops. This idea I got from TrollMUD although Legend has something like it. This allows the mobile to run any command when it pops, like 'sleep', 'lang dwarf' or anything you want the mobile to do/be/have but don't want to change file format for.
This page © DIKU, Merc Industries, and Envy (because it contains code derived from Merc which is derived from DIKU. This means that you cannot sell this page, even for the price of the paper. It also means that if you publish this page for free that you have to send mail to the address on the license agreement beforehand.
Merc's MOBprogram documentation, provided by Voivod's builder page.
MUD info page