LOP/
LOP/area/
LOP/boards/
LOP/channels/
LOP/clans/
LOP/classes/
LOP/color/
LOP/councils/
LOP/deity/
LOP/races/
LOP/src/specials/
/*****************************************************************************
 * DikuMUD (C) 1990, 1991 by:                                                *
 *   Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen,   *
 *   and Katja Nyboe.                                                        *
 *---------------------------------------------------------------------------*
 * MERC 2.1 (C) 1992, 1993 by:                                               *
 *   Michael Chastain, Michael Quan, and Mitchell Tse.                       *
 *---------------------------------------------------------------------------*
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider.                    *
 *   Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
 *         gorog, Grishnakh, Nivek, Tricops, and Fireblade.                  *
 *---------------------------------------------------------------------------*
 * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community.              *
 *                    Their contributions are greatly appreciated.           *
 *---------------------------------------------------------------------------*
 * LoP (C) 2006, 2007, 2008 by: the LoP team.                                *
 *---------------------------------------------------------------------------*
 *                                  Quest                                    *
 *****************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "h/mud.h"

void increase_gold( CHAR_DATA *ch, int amount );
void show_obj( CHAR_DATA *ch, OBJ_DATA *obj );

/* See if the character has killed the specified mobile vnum already */
int has_killed( CHAR_DATA *ch, int vnum )
{
   int track;

   if( !ch || !ch->pcdata )
      return 0;
   for( track = 0; track < MAX_KILLTRACK; track++ )
   {
      if( !ch->pcdata->killed[track].vnum || ch->pcdata->killed[track].vnum != vnum )
         continue;
      return ch->pcdata->killed[track].count;
   }
   return 0;
}

bool can_quest_room( CHAR_DATA *ch, ROOM_INDEX_DATA *room )
{
   if( !room->first_exit || !room->area )
      return false;
   if( xIS_SET( room->room_flags, ROOM_DEATH )
   || xIS_SET( room->room_flags, ROOM_SAFE )     || xIS_SET( room->room_flags, ROOM_SOLITARY )
   || xIS_SET( room->room_flags, ROOM_PET_SHOP ) || xIS_SET( room->room_flags, ROOM_DONATION )
   || xIS_SET( room->room_flags, ROOM_PRIVATE )  || xIS_SET( room->area->flags, AFLAG_NOQUEST )
   || ch->level < room->area->low_hard_range     || ch->level > room->area->hi_hard_range )
      return false;
   return true;
}

/* Can this mobile used for a quest? */
bool can_quest_mobile( CHAR_DATA *ch, CHAR_DATA *questman, CHAR_DATA *victim )
{
   int leveldiff;

   if( !ch || !victim )
      return false;
   if( !is_npc( victim ) || !can_see( ch, victim ) )
      return false;
   if( victim == ch || victim == questman )
      return false;
   if( !victim->in_room || !victim->in_room->first_exit )
      return false;
   leveldiff = ( victim->level - ch->level );
   if( leveldiff < -5 || leveldiff > 10 )
      return false;
   if( xIS_SET( victim->act, ACT_PACIFIST ) || xIS_SET( victim->act, ACT_PROTOTYPE )
   || is_safe( ch, victim, false ) || xIS_SET( victim->in_room->area->flags, AFLAG_NOQUEST ) )
      return false;
   if( victim->pIndexData->pShop || victim->pIndexData->rShop )
      return false;
   if( !can_quest_room( ch, victim->in_room ) )
      return false;
   return true;
}

void reward_quest( CHAR_DATA *ch, CHAR_DATA *victim )
{
   char buf[MSL];
   int qpoints = 0, gold = 0, practices = 0;

   if( !ch || !victim )
      return;
   qpoints = number_range( 3, 10 );
   ch->pcdata->quest_curr += qpoints;
   if( number_percent( ) < 25 )
   {
      gold = number_range( 100, 500 );
      increase_gold( ch, gold );
   }
   if( number_percent( ) < 10 )
   {
      practices = number_range( 1, 3 );
      ch->practice += practices;
   }
   if( gold > 0 && practices > 0 )
      snprintf( buf, sizeof( buf ), "0.%s As a reward I'm going to give you %d quest points, %d gold, and %d practices.", ch->name, qpoints, gold, practices );
   else if( gold > 0 )
      snprintf( buf, sizeof( buf ), "0.%s As a reward I'm going to give you %d quest points and %d gold.", ch->name, qpoints, gold );
   else if( practices > 0 )
      snprintf( buf, sizeof( buf ), "0.%s As a reward I'm going to give you %d quest points and %d practices.", ch->name, qpoints, practices );
   else
      snprintf( buf, sizeof( buf ), "0.%s As a reward I'm going to give you %d quest points", ch->name, qpoints );
   do_tell( victim, buf );
}

