legend/
legend/area/
legend/player/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"

char *smash_article (char *text)
{
   char *arg;
   char buf[MAX_STRING_LENGTH];
   static char buf2[MAX_STRING_LENGTH];

   one_argument (text, buf);

   if (!str_cmp (buf, "the") || !str_cmp (buf, "an") || !str_cmp (buf, "a"))
   {
      arg = one_argument (text, buf);
      sprintf (buf2, "%s", arg);
   }
   else
      strcpy (buf2, text);

   return buf2;
}

void do_hiscoset (CHAR_DATA * ch, char *argument)
/* Hiscoset command */
{
   char cmd[MAX_INPUT_LENGTH];
   char kwd[MAX_INPUT_LENGTH];
   char pnf[MAX_INPUT_LENGTH];
   char set_val[MAX_INPUT_LENGTH];
   HISCORE *table;
   HISCORE_ENTRY *entry;
   sh_int i;
   bool cmd_found;

   if (argument[0] == '\0')
   {
      send_to_char
	 ("Syntax: hiscoset <command> [table keyword] [field] [value]\n\r",
	  ch);
      send_to_char ("\n\r", ch);
      send_to_char ("    Command being one of:\n\r", ch);
      send_to_char
	 ("    list                     Lists all hiscore tables.\n\r", ch);
      send_to_char
	 ("    show <kwd>               Shows the data for that table.\n\r",
	  ch);
      send_to_char
	 ("    create <kwd>             Create new table with that keyword.\n\r",
	  ch);
      send_to_char
	 ("    destroy <kwd>            Destroy table with that keyword.\n\r",
	  ch);
      send_to_char ("    clear                    Clears the table\n\r", ch);
      send_to_char
	 ("    set <kwd> <field> <val>  Sets data for that table.\n\r", ch);
      send_to_char ("\n\r", ch);
      send_to_char ("    Field being one of:\n\r", ch);
      send_to_char
	 ("    keyword <str>            Set new keyword for the table.\n\r",
	  ch);
      send_to_char
	 ("    vnum <num>               Set an object vnum for this table.\n\r",
	  ch);
      send_to_char ("    desc <str>               Set the description.\n\r",
		    ch);
      send_to_char
	 ("    maxlength <num>          Set Max entries in the table.\n\r",
	  ch);
      send_to_char
	 ("    entry <name> <score>     Change the score for a player.\n\r",
	  ch);
      send_to_char ("\n\r", ch);
      send_to_char ("    See HELP HISCOSET for more details.\n\r", ch);
      return;
   }

   argument = one_argument (argument, cmd);

   if (!str_cmp (cmd, "list"))
   {
      send_to_char ("List of hiscore tables: \n\r", ch);
      for (table = first_table; table; table = table->next)
      {
	 sprintf (pnf, "    Table '%s' (%s), %d entries, vnum is %d\n\r",
		  table->keyword, table->desc, table->length, table->vnum);
	 stc (pnf, ch);
      }
      if (!first_table)
	 send_to_char ("    No tables found.\n\r", ch);
      return;
   }

   argument = one_argument (argument, kwd);
   if (kwd[0] != '\0')
      table = find_table (kwd);
   else
      table = NULL;
   cmd_found = FALSE;

   if (!str_cmp (cmd, "create") && (cmd_found = TRUE) && kwd[0] != '\0')
   {
      if (table != NULL)
      {
	 send_to_char ("A table with that keyword already exists.\n\r", ch);
	 return;
      }
      create_hitable (kwd, "Description not set yet");
      sprintf (pnf, "Table '%s' created.\n\r", kwd);
      stc (pnf, ch);
      save_hiscores ();
      return;
   }
   else if (!str_cmp (cmd, "show") && (cmd_found = TRUE) && table != NULL)
   {
      sprintf (pnf, "Hiscore table, keyword '%s':\n\r", kwd);
      stc (pnf, ch);
      sprintf (pnf, "Description: %s\n\r", table->desc);
      stc (pnf, ch);
      sprintf (pnf, "Vnum: %d    MaxLength: %d Length: %d\n\r",
	       table->vnum, table->max_length, table->length);
      stc (pnf, ch);
      for (entry = table->first_entry, i = 1; entry; entry = entry->next, i++)
         sprintf (pnf, "%d. Name: %-15.15s    Score: %lli\n\r",
		  i, capitalize (entry->name), entry->score);
      stc (pnf, ch);
      return;
   }
   else if (!str_cmp (cmd, "clear") && (cmd_found = TRUE) && table)
   {
      if (clear_hitable (kwd))
      {
	 sprintf (pnf, "Table '%s' cleared succesfully.\n\r", kwd);
	 stc (pnf, ch);
      }
      else
      {
	 sprintf (pnf, "Table '%s' could not be cleared.\n\r", kwd);
	 stc (pnf, ch);
      }
      return;
   }
   else if (!str_cmp (cmd, "destroy") && (cmd_found = TRUE) && table != NULL)
   {
      if (destroy_hitable (kwd))
      {
	 sprintf (pnf, "Table '%s' destroyed.\n\r", kwd);
	 stc (pnf, ch);
      }
      else
      {
	 sprintf (pnf, "ERROR: Couldn't destroy table '%s'.\n\r", kwd);
	 stc (pnf, ch);
	 LINK (table, first_table, last_table, next, prev);
      }
      save_hiscores ();
      return;
   }
   else if (!str_cmp (cmd, "set"))
      cmd_found = TRUE;

   if (!cmd_found)
   {
      sprintf (pnf, "Invalid command '%s' for hiscoset.\n\r", cmd);
      stc (pnf, ch);
      return;
   }
   if (kwd[0] == '\0')
   {
      send_to_char ("Please specify a table keyword.\n\r", ch);
      return;
   }
   if (table == NULL)
   {
      sprintf (pnf, "No such table '%s'.\n\r", kwd);
      stc (pnf, ch);
      return;
   }

   /* If it reached here, its "hiscoset set" and table is valid */
   argument = one_argument (argument, cmd);
   if (cmd[0] == '\0')
   {
      send_to_char ("Hiscoset set what?\n\r", ch);
      return;
   }

   cmd_found = FALSE;
   if (!str_cmp (cmd, "desc") && (cmd_found = TRUE) && argument[0] != '\0')
   {
      free_string (table->desc);
      table->desc = str_dup (argument);
      sprintf (pnf, "Ok. Description for table '%s' is now '%s'.\n\r",
	       kwd, argument);
      stc (pnf, ch);
      save_hiscores ();
      return;
   }
   argument = one_argument (argument, set_val);
   if (!str_cmp (cmd, "keyword") && (cmd_found = TRUE) && set_val[0] != '\0')
   {
      free_string (table->keyword);
      table->keyword = str_dup (set_val);
      sprintf (pnf, "Ok. Keyword for table '%s' is now '%s'.\n\r",
	       kwd, set_val);
      stc (pnf, ch);
      save_hiscores ();
      return;
   }
   else if (!str_cmp (cmd, "vnum") && (cmd_found = TRUE)
	    && set_val[0] != '\0')
   {
      if (is_number (set_val))
      {
	 table->vnum = atoi (set_val);
	 sprintf (pnf, "Ok. Vnum for table '%s' is now '%d'.\n\r",
		  kwd, table->vnum);
	 stc (pnf, ch);
	 save_hiscores ();
      }
      else
	 send_to_char ("Argument for set vnum must be numeric.\n\r", ch);
      return;
   }
   else if (!str_cmp (cmd, "maxlength") && (cmd_found = TRUE) &&
	    set_val[0] != '\0')
   {
      if (is_number (set_val))
      {
	 table->max_length = atoi (set_val);
	 sprintf (pnf, "Ok. Max length for table '%s' is now '%d'.\n\r",
		  kwd, table->max_length);
	 stc (pnf, ch);
	 fix_table_length (table);
	 save_hiscores ();
      }
      else
	 send_to_char ("Argument for set maxlength must benumeric.\n\r", ch);
      return;
   }
   else if (!str_cmp (cmd, "entry"))
      cmd_found = TRUE;

   if (!cmd_found)
   {
      sprintf (pnf, "Invalid value '%s' for hiscoset set.\n\r", cmd);
      stc (pnf, ch);
      return;
   }
   if (set_val[0] == '\0')
   {
      sprintf (pnf, "Hiscoset set %s to what?.\n\r", cmd);
      stc (pnf, ch);
      return;
   }

   /* at this point, its hiscoset set entry .. */
   if (argument == '\0' || !is_number (argument))
   {
      send_to_char ("Second argument to set entry must be numberic.\n\r", ch);
      return;
   }

   sprintf (pnf, "New score for %s set to %s.\n\r", set_val, argument);
   stc (pnf, ch);
   if (add_hiscore (kwd, set_val, atoi (argument)))
   {
      sprintf (pnf, "New position is %d.\n\r", get_position (kwd, set_val));
      stc (pnf, ch);
   }
   else
      sprintf (pnf, "They are out of the table.\n\r");
   stc (pnf, ch);
   save_hiscores ();
}



