/*
   Quest Bits for Mobprogs by Igor van den Hoven.

   The Diku and Merc license apply. This code is compatible with smaug muds.
*/

/*
   The idea of this snippet is to move away from the traditional if value
   == (number between -2 and +2 billion) check.

   Given the average quest has around 10 steps you only need 4 bits of a
   32 bit integer to store it. If you have a large area and a quest value
   assigned for a player for that area you can add a total of eight 10 step
   quests stored in a 32 bit integer.

   Using quest[MAX_VNUM / 100] is an easy way to create a quest value for
   each area, and you can access it with: ch->pcdata->quest[mob->vnum / 100]
   with ch being the player and mob being the mob setting the quest value.

   In this code you define a bit range by giving the first bit, next
   giving the number of bits, followed by the value you want those bits
   to hold. 4 bits would give a value between 0 and 15, 8 bits a value
   between 0 and 255 (which should be enough for everyone).

   To set a quest value you'd use: mpmset $n quest 0 4 1. 0 would be the
   first bit, 4 would be the total number of bits, and 1 is the value to
   assign to them. To check if bit 1 to 4 has the value 1 you'd use:
   if quest (0,4,$n) == 1.

   When adding another quest you'd start out with: if quest (4,4,$n) == 0
   to see if the player has or hasn't started the quest assigned to bit
   5 to 8.

   Methods for saving and reading aren't included, this is pretty much
   a proof of concept.
*/


// In mud_prog.c add these two functions:

int get_quest_value(int quest, int fBit, int nBit)
{
   int cnt, value = 0;

   for (cnt = fBit ; cnt < fBit + nBit ; cnt++)
   {
      if (IS_SET(quest, 1 << cnt))
      {
          SET_BIT(value, 1 << (cnt - fBit));
      }
  }
  return value;
}

void set_quest_value(int *quest, int fBit, int nBit, int value)
{
   int cnt;
           
   for (cnt = fBit ; cnt < fBit + nBit ; cnt++)
   {
      if (IS_SET(value, 1 << (cnt - fBit)))
      {
          SET_BIT(*quest, 1 << cnt);
      }
      else
      {   
          REMOVE_BIT(*quest, 1 << cnt);
      }
   }   
}

// In mprog_do_ifcheck add:

   if( !str_cmp( chck, "quest" ) )
   {
      int fBit, nBit;
      char name[MAX_INPUT_LENGTH];

      if (sscanf(arg, "%d,%d,%s", &fBit, &nBit, name) != 3)
      {
         return 0; /* error */
      }

      if ( name[0] == '$' )
      {
         switch ( name[1] )
         {
            case 'i':
               chkchar = mob;
               break;        
            case 'n':
               chkchar = actor;
               break;          
            case 't':
               chkchar = ( CHAR_DATA * ) vo;
               break;                       
            case 'r':
               chkchar = rndm;
               break;         
            default:
               return 0; /* error */
         }
      }   

      if (chkchar)
      {
         if (IS_NPC(chkchar)
         {
            lhsvl = get_quest_value(chkchar->quest, fBit, nBit);
         }
         else
         {
            lhsvl = get_quest_value(chkchar->quest[mob->in_room->area->low_r_vnum / 100], fBit, nBit);
         }
         rhsvl = atoi(rval);                                 
         return mprog_veval(lhsvl, opr, rhsvl);
      }   
      else
      {
         return 0; /* error */
      }
   }   


// In mpxset.c add:

   if( !str_cmp( arg2, "quest" ) )
   {
      int fBit, nBit, value;
      
      if (sscanf(arg3,"%d %d %d", &fBit, &nBit, &value) != 3)
      {
         return;
      }
      if (IS_NPC(victim)
      {
         set_quest_value(&victim->quest, fBit, nBit, value);
      }
      else
      {
         set_quest_value(&victim->quest[ch->in_room->area->low_r_vnum / 100], fBit, nBit, value);
      }
      return;
   }

// In mud.h add to char_data:

   int quest;

// And to player_data;

   int quest[MAX_VNUM/100];