void complete_quest( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj )
{
   char buf[MSL];

   if( !ch )
      return;
   separate_obj( obj );
   ch->questgiver = 0;
   ch->questvnum = 0;
   ch->questcountdown = 20;
   ch->questtype = 0;
   xREMOVE_BIT( ch->act, PLR_QUESTOR );
   if( victim )
   {
      if( obj )
      {
         obj_from_char( obj );
         obj_to_char( obj, victim );
         snprintf( buf, sizeof( buf ), "0.%s Thank you for bringing me %s.", ch->name, obj->short_descr );
         do_tell( victim, buf );
         extract_obj( obj );
      }
      else
      {
         snprintf( buf, sizeof( buf ), "0.%s Thank you for taking care of that problem for me.", ch->name );
         do_tell( victim, buf );
      }
      reward_quest( ch, victim );
   }
   save_char_obj( ch );
}

void assign_quest( CHAR_DATA *ch, CHAR_DATA *questman )
{
   char buf[MSL];
   CHAR_DATA *victim = NULL;
   ROOM_INDEX_DATA *qroom = NULL;
   OBJ_DATA *obj, *iobj = NULL;

   if( !ch || is_npc( ch ) )
      return;

   if( ch->questcountdown > 0 )
   {
      if( xIS_SET( ch->act, PLR_QUESTOR ) )
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you are already on a quest.", ch->name );
      else
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you aren't able to quest again yet.", ch->name );
      do_tell( questman, buf );
      return;
   }

   /* Lets toss through the list of objects and see if we can find one to have them quest for */
   for( obj = first_object; obj; obj = obj->next )
   {
      iobj = NULL;
      victim = NULL;
      qroom = NULL;

      if( number_percent( ) > 20 )
         continue;

      if( !can_see_obj( ch, obj ) || can_wear( obj, ITEM_NO_TAKE ) )
         continue;

      /* Should we kill someone for an object they have? */
      if( ( victim = obj->carried_by ) )
      {
         if( !can_quest_mobile( ch, questman, victim ) )
            continue;
         else
            break;
      }
      /* Should we look for the object in a room? */
      else if( ( qroom = obj->in_room ) )
      {
         if( !can_quest_room( ch, qroom ) )
            continue;
         else
            break;
      }
      else if( ( iobj = obj->in_obj ) )
      {
         bool scontinue = false;

         while( iobj->in_obj )
         {
            if( !can_see_obj( ch, iobj ) )
               scontinue = true;
            iobj = iobj->in_obj;
         }
         if( scontinue )
            continue;
         if( ( victim = iobj->carried_by ) )
         {
            if( !can_quest_mobile( ch, questman, victim ) )
               continue;
            else
               break;
         }
         else if( ( qroom = iobj->in_room ) )
         {
            if( !can_quest_room( ch, qroom ) )
               continue;
            else
               break;
         }
      }
      else /* object not in a room, carried by someone or in an object */
         continue;
   }

   /* Maybe we can find a mobile to let them kill */
   if( !obj )
   {
      for( victim = first_char; victim; victim = victim->next )
      {
         if( number_percent( ) > 20 )
            continue;
         if( has_killed( ch, victim->pIndexData->vnum ) > 0 )
            continue;
         if( !can_quest_mobile( ch, questman, victim ) )
            continue;
         else
            break;
      }
   }

   if( !obj && !victim )
   {
      snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but I don't need anything at this time.", ch->name );
      do_tell( questman, buf );
      snprintf( buf, sizeof( buf ), "0.%s Come back later.", ch->name );
      do_tell( questman, buf );
      ch->questcountdown = 5;
      return;
   }

   if( obj )
   {
      snprintf( buf, sizeof( buf ), "0.%s I'm looking for %s.", ch->name, obj->short_descr );
      do_tell( questman, buf );
      if( qroom )
      {
         if( !qroom->area )
            snprintf( buf, sizeof( buf ), "0.%s Look for it at %s.", ch->name, qroom->name );
         else
            snprintf( buf, sizeof( buf ), "0.%s Look for it at %s in %s.", ch->name, qroom->name, qroom->area->name );
         do_tell( questman, buf );
      }
      else if( victim )
      {
         if( !victim->in_room || !victim->in_room->area )
            snprintf( buf, sizeof( buf ), "0.%s Look for it on %s.", ch->name, PERS( victim, ch ) );
         else
            snprintf( buf, sizeof( buf ), "0.%s Look for it on %s in %s.", ch->name, PERS( victim, ch ),
               victim->in_room->area->name );
         do_tell( questman, buf );
      }
      else if( iobj )
      {
         if( ( victim = iobj->carried_by ) )
         {
            if( victim->in_room && victim->in_room->area )
               snprintf( buf, sizeof( buf ), "0.%s Look for it in %s on %s in %s.", ch->name, iobj->short_descr,
                  PERS( victim, ch ), victim->in_room->area->name );
            else
               snprintf( buf, sizeof( buf ), "0.%s Look for it in %s on %s.", ch->name, iobj->short_descr,
                  PERS( victim, ch ) );
         }
         else if( ( qroom = iobj->in_room ) )
         {
            if( qroom->area )
               snprintf( buf, sizeof( buf ), "0.%s Look for it in %s at %s in %s.", ch->name, iobj->short_descr, qroom->name, qroom->area->name );
            else
               snprintf( buf, sizeof( buf ), "0.%s Look for it in %s at %s.", ch->name, iobj->short_descr, qroom->name );
         }
         else
            snprintf( buf, sizeof( buf ), "0.%s Look for it in %s.", ch->name, iobj->short_descr );
         do_tell( questman, buf );
      }
      ch->questcountdown = number_range( 10, 20 );
      ch->questvnum = obj->pIndexData->vnum;
      ch->questtype = 1; /* Object */
      snprintf( buf, sizeof( buf ), "0.%s You have %d minutes to bring me it.", ch->name, ch->questcountdown );
   }
   else /* Mobile quest here */
   {
      ch->questcountdown = number_range( 10, 20 );
      ch->questvnum = victim->pIndexData->vnum;
      ch->questtype = 2; /* Mobile */
      snprintf( buf, sizeof( buf ), "0.%s You have %d minutes to kill %s.", ch->name, ch->questcountdown, PERS( ch, victim ) );
   }
   xSET_BIT( ch->act, PLR_QUESTOR );
   ch->questgiver = questman->pIndexData->vnum;
   do_tell( questman, buf );
   save_char_obj( ch );
}

