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.                                *
 *---------------------------------------------------------------------------*
 *                              Hint System                                  *
 *****************************************************************************/

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

int get_pc_race( char *type );
int get_pc_class( char *Class );

#define HINT_FILE SYSTEM_DIR "hints.dat"
typedef struct hint_data HINT_DATA;
struct hint_data
{
   HINT_DATA *next, *prev;
   char *hint;
   /* Restrictions below */
   int minlevel, maxlevel; /* Levels */
   char *rname;            /* Race name */
   char *cname;            /* Class name */
   char *aname;            /* Area name */
};

HINT_DATA *first_hint, *last_hint;

void save_hints( void )
{
   HINT_DATA *hint;
   FILE *fp;

   if( !first_hint )
   {
      remove_file( HINT_FILE );
      return;
   }
   if( !( fp = fopen( HINT_FILE, "w" ) ) )
   {
      bug( "%s: Can't open %s for writing.", __FUNCTION__, HINT_FILE );
      perror( HINT_FILE );
      return;
   }

   for( hint = first_hint; hint; hint = hint->next )
   {
      if( !hint->hint )
         continue;
      fprintf( fp, "Hint      %s~\n", hint->hint );
      if( hint->aname )
         fprintf( fp, "AName     %s~\n", hint->aname );
      if( hint->cname )
         fprintf( fp, "CName     %s~\n", hint->cname );
      if( hint->rname )
         fprintf( fp, "RName     %s~\n", hint->rname );
      if( hint->minlevel )
         fprintf( fp, "MinLevel  %d\n", hint->minlevel );
      if( hint->maxlevel != MAX_LEVEL )
         fprintf( fp, "MaxLevel  %d\n", hint->maxlevel );
   }
   fprintf( fp, "%s", "End\n" );
   fclose( fp );
   fp = NULL;
}

void free_hint( HINT_DATA *hint )
{
   if( !hint )
      return;
   STRFREE( hint->hint );
   STRFREE( hint->aname );
   STRFREE( hint->rname );
   STRFREE( hint->cname );
   DISPOSE( hint );
}

void free_hints( void )
{
   HINT_DATA *hint, *hint_next;

   for( hint = first_hint; hint; hint = hint_next )
   {
      hint_next = hint->next;
      UNLINK( hint, first_hint, last_hint, next, prev );
      free_hint( hint );
   }
}

HINT_DATA *add_hint( char *newhint )
{
   HINT_DATA *hint;

   if( !newhint || newhint[0] == '\0' )
      return NULL;

   CREATE( hint, HINT_DATA, 1 );
   STRSET( hint->hint, newhint );
   hint->minlevel = 0;
   hint->maxlevel = MAX_LEVEL;
   hint->aname = NULL;
   hint->cname = NULL;
   hint->rname = NULL;
   LINK( hint, first_hint, last_hint, next, prev );
   return hint;
}