void do_hiscore (CHAR_DATA * ch, char *argument)
/* Hiscore command */
{
   HISCORE *table;
   bool some_table;
   OBJ_INDEX_DATA *oindex;
   char pnf[MSL];

   adjust_hiscore ("pkill", ch, ch->pkill);
   adjust_hiscore ("pdeath", ch, ch->pdeath);
   adjust_hiscore ("mkill", ch, ch->mkill);
   adjust_hiscore ("mdeath", ch, ch->mdeath);
   adjust_hiscore ("awins", ch, ch->awins);
   adjust_hiscore ("alosses", ch, ch->alosses);
   adjust_hiscore ("exp", ch, ch->pcdata->score[SCORE_TOTAL_XP]);
   adjust_hiscore ("quest", ch, ch->pcdata->score[SCORE_QUEST]);
   adjust_hiscore ("tier", ch, ch->tier);
   if (argument[0] == '\0')
   {
      do_leader (ch, "");
      some_table = FALSE;
//              send_to_char( "Hiscore tables in this game:\n\r", ch );
      for (table = first_table; table; table = table->next)
      {
	 if (table->vnum == -1)
	 {
	    sprintf (pnf, "  %s: keyword '%s'\n\r",
		     table->desc, table->keyword);
	    //stc(pnf,ch);
	    some_table = TRUE;
	 }
	 else
	 {
	    oindex = get_obj_index (table->vnum);
	    if (oindex != NULL)
	    {
	       sprintf (pnf, "  %s: in object %s\n\r",
			table->desc, oindex->short_descr);
	       //stc(pnf,ch);
	       some_table = TRUE;
	    }
	 }
      }
      if (!some_table)
      {
	 //send_to_char( "  None.\n\r", ch );
	 return;
      }
   }
   if (argument[0] == '\0')
   {
      return;
   }
   else
      table = find_table (argument);
   if (table == NULL)
   {
      send_to_char ("No such hiscore table.\n\r", ch);
      return;
   }

   if (table->vnum != -1 && !IS_IMMORTAL (ch))
   {
      send_to_char
	 ("That hiscore table is attached to an object. Go see the object.\n\r",
	  ch);
      return;
   }

   show_hiscore (table->keyword, ch);
}