CHAR_DATA *find_questgiver( CHAR_DATA *ch )
{
   CHAR_DATA *questgiver = NULL;

   for( questgiver = ch->in_room->first_person; questgiver; questgiver = questgiver->next_in_room )
   {
      if( is_npc( questgiver ) && xIS_SET( questgiver->act, ACT_QUESTGIVER ) )
         break;
   }
   return questgiver;
}

CMDF( do_aquest )
{
   char buf[MSL];
   CHAR_DATA *questgiver;
   MOB_INDEX_DATA *questmob;
   OBJ_DATA *obj;

   if( !ch || is_npc( ch ) )
      return;
   if( !argument || argument[0] == '\0' )
   {
      if( ch->questcountdown > 0 )
      {
         if( xIS_SET( ch->act, PLR_QUESTOR ) )
         {
            OBJ_INDEX_DATA *oindex;

            if( ch->questtype == 1 )
            {
               if( !( oindex = get_obj_index( ch->questvnum ) ) )
               {
                  ch->questgiver = 0;
                  ch->questvnum = 0;
                  ch->questcountdown = 0;
                  ch->questtype = 0;
                  xREMOVE_BIT( ch->act, PLR_QUESTOR );
                  send_to_char( "The object you were questing for no longer exist.\r\n", ch );
                  send_to_char( "Quest has been removed and you may quest again.\r\n", ch );
                  save_char_obj( ch );
                  return;
               }
               ch_printf( ch, "You are currently on a quest to bring back %s.\r\n", oindex->short_descr );
            }
            else if( ch->questtype == 2 )
            {
               if( !( questmob = get_mob_index( ch->questvnum ) ) )
               {
                  ch->questgiver = 0;
                  ch->questvnum = 0;
                  ch->questcountdown = 0;
                  ch->questtype = 0;
                  xREMOVE_BIT( ch->act, PLR_QUESTOR );
                  send_to_char( "The mobile you were questing for no longer exist.\r\n", ch );
                  send_to_char( "Quest has been removed and you may quest again.\r\n", ch );
                  save_char_obj( ch );
                  return;
               }
               ch_printf( ch, "You are currently on a quest to kill %s.\r\n", questmob->short_descr );
            }
            ch_printf( ch, "You have %d minute%s left to complete the quest.\r\n", ch->questcountdown,
               ch->questcountdown == 1 ? "" : "s" );
         }
         else
            ch_printf( ch, "You have %d minute%s till you can quest again.\r\n", ch->questcountdown,
               ch->questcountdown == 1 ? "" : "s" );
      }
      else
         send_to_char( "You aren't currently on a quest.\r\n", ch );
      return;
   }
   if( !( questgiver = find_questgiver( ch ) ) )
   {
      send_to_char( "You aren't at a questgiver.\r\n", ch );
      return;
   }
   if( !str_cmp( argument, "request" ) )
   {
      assign_quest( ch, questgiver );
      return;
   }
   if( !str_cmp( argument, "complete" ) )
   {
      if( !xIS_SET( ch->act, PLR_QUESTOR ) )
      {
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you aren't on a quest.", ch->name );
         do_tell( questgiver, buf );
         return;
      }
      else if( questgiver->pIndexData->vnum != ch->questgiver )
      {
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but I never sent you on a quest.", ch->name );
         do_tell( questgiver, buf );
         return;
      }

      if( ch->questtype == 1 )
      {
         for( obj = ch->first_carrying; obj; obj = obj->next_content )
         {
            separate_obj( obj );
            if( obj->wear_loc != WEAR_NONE )
               continue;
            if( obj->pIndexData->vnum == ch->questvnum )
            {
               complete_quest( ch, questgiver, obj );
               return;
            }
         }
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you don't seem to have the item im wanting.", ch->name );
         do_tell( questgiver, buf );
      }
      else if( ch->questtype == 2 )
      {
         if( has_killed( ch, ch->questvnum ) > 0 )
         {
            complete_quest( ch, questgiver, NULL );
            return;
         }
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you haven't killed the one I wanted yet.", ch->name );
         do_tell( questgiver, buf );
      }
      snprintf( buf, sizeof( buf ), "0.%s You have %d minute%s left to complete the quest.",
         ch->name, ch->questcountdown, ch->questcountdown == 1 ? "" : "s" );
      do_tell( questgiver, buf );
      return;
   }
   if( !str_cmp( argument, "cancel" ) )
   {
      if( !xIS_SET( ch->act, PLR_QUESTOR ) )
      {
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but you aren't on a quest.", ch->name );
         do_tell( questgiver, buf );
         return;
      }
      else if( questgiver->pIndexData->vnum != ch->questgiver )
      {
         snprintf( buf, sizeof( buf ), "0.%s I'm sorry, but I never sent you on a quest.", ch->name );
         do_tell( questgiver, buf );
         return;
      }
      ch->questgiver = 0;
      ch->questvnum = 0;
      ch->questcountdown = 20;
      ch->questtype = 0;
      xREMOVE_BIT( ch->act, PLR_QUESTOR );
      snprintf( buf, sizeof( buf ), "0.%s I'm sorry you aren't going to finish the quest.", ch->name );
      do_tell( questgiver, buf );
      snprintf( buf, sizeof( buf ), "0.%s Come back later and try another quest.", ch->name );
      do_tell( questgiver, buf );
      save_char_obj( ch );
      return;
   }
   send_to_char( "Usage: aquest [request/cancel/complete]\r\n", ch );
}

