1stMud/CVS/
1stMud/area/CVS/
1stMud/backup/CVS/
1stMud/bin/
1stMud/bin/CVS/
1stMud/bin/extras/
1stMud/bin/extras/CVS/
1stMud/data/CVS/
1stMud/data/i3/CVS/
1stMud/doc/1stMud/
1stMud/doc/1stMud/CVS/
1stMud/doc/CVS/
1stMud/doc/Diku/
1stMud/doc/Diku/CVS/
1stMud/doc/MPDocs/CVS/
1stMud/doc/Merc/CVS/
1stMud/doc/Rom/
1stMud/doc/Rom/CVS/
1stMud/log/CVS/
1stMud/notes/
1stMud/notes/CVS/
1stMud/player/CVS/
1stMud/player/backup/CVS/
1stMud/player/deleted/CVS/
1stMud/src/CVS/
1stMud/src/config/CVS/
1stMud/src/h/CVS/
1stMud/src/o/CVS/
1stMud/win/CVS/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "data_table.h"

DataTable stat_data_table[] = {
  {"name", FIELD_STRING, (void *) &stat_zero.name, NULL, NULL},
  {"stats", FIELD_LONG_ARRAY, (void *) &stat_zero.gamestat,
   (const void *) MAX_GAMESTAT, (const void *) 0},
  {"version", FIELD_INT, (void *) &stat_zero.version, NULL, NULL},
  {NULL, (field_t) - 1, NULL, NULL, NULL}
};

TableSave_Fun (rw_stat_data)
{
  rw_list (type, STAT_FILE, StatData, stat);
}

void
update_statlist (CharData * ch, bool pdelete)
{
  StatData *prev;
  StatData *curr;
  int i;

  if (IsNPC (ch) || IsImmortal (ch))
    return;

  prev = NULL;

  for (curr = stat_first; curr != NULL; curr = prev)
    {
      prev = curr->next;

      if (!str_cmp (ch->name, curr->name))
	{
	  if (curr->version < mud_info.stats.version)
	    {
	      memset (curr->gamestat, 0, MAX_GAMESTAT);
	      memset (ch->pcdata->gamestat, 0, MAX_GAMESTAT);
	    }
	  UnLink (curr, stat, next, prev);
	  free_stat (curr);
	}
    }
  if (pdelete || IsNPC (ch) || IsImmortal (ch))
    {
      rw_stat_data (act_write);
      return;
    }

  curr = new_stat ();
  curr->name = str_dup (ch->name);
  curr->version = mud_info.stats.version;
  for (i = 0; i < MAX_GAMESTAT; i++)
    curr->gamestat[i] = GetStat (ch, i);

  Link (curr, stat, next, prev);
  rw_stat_data (act_write);
  return;
}


const char *
print_stat (CharData * ch, const char *head, long value)
{
  return FORMATF ("{W%-19.19s {w[{R%10.10ld{w]", head, value);
}