char *is_hiscore_obj (OBJ_DATA * obj)
/* If the given object is marked as a hiscore table object, it returns
 * a pointer to the keyword for that table; otherwise returns NULL */
{
   HISCORE *table;

   for (table = first_table; table; table = table->next)
   {
      if (obj->pIndexData->vnum == table->vnum)
	 return table->keyword;
   }
   return NULL;
}

/*
(@)                                                 (@)
| |-------------------------------------------------| |
| |                                                 | |
| |      Greatest Pkillers of Frozen Wasteland      | |
| |                                                 | |
| |      1. Darklord ..........|.......... 1000     | |
| |      2. Pepto .............|............ 50     | |
| |     10. 12345678901234567890123456789012345     | |
| |     1234                                        | |
| |-------------------------------------------------| |
(@)                                                 (@)
   width =
01234567890123456789012345678901234567890123456789012345678901234567890123456789
0         1         2         3         4         5         6         7
3 + 5 + text + 5 + 3 = 16 + text
text = 4 + 20 + 15 = 39
39 + 16 = 49+6 = 55
*/
/* this is width of text only,
 * add 13 to get actual width */

void show_hiscore (char *keyword, CHAR_DATA * ch)
/* Shows a hiscore table to a player in a (more or less) nicely formatted
 * way. */
{
   HISCORE *table;
   HISCORE_ENTRY *entry;
   sh_int num, len;
   char buf[MAX_STRING_LENGTH];
   char pnf[MSL];
   bool odd;

   table = find_table (keyword);
   if (table == NULL)
   {
      bug ("show_hiscore: no such table ", 0);
      return;
   }
   sprintf (pnf,
	    " #R *-------------------------------------------------*#n\n\r");
   stc (pnf, ch);
   sprintf (pnf,
	    "#R  |                                                 |#n\n\r");
   stc (pnf, ch);
   sprintf (buf, "%s", table->desc);
   len = strlen (buf);
   len = (39 - len);
   odd = (len % 2) == 1;
   len /= 2;
   if (len < 0)
      len = 0;
   for (num = 0; num < len; num++)
      buf[num] = ' ';
   buf[num] = '\0';
   sprintf (pnf, "#R  |     #C%s%s%s%s     #R|#n\n\r",
	    buf, table->desc, odd ? " " : "", buf);
   stc (pnf, ch);
   sprintf (pnf,
	    "#R  |                                                 |#n\n\r");
   stc (pnf, ch);
   num = 1;
   for (entry = table->first_entry; entry; entry = entry->next)
   {
      sprintf (pnf, "#R  |     %s%2d. %-20.20s%15lli     #R|#n\n\r",
	       num <= 3 ? "#y" : "#o",
	       num, capitalize (entry->name), entry->score);
      stc (pnf, ch);
      num++;
   }

   sprintf (pnf,
	    " #R |                                                 |#n\n\r");
   stc (pnf, ch);
   sprintf (pnf,
	    " #R *-------------------------------------------------*#n\n\r");
   stc (pnf, ch);
}
void adjust_hiscore (char *keyword, CHAR_DATA * ch, long long int score)
/* Adjusts the hiscore for that character in that table
 * and sends message to the character and to the whole mud
 * if the player entered the table */
{
   char pnf[MSL];
   sh_int pos, old_pos;
   HISCORE *table;
   int imm;

   if (IS_NPC (ch))
      return;
   if (IS_IMMORTAL (ch))
      return;
   if IS_SET
      (ch->extra2, NHELPER) return;

   for (imm = 0; *immlist[imm].name; imm++)
      if (!str_cmp (ch->name, immlist[imm].name))
         return;

   old_pos = get_position (keyword, ch->name);
   add_hiscore (keyword, ch->name, score);
   pos = get_position (keyword, ch->name);
   table = find_table (keyword);
   if (pos != -1 && pos != old_pos && table != NULL)
   {
      sprintf (pnf, "You have reached position %d in the table of '%s'.\n\r",
	       pos, table->desc);
      //stc(pnf,ch);
   }
   else if (pos != -1 && table != NULL)
   {
      sprintf (pnf, "You remain in position %d in the table of '%s'.\n\r",
	       pos, table->desc);
      //stc(pnf,ch);
   }
}