void quest_update( void )
{
   static int quest_update_time;
   CHAR_DATA *ch;
   MOB_INDEX_DATA *victim;
   OBJ_INDEX_DATA *oindex;

   if( --quest_update_time > 0 )
      return;

   /* Should be around 1 minute per update */
   quest_update_time = ( 60 * PULSE_PER_SECOND );

   for( ch = first_char; ch; ch = ch->next )
   {
      if( is_npc( ch ) || ch->questcountdown == 0 )
         continue;

      if( ch->questtype == 1 && ch->questvnum != 0 && !( oindex = get_obj_index( ch->questvnum ) ) )
      {
         ch->questgiver = 0;
         ch->questvnum = 0;
         ch->questcountdown = 0;
         ch->questtype = 0;
         xREMOVE_BIT( ch->act, PLR_QUESTOR );
         send_to_char( "The object you were questing for no longer exist.\r\n", ch );
         send_to_char( "Quest has been removed and you may quest again.\r\n", ch );
         save_char_obj( ch );
         return;
      }
      else if( ch->questtype == 2 && ch->questvnum != 0 && !( victim = get_mob_index( ch->questvnum ) ) )
      {
         ch->questgiver = 0;
         ch->questvnum = 0;
         ch->questcountdown = 0;
         ch->questtype = 0;
         xREMOVE_BIT( ch->act, PLR_QUESTOR );
         send_to_char( "The mob you were questing for no longer exist.\r\n", ch );
         send_to_char( "Quest has been removed and you may quest again.\r\n", ch );
         save_char_obj( ch );
         return;
      }
      if( --ch->questcountdown == 0 )
      {
         if( xIS_SET( ch->act, PLR_QUESTOR ) )
         {
            ch->questcountdown = 20;
            ch_printf( ch, "You have ran out of time for the quest!\r\nYou can quest again in %d minutes.\r\n", ch->questcountdown );
            xREMOVE_BIT( ch->act, PLR_QUESTOR );
            ch->questgiver = 0;
            ch->questvnum = 0;
            ch->questtype = 0;
            save_char_obj( ch );
         }
         else
            send_to_char( "You may now quest again.\r\n", ch );
      }
      else if( ch->questcountdown < 6 && xIS_SET( ch->act, PLR_QUESTOR ) )
         ch_printf( ch, "Better hurry! You only have %d minute%s left to complete the quest.\r\n", ch->questcountdown,
            ch->questcountdown == 1 ? "" : "s" );
   }
}