Do_Fun (do_showstats)
{
  int option;
  char arg[MIL];

  argument = one_argument (argument, arg);

  if (NullStr (arg))
    {
      chprintln (ch, "      {ROPTIONS AVAILABLE:{x");
      chprintln (ch, "      {G0{x - Show general {n stats. (gstats)");
      chprintln (ch, "      {G1{x - Ranking of Player Killers (pkills)");
      chprintln (ch, "      {G2{x - Ranking of Player Deaths (pdeaths)");
      chprintln (ch, "      {G3{x - Ranking of Mob Kills (mkills)");
      chprintln (ch, "      {G4{x - Ranking of Mob Deaths (mdeaths)");
      chprintln (ch, "      {G5{x - Personal Rankings (personal)");
      if (IsImmortal (ch))
	chprintln (ch, "      {Gdelete <name>{x - deletes from statlist");
      return;
    }
  option = atoi (arg);

  if (!str_cmp (arg, "delete") && IsImmortal (ch))
    {
      StatData *prev = NULL;
      StatData *curr = NULL;
      bool found = false;

      for (curr = stat_first; curr != NULL; curr = prev)
	{
	  prev = curr->next;

	  if (!str_cmp (argument, curr->name))
	    {
	      UnLink (curr, stat, next, prev);
	      free_stat (curr);
	      rw_stat_data (act_write);
	      found = true;
	    }
	}
      if (!found)
	chprintlnf (ch, "Error deleting %s.", argument);
    }
  else if (option == 0 || !str_prefix (arg, "gstats"))
    {
      Column *Cd;
      Buffer *b;

      Cd = new_column ();
      b = new_buf ();
      set_cols (Cd, ch, 2, COLS_BUF, b);

      bprintln (b,
		stringf (ch, 0, Center, "{R-{r=",
			 "{C[ %s Stats ]", mud_info.name));
      print_cols (Cd, print_stat (ch, "Logins", mud_info.stats.logins));
      print_cols (Cd, print_stat (ch, "Quests", mud_info.stats.quests));
      print_cols (Cd,
		  print_stat (ch, "Quests Complete",
			      mud_info.stats.qcomplete));
      print_cols (Cd, print_stat (ch, "Levels", mud_info.stats.levels));
      print_cols (Cd, print_stat (ch, "Newbies", mud_info.stats.newbies));
      print_cols (Cd, print_stat (ch, "Deletions", mud_info.stats.deletions));
      print_cols (Cd,
		  print_stat (ch, "Mob Deaths", mud_info.stats.mobdeaths));
      print_cols (Cd, print_stat (ch, "Auctions", mud_info.stats.auctions));
      print_cols (Cd,
		  print_stat (ch, "Auctions Sold", mud_info.stats.aucsold));
      print_cols (Cd, print_stat (ch, "Player Deaths", mud_info.stats.pdied));
      print_cols (Cd, print_stat (ch, "Player Kills", mud_info.stats.pkill));
      print_cols (Cd, print_stat (ch, "Notes", mud_info.stats.notes));
      print_cols (Cd, print_stat (ch, "Remorts", mud_info.stats.remorts));
      print_cols (Cd, print_stat (ch, "Wars", mud_info.stats.wars));
      print_cols (Cd,
		  print_stat (ch, "Global Quests", mud_info.stats.gquests));
      print_cols (Cd,
		  print_stat (ch, "Connections", mud_info.stats.connections));
      print_cols (Cd,
		  print_stat (ch, "Connects this Boot",
			      mud_info.stats.boot_connects));
      print_cols (Cd,
		  print_stat (ch, "Online Record", mud_info.stats.online));
      print_cols (Cd,
		  print_stat (ch, "Web Hits", mud_info.stats.web_requests));
      print_cols (Cd,
		  print_stat (ch, "Channel Messages",
			      mud_info.stats.chan_msgs));
      cols_nl (Cd);
      bprintln (b,
		stringf (ch, 0, Center, "{R-{r=",
			 "{C[ Stats since: %s ]",
			 str_time (mud_info.stats.lastupdate,
				   GetTzone (ch), NULL)));
      sendpage (ch, buf_string (b));
      free_buf (b);
      free_column (Cd);
      return;
    }
  else if (option == 1 || !str_prefix (arg, "pkills"))
    show_game_stats (ch, PK_KILLS);
  else if (option == 3 || !str_prefix (arg, "mkills"))
    show_game_stats (ch, MOB_KILLS);
  else if (option == 2 || !str_prefix (arg, "pdeaths"))
    show_game_stats (ch, PK_DEATHS);
  else if (option == 4 || !str_prefix (arg, "mdeaths"))
    show_game_stats (ch, MOB_DEATHS);
  else if (option == 5 || !str_prefix (arg, "personal"))
    {
      StatData *curr;
      Column Cd;
      Buffer b;
      int i = 0;
      const char *stat_self[MAX_GAMESTAT] = {
	"PLAYER KILLS",
	"MOB KILLS",
	"PK DEATHS",
	"MOB DEATHS",
      };

      update_statlist (ch, false);

      for (curr = stat_first; curr != NULL; curr = curr->next)
	if (!str_cmp (ch->name, curr->name))
	  break;

      if (!curr)
	{
	  chprintln (ch, "You have no stats yet.");
	  return;
	}

      set_cols (&Cd, ch, 2, COLS_BUF, &b);

      bprintln (&b, stringf (ch, 0, Center, "{r-{R=",
			     "{C[ RANKING OF PERSONAL BESTS ]"));
      for (i = 0; i < MAX_GAMESTAT; i++)
	{
	  print_cols (&Cd, "{G%2d{w){W %s{x", i + 1,
		      print_stat (ch, stat_self[i], curr->gamestat[i]));
	}
      cols_nl (&Cd);
      bprintln (&b, draw_line (ch, "{r-{R=", 0));
      sendpage (ch, buf_string (&b));
      return;
    }
  else
    do_showstats (n_fun, ch, "");

  return;
}

int compare_type;

int
compare_stats (const void *v1, const void *v2)
{
  StatData *stat1 = *(StatData **) v1;
  StatData *stat2 = *(StatData **) v2;

  if (!stat2)
    return 1;
  if (!stat1)
    return 2;

  return stat2->gamestat[compare_type] - stat1->gamestat[compare_type];
}

void
show_game_stats (CharData * ch, int type)
{
  StatData *curr;
  Buffer *output;
  StatData **top;
  Column *Cd, c;
  int count, loop;
  bool found = false;
  const char *stat_name[MAX_GAMESTAT] = {
    "PLAYER KILLERS",
    "MOB KILLERS",
    "PK DEATHS",
    "MOB DEATHS",
  };

  output = new_buf ();
  Cd = &c;
  set_cols (Cd, ch, 2, COLS_BUF, output);
  count = 0;
  compare_type = type;

  alloc_mem (top, StatData *, top_stat);

  bprintln (output, stringf (ch, 0, Center, "{R-{r=",
			     "{C[ RANKING OF %s ]", stat_name[type]));
  loop = 0;
  loop = 0;
  for (curr = stat_first; curr != NULL; curr = curr->next)
    {
      top[count] = curr;
      count++;
      found = true;
    }

  if (found)
    {
      qsort (top, count, sizeof (*top), compare_stats);

      for (loop = 0; loop < count; loop++)
	{
	  if (loop >= 50)
	    break;

	  print_cols (Cd,
		      "{G%2d{w){W %-20s {w[{R%8ld{W]{x", loop + 1,
		      top[loop]->name, top[loop]->gamestat[type]);
	}
    }
  if (!found)
    bprintln (output, "No one found yet.");
  else
    cols_nl (Cd);
  bprintln (output, draw_line (ch, "{R-{r=", 0));
  sendpage (ch, buf_string (output));
  free_mem (top);
  free_buf (output);
  free_column (Cd);
  return;
}