bool add_hiscore (char *keyword, char *name, long long int score)
/* Sets the score for 'name'. If name is already on the table, the old
 * score is discarded and the new one takes effect.
 * Returns TRUE if as a result of this call, name was added to the
 * table or remained there. */
{
   HISCORE *table;
   HISCORE_ENTRY *entry, *new_entry;
   sh_int i;
   bool added;

   table = find_table (keyword);
   if (table == NULL)
   {
      bug ("add_hiscore: table not found", 0);
      return FALSE;
   }

   for (entry = table->first_entry; entry; entry = entry->next)
   {
      if (!str_cmp (entry->name, name))
      {
	 UNLINK (entry, table->first_entry, table->last_entry, next, prev);
	 free_string (entry->name);
	 free_mem (entry, sizeof (*entry));
	 table->length--;
	 break;
      }
   }

   added = FALSE;
   new_entry = NULL;
   for (i = 1, entry = table->first_entry; i <= table->max_length;
	entry = entry->next, i++)
   {
      if (!entry)
	 /* there are empty slots at end of list, add there */
      {
	 new_entry = alloc_mem (sizeof (HISCORE_ENTRY));
	 new_entry->name = str_dup (name);
	 new_entry->score = score;
	 LINK (new_entry, table->first_entry, table->last_entry, next, prev);
	 table->length++;
	 added = TRUE;
	 break;
      }
      else if (score > entry->score)
      {
	 new_entry = alloc_mem (sizeof (HISCORE_ENTRY));
	 new_entry->name = str_dup (name);
	 new_entry->score = score;
	 INSERT (new_entry, entry, table->first_entry, next, prev);
	 table->length++;
	 added = TRUE;
	 break;
      }
   }

   fix_table_length (table);

   if (added)
      save_hiscores ();

   return added;
}