#define REWARD_FILE SYSTEM_DIR "rewards.dat"
typedef struct reward_data REWARD_DATA;
struct reward_data
{
   REWARD_DATA *next, *prev;
   int vnum;
   int qpcost;
};
REWARD_DATA *first_reward, *last_reward;

void save_rewards( void )
{
   REWARD_DATA *reward;
   FILE *fp;

   if( !first_reward )
   {
      remove_file( REWARD_FILE );
      return;
   }
   if( !( fp = fopen( REWARD_FILE, "w" ) ) )
   {
      bug( "%s: Can't open %s for writing.", __FUNCTION__, REWARD_FILE );
      perror( REWARD_FILE );
      return;
   }
   for( reward = first_reward; reward; reward = reward->next )
      fprintf( fp, "Reward  %5d %5d\n", reward->vnum, reward->qpcost );
   fprintf( fp, "%s", "End\n" );
   fclose( fp );
   fp = NULL;
}

void free_reward( REWARD_DATA *reward )
{
   if( !reward )
      return;
   UNLINK( reward, first_reward, last_reward, next, prev );
   DISPOSE( reward );
}

void free_rewards( void )
{
   while( last_reward )
      free_reward( last_reward );
}

void add_reward( int vnum, int qpcost )
{
   REWARD_DATA *reward;

   CREATE( reward, REWARD_DATA, 1 );
   reward->vnum = vnum;
   reward->qpcost = qpcost;
   LINK( reward, first_reward, last_reward, next, prev );
}

void load_rewards( void )
{
   FILE *fp;

   first_reward = last_reward = NULL;
   if( !( fp = fopen( REWARD_FILE, "r" ) ) )
      return;
   for( ;; )
   {
      char *word;

      if( feof( fp ) )
         break;
      word = fread_word( fp );
      if( word[0] == EOF )
         break;
      if( !str_cmp( word, "Reward" ) )
      {
         int vnum = fread_number( fp );
         int qpcost = fread_number( fp );

         if( get_obj_index( vnum ) )
            add_reward( vnum, qpcost );
         continue;
      }
      else if( !str_cmp( word, "End" ) )
         break;
      else
      {
         bug( "%s: bad section (%s).", __FUNCTION__, word );
         fread_to_eol( fp );
         continue;
      }
   }
   fclose( fp );
   fp = NULL;
}

REWARD_DATA *find_reward( int vnum )
{
   REWARD_DATA *reward;

   for( reward = first_reward; reward; reward = reward->next )
      if( reward->vnum == vnum )
         return reward;
   return NULL;
}