void load_hints( void )
{
   FILE *fp;
   HINT_DATA *hint = NULL;
   char *name;
   int value;

   first_hint = last_hint = NULL;
   if( !( fp = fopen( HINT_FILE, "r" ) ) )
      return;
   for( ;; )
   {
      char *word;

      if( feof( fp ) )
         break;
      word = fread_word( fp );
      if( word[0] == EOF )
         break;
      if( !str_cmp( word, "Hint" ) )
      {
         name = fread_flagstring( fp );
         hint = add_hint( name );
         continue;
      }
      else if( !str_cmp( word, "AName" ) )
      {
         name = fread_flagstring( fp );
         if( !hint )
            continue;
         STRSET( hint->aname, name );
         continue;
      }
      else if( !str_cmp( word, "CName" ) )
      {
         name = fread_flagstring( fp );
         value = get_pc_class( name );

         if( value < 0 || value >= MAX_PC_CLASS )
            continue;
         if( !hint )
            continue;
         STRSET( hint->cname, name );
         continue;
      }
      else if( !str_cmp( word, "RName" ) )
      {
         name = fread_flagstring( fp );
         value = get_pc_race( name );

         if( value < 0 || value >= MAX_PC_RACE )
            continue;
         if( !hint )
            continue;
         STRSET( hint->rname, name );
         continue;
      }
      else if( !str_cmp( word, "MinLevel" ) )
      {
         value = fread_number( fp );
         if( value < 0 || value > MAX_LEVEL )
            value = 0;
         if( !hint )
            continue;
         hint->minlevel = value;
         continue;
      }
      else if( !str_cmp( word, "MaxLevel" ) )
      {
         value = fread_number( fp );
         if( value < 0 || value > MAX_LEVEL )
            value = MAX_LEVEL;
         if( !hint )
            continue;
         hint->maxlevel = value;
         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;
}

HINT_DATA *find_hint( int nhint )
{
   HINT_DATA *hint;
   int count = 0;

   for( hint = first_hint; hint; hint = hint->next )
      if( ++count == nhint )
         return hint;
   return NULL;
}

CMDF( do_hintset )
{
   HINT_DATA *hint;
   char arg[MSL];
   int count = 0, value = 0;

   set_char_color( AT_HINT, ch );
   if( !argument || argument[0] == '\0' )
   {
      if( !first_hint )
      {
         send_to_char( "No hints currently in the mud.\r\n", ch );
         return;
      }
      for( hint = first_hint; hint; hint = hint->next )
      {
         ch_printf( ch, "&[hint2]%3d&[hint]> &[hint2]%s\r\n", ++count, hint->hint );
         if( hint->aname || hint->cname || hint->rname || hint->minlevel || hint->maxlevel != MAX_LEVEL )
         {
            send_to_char( "&[hint]Restrictions:", ch );
            if( hint->aname )
               ch_printf( ch, " &[hint]Area: &[hint2]%s", hint->aname );
            if( hint->rname )
               ch_printf( ch, " &[hint]Race: &[hint2]%s", hint->rname );
            if( hint->cname )
               ch_printf( ch, " &[hint]Class: &[hint2]%s", hint->cname );
            ch_printf( ch, "  &[hint]Levels: &[hint2]%d &[hint]to &[hint2]%d\r\n", hint->minlevel, hint->maxlevel );
         }
      }
      return;
   }

   argument = one_argument( argument, arg );
   if( !str_cmp( arg, "create" ) )
   {
      if( !( hint = add_hint( argument ) ) )
      {
         send_to_char( "Hint couldn't be created.\r\n", ch );
         return;
      }
      save_hints( );
      send_to_char( "Hint created.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "delete" ) )
   {
      if( !( hint = find_hint( atoi( argument ) ) ) )
      {
         send_to_char( "No such hint to delete.\r\n", ch );
         return;
      }
      UNLINK( hint, first_hint, last_hint, next, prev );
      free_hint( hint );
      save_hints( );
      send_to_char( "Hint deleted.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "class" ) )
   {
      argument = one_argument( argument, arg );
      if( !( hint = find_hint( atoi( arg ) ) ) )
      {
         send_to_char( "No such hint to restrict to one class.\r\n", ch );
         return;
      }
      if( !str_cmp( argument, "clear" ) )
      {
         STRFREE( hint->cname );
         hint->cname = NULL;
         save_hints( );
         send_to_char( "Hint class cleared.\r\n", ch );
         return;
      }
      value = get_pc_class( argument );
      if( value < 0 || value >= MAX_PC_CLASS )
      {
         send_to_char( "Not a valid pc class.\r\n", ch );
         return;
      }
      STRSET( hint->cname, argument );
      save_hints( );
      send_to_char( "Hint class set.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "race" ) )
   {
      argument = one_argument( argument, arg );
      if( !( hint = find_hint( atoi( arg ) ) ) )
      {
         send_to_char( "No such hint to restrict to one race.\r\n", ch );
         return;
      }
      if( !str_cmp( argument, "clear" ) )
      {
         STRFREE( hint->rname );
         hint->rname = NULL;
         save_hints( );
         send_to_char( "Hint race cleared.\r\n", ch );
         return;
      }
      value = get_pc_race( argument );
      if( value < 0 || value >= MAX_PC_RACE )
      {
         send_to_char( "Not a valid pc race.\r\n", ch );
         return;
      }
      STRSET( hint->rname, argument );
      save_hints( );
      send_to_char( "Hint race set.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "area" ) )
   {
      argument = one_argument( argument, arg );
      if( !( hint = find_hint( atoi( arg ) ) ) )
      {
         send_to_char( "No such hint to restrict to one area.\r\n", ch );
         return;
      }
      if( !str_cmp( argument, "clear" ) )
      {
         STRFREE( hint->aname );
         hint->aname = NULL;
         save_hints( );
         send_to_char( "Hint area cleared.\r\n", ch );
         return;
      }
      STRSET( hint->aname, argument );
      save_hints( );
      send_to_char( "Hint area set.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "minlevel" ) )
   {
      argument = one_argument( argument, arg );
      if( !( hint = find_hint( atoi( arg ) ) ) )
      {
         send_to_char( "No such hint to restrict to a minlevel.\r\n", ch );
         return;
      }
      value = atoi( argument );
      if( value < 0 || value > MAX_LEVEL )
      {
         send_to_char( "Invalid level.\r\n", ch );
         return;
      }
      hint->minlevel = value;
      save_hints( );
      send_to_char( "Hint minlevel set.\r\n", ch );
      return;
   }

   if( !str_cmp( arg, "maxlevel" ) )
   {
      argument = one_argument( argument, arg );
      if( !( hint = find_hint( atoi( arg ) ) ) )
      {
         send_to_char( "No such hint to restrict to a maxlevel.\r\n", ch );
         return;
      }
      value = atoi( argument );
      if( value < 0 || value > MAX_LEVEL )
      {
         send_to_char( "Invalid level.\r\n", ch );
         return;
      }
      hint->maxlevel = value;
      save_hints( );
      send_to_char( "Hint maxlevel set.\r\n", ch );
      return;
   }

   send_to_char( "Usage: hintset create <hint>\r\n", ch );
   send_to_char( "Usage: hintset delete <hint #>\r\n", ch );
   send_to_char( "Usage: hintset class/race/area <hint #> <class/race/area name>/clear\r\n", ch );
   send_to_char( "Usage: hintset minlevel/maxlevel <hint #> <level>\r\n", ch );
}

/* Should we send the hint to the character? */
bool can_send_hint( CHAR_DATA *ch, HINT_DATA *hint )
{
   if( hint->cname && str_cmp( dis_class_name( ch->race ), hint->cname ) )
      return false;
   if( hint->rname && str_cmp( dis_race_name( ch->Class ), hint->rname ) )
      return false;
   if( hint->aname && ( !ch->in_room || !ch->in_room->area ||  str_cmp( ch->in_room->area->name, hint->aname ) ) )
      return false;
   if( ch->level < hint->minlevel || ch->level > hint->maxlevel )
      return false;
   return true;
}

void send_hint( CHAR_DATA *ch )
{
   HINT_DATA *hint;

   for( hint = first_hint; hint; hint = hint->next )
   {
      if( number_percent( ) > 10 )
         continue;
      if( !can_send_hint( ch, hint ) )
         return;
      ch_printf( ch, "&[hint]HINT: &[hint2]%s\r\n", hint->hint );
      return;
   }
}