void fix_table_length (HISCORE * table)
/* Chops entries at the end of the table if the table
 * has exceeded its maximum length */
{
   HISCORE_ENTRY *entry;

   while (table->length > table->max_length)
   {
      table->length--;
      entry = table->last_entry;
      UNLINK (entry, table->first_entry, table->last_entry, next, prev);
      free_string (entry->name);
      free_mem (entry, sizeof (*entry));
   }
}

sh_int get_position (char *keyword, char *name)
/* Returns the position of 'name' within the table of that keyword, or
 * -1 if 'name' is not in that table */
{
   sh_int i;
   HISCORE *table;
   HISCORE_ENTRY *entry;

   table = find_table (keyword);
   if (!table)
      return -1;

   i = 1;
   for (entry = table->first_entry; entry; entry = entry->next)
   {
      if (!str_cmp (entry->name, name))
	 return i;
      i++;
   }

   return -1;
}

HISCORE *find_table (char *keyword)
/* Returns a pointer to the table for the given keyword
 * or NULL if there's no such table */
{
   HISCORE *table;

   for (table = first_table; table; table = table->next)
   {
      if (!str_cmp (table->keyword, keyword))
	 return table;
   }
   return NULL;
}

void create_hitable (char *keyword, char *desc)
/* Creates a new hiscore table with the given keyword and description */
{
   HISCORE *new_table;

   new_table = alloc_mem (sizeof (HISCORE));

   new_table->keyword = str_dup (keyword);
   new_table->desc = str_dup (desc);
   new_table->vnum = -1;
   new_table->max_length = 10;
   new_table->length = 0;
   new_table->first_entry = NULL;
   new_table->last_entry = NULL;
   LINK (new_table, first_table, last_table, next, prev);
}

bool destroy_hitable (char *keyword)
/* Destroyes a given hiscore table. Returns FALSE if error */
{
   HISCORE *table;
   HISCORE_ENTRY *entry, *nentry;

   table = find_table (keyword);
   if (!table)
      return FALSE;

   UNLINK (table, first_table, last_table, next, prev);
   free_string (table->keyword);
   free_string (table->desc);
   for (entry = table->first_entry; entry; entry = nentry)
   {
      nentry = entry->next;
      UNLINK (entry, table->first_entry, table->last_entry, next, prev);
      free_string (entry->name);
      free_mem (entry, sizeof (*entry));
   }
   free_mem (table, sizeof (*table));
   return TRUE;
}

bool clear_hitable (char *keyword)
/* Destroyes a given hiscore table. Returns FALSE if error */
{
   HISCORE *table;
   HISCORE_ENTRY *entry, *nentry;

   table = find_table (keyword);
   if (!table)
      return FALSE;

   for (entry = table->first_entry; entry; entry = nentry)
   {
      nentry = entry->next;
      UNLINK (entry, table->first_entry, table->last_entry, next, prev);
      free_string (entry->name);
      free_mem (entry, sizeof (*entry));
   }
   return TRUE;
}