CMDF( do_showrewards )
{
   REWARD_DATA *reward;
   int cnt = 0, col = 0;

   send_to_char( "-----------------------------------------------------------------\r\n", ch );
   ch_printf( ch, "| %6s %6s | %6s %6s | %6s %6s | %6s %6s |\r\n", "Vnum", "QPCost", "Vnum", "QPCost",
      "Vnum", "QPCost", "Vnum", "QPCost" );
   send_to_char( "-----------------------------------------------------------------\r\n", ch );
   for( reward = first_reward; reward; reward = reward->next )
   {
      cnt++;
      ch_printf( ch, "  %6d %6d ", reward->vnum, reward->qpcost );
      if( ++col == 4 )
      {
         col = 0;
         send_to_char( "\r\n", ch );
      }
   }
   if( col != 0 )
      send_to_char( "\r\n", ch );
   ch_printf( ch, "There %s currently %d reward%s.\r\n", cnt == 1 ? "is" : "are", cnt, cnt == 1 ? "" : "s" );
}

CMDF( do_reward )
{
   REWARD_DATA *reward;
   OBJ_INDEX_DATA *oindex;
   OBJ_DATA *obj;
   CHAR_DATA *questgiver = NULL;
   char arg[MSL];
   int cnt = 0, value = 0;

   if( !( questgiver = find_questgiver( ch ) ) )
   {
      send_to_char( "You aren't at a questgiver.\r\n", ch );
      return;
   }

   if( !argument || argument[0] == '\0' )
   {
      for( reward = first_reward; reward; reward = reward->next )
      {
         if( !( oindex = get_obj_index( reward->vnum ) ) || !oindex->short_descr )
            continue;
         ch_printf( ch, "%3d> %6d - %s\r\n", ++cnt, reward->qpcost, oindex->short_descr );
      }
      if( !cnt )
         send_to_char( "There are currently no rewards.\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg );
   if( ( value = atoi( arg ) ) <= 0 )
   {
      send_to_char( "Usage: reward <#>.\r\n", ch );
      return;
   }
   for( reward = first_reward; reward; reward = reward->next )
   {
       if( !( oindex = get_obj_index( reward->vnum ) ) || !oindex->short_descr )
          continue;
       if( ++cnt == value )
          break;
   }
   if( !reward )
   {
      send_to_char( "No such reward.\r\n", ch );
      return;
   }
   if( str_cmp( argument, "buy" ) )
   {
      if( !( obj = create_object( get_obj_index( reward->vnum ), 0 ) ) )
      {
         send_to_char( "There was a problem creating the object.\r\n", ch );
         return;
      }
      ch_printf( ch, "%3d> %6d - %s", value, reward->qpcost, obj->short_descr );
      show_obj( ch, obj );
      send_to_char( "Use 'reward <#> buy' if you wish to buy this reward.\r\n", ch );
      extract_obj( obj );
      return;
   }
   if( reward->qpcost > ch->pcdata->quest_curr )
   {
      send_to_char( "You don't have enough quest points to get that reward yet.\r\n", ch );
      return;
   }
   if( !( obj = create_object( get_obj_index( reward->vnum ), 0 ) ) )
   {
      send_to_char( "There was a problem creating the object.\r\n", ch );
      return;
   }
   if( !( obj = obj_to_char( obj, ch ) ) )
   {
      send_to_char( "There was a problem in giving you the object.\r\n", ch );
      return;
   }
   ch->pcdata->quest_curr -= reward->qpcost;
   ch_printf( ch, "You have traded %d quest points for reward #%d.\r\n", reward->qpcost, value );
   save_char_obj( ch );
}

CMDF( do_setreward )
{
   char arg[MIL], arg2[MIL];
   REWARD_DATA *reward;
   int vnum = 0, value = 0;

   argument = one_argument( argument, arg );
   if( !arg || arg[0] == '\0' )
   {
      send_to_char( "Usage: setreward create <vnum> <qpcost>\r\n", ch );
      send_to_char( "Usage: setreward delete <vnum>\r\n", ch );
      send_to_char( "Usage: setreward <vnum> vnum/qpcost <value>\r\n", ch );
      return;
   }
   argument = one_argument( argument, arg2 );
   if( !arg2 || arg2[0] == '\0' )
   {
      do_setreward( ch, "" );
      return;
   }
   if( !str_cmp( arg, "delete" ) )
   {
      vnum = atoi( arg2 );
      if( !( reward = find_reward( vnum ) ) )
      {
         send_to_char( "There is no such reward using that vnum.\r\n", ch );
         return;
      }
      free_reward( reward );
      save_rewards( );
      send_to_char( "The reward has been deleted.\r\n", ch );
      return;
   }
   if( !str_cmp( arg, "create" ) )
   {
      vnum = atoi( arg2 );
      if( !get_obj_index( vnum ) )
      {
         send_to_char( "No object is using that vnum.\r\n", ch );
         return;
      }
      if( ( reward = find_reward( vnum ) ) )
      {
         send_to_char( "There is already a reward using that vnum.\r\n", ch );
         return;
      }
      if( ( value = atoi( argument ) ) <= 0 )
      {
         send_to_char( "Usage: setreward create <vnum> <qpcost>\r\n", ch );
         return;
      }
      add_reward( vnum, value );
      save_rewards( );
      send_to_char( "The reward has been added.\r\n", ch );
      return;
   }
   if( !( reward = find_reward( atoi( arg ) ) ) )
   {
      send_to_char( "There is no reward using that vnum.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "vnum" ) )
   {
      if( ( vnum = atoi( argument ) ) <= 0 )
      {
         send_to_char( "Usage: setreward <vnum> vnum <new vnum>.\r\n", ch );
         return;
      }
      if( !get_obj_index( vnum ) )
      {
         send_to_char( "No object is using that vnum.\r\n", ch );
         return;
      }
      reward->vnum = vnum;
      save_rewards( );
      send_to_char( "That reward's vnum has been changed.\r\n", ch );
      return;
   }
   if( !str_cmp( arg2, "qpcost" ) )
   {
      if( ( value = atoi( argument ) ) <= 0 )
      {
         send_to_char( "Usage: setreward <vnum> qpcost <qpcost>.\r\n", ch );
         return;
      }
      reward->qpcost = value;
      save_rewards( );
      send_to_char( "That reward's qpcost has been changed.\r\n", ch );
      return;
   }
   do_setreward( ch, "" );
}

CMDF( do_useglory )
{
   char arg1[MSL];
   OBJ_DATA *obj;
   AFFECT_DATA *paf;
   int value;

   argument = one_argument( argument, arg1 );
   if( !arg1 || arg1[0] == '\0' )
   {
      send_to_char( "What would you like to use glory on and for?\r\n", ch );
      return;
   }
   if( !( obj = get_obj_carry( ch, arg1 ) ) )
   {
      send_to_char( "You do not have that item.\r\n", ch );
      return;
   }

   argument = one_argument( argument, arg1 );
   separate_obj( obj );

   if( is_obj_stat( obj, ITEM_PROTOTYPE ) )
   {
      send_to_char( "You can't use glory on this object.\r\n", ch );
      return;
   }

   if( obj->wear_loc != WEAR_NONE )
   {
      send_to_char( "You must remove it first.\r\n", ch );
      return;
   }

   if( !str_cmp( arg1, "weight" ) )
   {
      if( obj->weight <= 1 )
      {
         send_to_char( "No point in reduceing the weight of that object.\r\n", ch );
         return;
      }
      if( ch->pcdata->quest_curr < 100 )
      {
         send_to_char( "You don't have the 100 glory required.\r\n", ch );
         return;
      }
      obj->weight = 1;
      ch->pcdata->quest_curr -= 100;
      save_char_obj( ch );
      send_to_char( "The object's weight has been reduced to 1.\r\n", ch );
      return;
   }
   if( !str_cmp( arg1, "glow" ) )
   {
      if( ch->pcdata->quest_curr < 5 )
      {
         send_to_char( "You don't have the 5 glory required.\r\n", ch );
         return;
      }
      xTOGGLE_BIT( obj->extra_flags, ITEM_GLOW );
      ch->pcdata->quest_curr -= 5;
      save_char_obj( ch );
      if( is_obj_stat( obj, ITEM_GLOW ) )
         send_to_char( "The item now glows.\r\n", ch );
      else
         send_to_char( "The item stops glowing.\r\n", ch );
      return;
   }
   if( !str_cmp( arg1, "noscrap" ) )
   {
      if( ch->pcdata->quest_curr < 500 )
      {
         send_to_char( "You don't have the 500 glory required.\r\n", ch );
         return;
      }
      if( is_obj_stat( obj, ITEM_NOSCRAP ) )
      {
         send_to_char( "This object already resist scrapping.\r\n", ch );
         return;
      }
      xSET_BIT( obj->extra_flags, ITEM_NOSCRAP );
      ch->pcdata->quest_curr -= 500;
      save_char_obj( ch );
      send_to_char( "The object will now resist scrapping.\r\n", ch );
      return;
   }
   if( !str_cmp( arg1, "resist" ) )
   {
      if( ch->pcdata->quest_curr < 500 )
      {
         send_to_char( "You don't have the 500 glory required.\r\n", ch );
         return;
      }
      value = get_flag( argument, ris_flags, RIS_MAX );
      if( value < 0 || value >= RIS_MAX )
      {
         ch_printf( ch, "Unknown resistant: %s\r\n", argument );
         return;
      }
      for( paf = obj->first_affect; paf; paf = paf->next )
      {
         if( paf->location == APPLY_RESISTANT && paf->modifier == value )
         {
            send_to_char( "The object already has an affect to help you resist that.\r\n", ch );
            return;
         }
      }
      paf = NULL;
      CREATE( paf, AFFECT_DATA, 1 );
      paf->type = -1;
      paf->duration = -1;
      paf->location = APPLY_RESISTANT;
      paf->modifier = value;
      xCLEAR_BITS( paf->bitvector );
      paf->next = NULL;
      LINK( paf, obj->first_affect, obj->last_affect, next, prev );
      ch->pcdata->quest_curr -= 500;
      save_char_obj( ch );
      send_to_char( "The object will now help you resist that.\r\n", ch );
      return;
   }
   if( !str_cmp( arg1, "affect" ) )
   {
      if( ch->pcdata->quest_curr < 400 )
      {
         send_to_char( "You don't have the 400 glory required.\r\n", ch );
         return;
      }
      value = get_flag( argument, a_flags, AFF_MAX );
      if( value <= 0 || value >= AFF_MAX )
      {
         ch_printf( ch, "Unknown affect: %s\r\n", argument );
         return;
      }
      /* Only allow these here */
      if( value != AFF_INVISIBLE && value != AFF_DETECT_EVIL && value != AFF_DETECT_INVIS
      && value != AFF_DETECT_MAGIC && value != AFF_DETECT_HIDDEN && value != AFF_INFRARED
      && value != AFF_SNEAK && value != AFF_HIDE && value != AFF_FLYING && value != AFF_PASS_DOOR
      && value != AFF_FLOATING && value != AFF_DETECTTRAPS && value != AFF_SCRYING
      && value != AFF_AQUA_BREATH && value != AFF_DETECT_SNEAK )
      {
         ch_printf( ch, "Unknown affect: %s\r\n", argument );
         return;
      }
      for( paf = obj->first_affect; paf; paf = paf->next )
      {
         if( paf->location == APPLY_EXT_AFFECT && paf->modifier == value )
         {
            send_to_char( "The object already has that affect.\r\n", ch );
            return;
         }
      }
      paf = NULL;
      CREATE( paf, AFFECT_DATA, 1 );
      paf->type = -1;
      paf->duration = -1;
      paf->location = APPLY_EXT_AFFECT;
      paf->modifier = value;
      xCLEAR_BITS( paf->bitvector );
      paf->next = NULL;
      LINK( paf, obj->first_affect, obj->last_affect, next, prev );
      ch->pcdata->quest_curr -= 400;
      save_char_obj( ch );
      send_to_char( "The object now has that affect.\r\n", ch );
      return;
   }
   if( !str_cmp( arg1, "armor" ) )
   {
      if( ch->pcdata->quest_curr < 50 )
      {
         send_to_char( "You don't have the 50 glory required.\r\n", ch );
         return;
      }
      for( paf = obj->first_affect; paf; paf = paf->next )
      {
         if( paf->location == APPLY_ARMOR )
            break;
      }
      if( !paf )
      {
         paf = NULL;
         CREATE( paf, AFFECT_DATA, 1 );
         paf->type = -1;
         paf->duration = -1;
         paf->location = APPLY_ARMOR;
         paf->modifier = 1;
         xCLEAR_BITS( paf->bitvector );
         paf->next = NULL;
         LINK( paf, obj->first_affect, obj->last_affect, next, prev );
      }
      else
         paf->modifier += 1;
      ch->pcdata->quest_curr -= 50;
      save_char_obj( ch );
      send_to_char( "The object now affects your armor class more.\r\n", ch );
      return;
   }
}