void save_hiscores (void)
/* Saves all hiscore tables */
{
   FILE *fp;
   char filename[MAX_INPUT_LENGTH];
   HISCORE *table;
   HISCORE_ENTRY *entry;

   sprintf (filename, "../db/hiscores.dat");

   fclose (fpReserve);
   fp = fopen (filename, "w");
   if (fp == NULL)
   {
      bug ("save_hiscores: fopen", 0);
      return;
   }

   fprintf (fp, "#HISCORES\n");

   for (table = first_table; table; table = table->next)
   {
      fprintf (fp, "#TABLE\n");
      fprintf (fp, "Keyword    %s\n", table->keyword);
      fprintf (fp, "Desc       %s~\n", table->desc);
      fprintf (fp, "Vnum       %d\n", table->vnum);
      fprintf (fp, "MaxLength  %d\n", table->max_length);
      for (entry = table->first_entry; entry; entry = entry->next)
      {
         fprintf (fp, "Entry      %s %lli\n", entry->name, entry->score);
      }
      fprintf (fp, "End\n\n");
   }

   fprintf (fp, "#END\n");

   fclose (fp);
   fpReserve = fopen (NULL_FILE, "r");
}

void load_hiscores (void)
/* Loads all hiscore tables */
{
   char filename[MAX_INPUT_LENGTH];
   FILE *fp;
   HISCORE *new_table;

   sprintf (filename, "../db/hiscores.dat");

   fp = fopen (filename, "r");
   if (fp == NULL)
   {
      bug ("Invalid filename. Defaulting to 0 Hiscore tables", 0);
      return;
   }

   for (;;)
   {
      char letter;
      char *word;

      letter = fread_letter (fp);

      if (letter != '#')
      {
	 bug ("load_hiscores: # not found", 0);
	 return;
      }

      word = fread_word (fp);

      if (!str_cmp (word, "HISCORES"))
	 ;
      else if (!str_cmp (word, "END"))
	 break;
      else if (!str_cmp (word, "TABLE"))
      {
	 new_table = load_hiscore_table (fp);
	 if (!new_table)
	    continue;
	 LINK (new_table, first_table, last_table, next, prev);
      }
      else
      {
	 bug ("load_hiscores: unknown field", 0);
	 break;
      }
   }

   fclose (fp);
   return;
}

HISCORE *load_hiscore_table (FILE * fp)
/* Loads one hiscore table from the file and returns it */
{
   char *word;
   HISCORE *new_table;
   HISCORE_ENTRY *new_entry;
   sh_int entry_count;

   new_table = alloc_mem (sizeof (HISCORE));
   entry_count = 0;
   for (;;)
   {
      word = fread_word (fp);
      if (!str_cmp (word, "End"))
	 break;
      else if (!str_cmp (word, "Keyword"))
	 new_table->keyword = str_dup (fread_word (fp));
      else if (!str_cmp (word, "Desc"))
	 new_table->desc = fread_string (fp);
      else if (!str_cmp (word, "Vnum"))
	 new_table->vnum = fread_number (fp);
      else if (!str_cmp (word, "MaxLength"))
	 new_table->max_length = fread_number (fp);
      else if (!str_cmp (word, "Entry"))
      {
	 new_entry = alloc_mem (sizeof (HISCORE_ENTRY));
	 new_entry->name = str_dup (fread_word (fp));
	 new_entry->score = fread_long (fp);
	 /* LINK adds at the end of the table. */
	 LINK (new_entry, new_table->first_entry, new_table->last_entry, next,
	       prev);
	 entry_count++;
      }
      else
      {
	 bug ("load_hiscore_table: unknown field", 0);
	 break;
      }
   }
   new_table->length = entry_count;
   if (entry_count > new_table->max_length)
   {
      bug ("load_hiscore_table: extra entries in table. fixed max_length", 0);
      new_table->max_length = entry_count;
   }

   if (new_table->keyword == NULL)
      new_table->keyword = str_dup ("error");
   if (new_table->desc == NULL)
      new_table->desc = str_dup ("Error: no description");

   return new_table;
}